Compare commits
208 Commits
v2.0.4
...
maui-build
Author | SHA1 | Date | |
---|---|---|---|
23aed49a79 | |||
8ddb6d4b6f | |||
114479321e | |||
1e5a783e7f | |||
035b91bec2 | |||
0993f788a1 | |||
b27afb9eed | |||
7bdb136c27 | |||
c0ad32eaf7 | |||
f61592cb35 | |||
0df173b415 | |||
a6c01f4658 | |||
5ea1af44d3 | |||
3821795ec5 | |||
5b7dafe142 | |||
e1888a038c | |||
e3afd3f933 | |||
055276ead9 | |||
fbdeec84e3 | |||
04676de783 | |||
766d3daf0d | |||
9480eff096 | |||
cb748e0897 | |||
90feb1810f | |||
a05212923b | |||
a6293d21c2 | |||
581307c334 | |||
5b2e633589 | |||
f56dc8c6ae | |||
dd99a7b32d | |||
6bc5c12051 | |||
048d0c445f | |||
0a50f7dba7 | |||
3218db5815 | |||
5ca19879b6 | |||
13a7e9be0a | |||
c95a2552d0 | |||
78a31b74c7 | |||
8450d882f9 | |||
19f33f830c | |||
e6fc7f1307 | |||
b0e3abe61f | |||
e1b2bc1a05 | |||
8c0d1fde45 | |||
6516ed3586 | |||
4e8975a539 | |||
66e8b1211b | |||
e42b59bec6 | |||
452f2be6c8 | |||
a38553da29 | |||
1a28f790fc | |||
afa3c46ce3 | |||
8224c84556 | |||
b619688d80 | |||
106b4442a0 | |||
fc98457add | |||
1ec5917518 | |||
ab0b067916 | |||
35645278a2 | |||
cc20a0ee95 | |||
0c0c2be67b | |||
c6b69babc2 | |||
696d6a823d | |||
cf47e2a1b3 | |||
d5faa2c8b7 | |||
e9f785e2b0 | |||
c881c3b7f2 | |||
bdb213dca6 | |||
0291766588 | |||
dabf1d4159 | |||
71f9cb27b6 | |||
cdc0a7fb09 | |||
f4cf4a7e4a | |||
d8c519d008 | |||
ed4dea214d | |||
af95d472fa | |||
20c80810f1 | |||
ce9d2dc3d2 | |||
fcd365b8f6 | |||
deb9c1e1e1 | |||
2b349bfc8a | |||
49aae758a9 | |||
308882234c | |||
0fdaffc677 | |||
8017493ff5 | |||
d18e8d2eaf | |||
49fbadbd29 | |||
64505f65f9 | |||
9327b08219 | |||
f893d8b8e2 | |||
dfc70e7482 | |||
e54f0831b8 | |||
c3d77c1de0 | |||
59c61e2e3d | |||
82f78d0cc4 | |||
d9290eae8e | |||
7175052a00 | |||
9008e84c98 | |||
67c70db758 | |||
d8a244b648 | |||
2602846b2f | |||
e19bf3a376 | |||
2a09cbbd07 | |||
60428ddb87 | |||
a2590af4f8 | |||
4641123f08 | |||
8d9460e1ce | |||
4cc52ee578 | |||
a93d794b11 | |||
90ae127cdb | |||
2ffae18d8b | |||
87d4038fc6 | |||
3838b2abe7 | |||
a7fa00be9a | |||
bb9143d493 | |||
aafedd7ccb | |||
f2b62bce8e | |||
db9f717656 | |||
e1cfd82254 | |||
3ddcf457df | |||
8066d356b0 | |||
365423e598 | |||
5b20aca1f2 | |||
20c30cf0d1 | |||
9ed6cb8cf4 | |||
3bb383f0f1 | |||
6de334e50a | |||
16159c6a29 | |||
2acea1ed99 | |||
3454bfd213 | |||
b0c25bcbb6 | |||
553e560b75 | |||
1e33229daa | |||
16c9c14f6c | |||
ba56947ca5 | |||
f5858f3338 | |||
d804fb132c | |||
f276e4ccab | |||
9287cc3732 | |||
5b498416ef | |||
7e41166390 | |||
8ae9a8d5d6 | |||
6e46651de2 | |||
df9d6b9a40 | |||
52770ec758 | |||
9087d7b91b | |||
63cd54d6fc | |||
7fc51b1ee0 | |||
7622aba453 | |||
61722fa099 | |||
61f37368f4 | |||
5196bc4548 | |||
3adb4b3c58 | |||
f37282112c | |||
2096b1dbd5 | |||
c5d86f6018 | |||
d3806a8337 | |||
d35429b356 | |||
17dc821c79 | |||
3e86ba91d6 | |||
b10db9e370 | |||
955be1f20d | |||
c965b27ca0 | |||
c3bd4490dd | |||
7c69bd249d | |||
0ccfdb16eb | |||
6479772571 | |||
6711688734 | |||
0458ba9373 | |||
e3c973fb61 | |||
28f26004c4 | |||
516132c32b | |||
46f0649343 | |||
2d4c30522d | |||
f207525ba3 | |||
13bb6eb6d7 | |||
796cd88ccf | |||
6b14d87d27 | |||
def9c3ce5b | |||
0ac8e0c517 | |||
eb3a37bd2b | |||
bd559f7bf5 | |||
bcce78c37b | |||
667bea4589 | |||
b9838204b2 | |||
6a29022335 | |||
5af47aa3f3 | |||
dc18f97d88 | |||
ec38da3c45 | |||
29905ba071 | |||
e0c57b1691 | |||
a9dd25e045 | |||
cd9d9b8f20 | |||
5d1413f733 | |||
395abe0e5c | |||
03b68b12e5 | |||
1a9a742dbe | |||
ed0938346d | |||
643739514e | |||
63720baa73 | |||
dc8aa1fc13 | |||
a1c86e011a | |||
2cbbf4af7e | |||
62d0409b57 | |||
f8325ad5a8 | |||
35371ee0a4 | |||
998032c6c8 | |||
a34bdd8557 |
@ -2,7 +2,7 @@ version: 2
|
||||
jobs:
|
||||
fast_tests:
|
||||
machine:
|
||||
image: ubuntu-2004:2024.11.1
|
||||
image: ubuntu-2004:202111-02
|
||||
steps:
|
||||
- checkout
|
||||
- run:
|
||||
@ -10,7 +10,7 @@ jobs:
|
||||
cd .circleci && ./run-tests.sh "Fast=Fast|ThirdParty=ThirdParty" && ./can-build.sh
|
||||
selenium_tests:
|
||||
machine:
|
||||
image: ubuntu-2004:2024.11.1
|
||||
image: ubuntu-2004:202111-02
|
||||
steps:
|
||||
- checkout
|
||||
- run:
|
||||
@ -18,7 +18,7 @@ jobs:
|
||||
cd .circleci && ./run-tests.sh "Selenium=Selenium"
|
||||
integration_tests:
|
||||
machine:
|
||||
image: ubuntu-2004:2024.11.1
|
||||
image: ubuntu-2004:202111-02
|
||||
steps:
|
||||
- checkout
|
||||
- run:
|
||||
@ -26,7 +26,7 @@ jobs:
|
||||
cd .circleci && ./run-tests.sh "Integration=Integration"
|
||||
trigger_docs_build:
|
||||
machine:
|
||||
image: ubuntu-2004:2024.11.1
|
||||
image: ubuntu-2004:202111-02
|
||||
steps:
|
||||
- run:
|
||||
command: |
|
||||
|
@ -2,8 +2,8 @@
|
||||
set -e
|
||||
|
||||
cd ../BTCPayServer.Tests
|
||||
docker-compose --version
|
||||
docker-compose -f "docker-compose.altcoins.yml" down -v
|
||||
docker-compose -v
|
||||
docker-compose -f "docker-compose.altcoins.yml" down --v
|
||||
|
||||
# For some reason, docker-compose pull fails time to time, so we try several times
|
||||
n=0
|
||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -266,7 +266,6 @@ paket-files/
|
||||
# JetBrains Rider
|
||||
.idea/
|
||||
*.sln.iml
|
||||
.run
|
||||
|
||||
# CodeRush
|
||||
.cr/
|
||||
|
@ -1,11 +1,12 @@
|
||||
namespace BTCPayServer.Abstractions.Constants
|
||||
namespace BTCPayApp.CommonServer
|
||||
{
|
||||
public class AuthenticationSchemes
|
||||
{
|
||||
public const string Cookie = "Identity.Application";
|
||||
public const string Bitpay = "Bitpay";
|
||||
public const string Greenfield = "Greenfield.APIKeys,Greenfield.Basic";
|
||||
public const string Greenfield = "Greenfield.APIKeys,Greenfield.Basic,Greenfield.Bearer";
|
||||
public const string GreenfieldAPIKeys = "Greenfield.APIKeys";
|
||||
public const string GreenfieldBasic = "Greenfield.Basic";
|
||||
public const string GreenfieldBearer = "Greenfield.Bearer";
|
||||
}
|
||||
}
|
16
BTCPayApp.CommonServer/BTCPayApp.CommonServer.csproj
Normal file
16
BTCPayApp.CommonServer/BTCPayApp.CommonServer.csproj
Normal file
@ -0,0 +1,16 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\BTCPayServer.Client\BTCPayServer.Client.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authorization" Version="8.0.6" />
|
||||
</ItemGroup>
|
||||
</Project>
|
122
BTCPayApp.CommonServer/IBTCPayAppHubClient.cs
Normal file
122
BTCPayApp.CommonServer/IBTCPayAppHubClient.cs
Normal file
@ -0,0 +1,122 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Client.Models;
|
||||
using BTCPayServer.Lightning;
|
||||
using NBitcoin;
|
||||
|
||||
namespace BTCPayApp.CommonServer;
|
||||
|
||||
//methods available on the hub in the client
|
||||
public interface IBTCPayAppHubClient
|
||||
{
|
||||
Task NotifyServerEvent(ServerEvent ev);
|
||||
Task NotifyNetwork(string network);
|
||||
Task NotifyServerNode(string nodeInfo);
|
||||
Task TransactionDetected(TransactionDetectedRequest request);
|
||||
Task NewBlock(string block);
|
||||
|
||||
Task<LightningInvoice> CreateInvoice(CreateLightningInvoiceRequest createLightningInvoiceRequest);
|
||||
Task<LightningInvoice?> GetLightningInvoice(uint256 paymentHash);
|
||||
Task<LightningPayment?> GetLightningPayment(uint256 paymentHash);
|
||||
Task<List<LightningPayment>> GetLightningPayments(ListPaymentsParams request);
|
||||
Task<List<LightningInvoice>> GetLightningInvoices(ListInvoicesParams request);
|
||||
Task<PayResponse> PayInvoice(string bolt11, long? amountMilliSatoshi);
|
||||
Task MasterUpdated(long? deviceIdentifier);
|
||||
Task<LightningNodeInformation> GetLightningNodeInfo();
|
||||
Task<LightningNodeBalance> GetLightningBalance();
|
||||
}
|
||||
|
||||
//methods available on the hub in the server
|
||||
public interface IBTCPayAppHubServer
|
||||
{
|
||||
Task<bool> DeviceMasterSignal(long deviceIdentifier, bool active);
|
||||
|
||||
Task<Dictionary<string,string>> Pair(PairRequest request);
|
||||
Task<AppHandshakeResponse> Handshake(AppHandshake request);
|
||||
Task<bool> BroadcastTransaction(string tx);
|
||||
Task<decimal> GetFeeRate(int blockTarget);
|
||||
Task<BestBlockResponse> GetBestBlock();
|
||||
|
||||
Task<TxInfoResponse> FetchTxsAndTheirBlockHeads(string[] txIds);
|
||||
Task<string> DeriveScript(string identifier);
|
||||
Task TrackScripts(string identifier, string[] scripts);
|
||||
Task<string> UpdatePsbt(string[] identifiers, string psbt);
|
||||
Task<CoinResponse[]> GetUTXOs(string[] identifiers);
|
||||
Task<Dictionary<string, TxResp[]>> GetTransactions(string[] identifiers);
|
||||
|
||||
Task SendInvoiceUpdate(string identifier, LightningInvoice lightningInvoice);
|
||||
}
|
||||
|
||||
public class ServerEvent(string type)
|
||||
{
|
||||
public string Type { get; } = type;
|
||||
public string? StoreId { get; init; }
|
||||
public string? UserId { get; init; }
|
||||
public string? InvoiceId { get; init; }
|
||||
}
|
||||
|
||||
public record TxResp(long Confirmations, long? Height, decimal BalanceChange, DateTimeOffset Timestamp, string TransactionId)
|
||||
{
|
||||
public override string ToString()
|
||||
{
|
||||
return $"{{ Confirmations = {Confirmations}, Height = {Height}, BalanceChange = {BalanceChange}, Timestamp = {Timestamp}, TransactionId = {TransactionId} }}";
|
||||
}
|
||||
}
|
||||
|
||||
public class TransactionDetectedRequest
|
||||
{
|
||||
public string Identifier { get; set; }
|
||||
public string TxId { get; set; }
|
||||
public string[] SpentScripts { get; set; }
|
||||
public string[] ReceivedScripts { get; set; }
|
||||
public bool Confirmed { get; set; }
|
||||
}
|
||||
|
||||
public class CoinResponse
|
||||
{
|
||||
public string Identifier{ get; set; }
|
||||
public bool Confirmed { get; set; }
|
||||
public string Script { get; set; }
|
||||
public string Outpoint { get; set; }
|
||||
public decimal Value { get; set; }
|
||||
public string Path { get; set; }
|
||||
}
|
||||
|
||||
public class TxInfoResponse
|
||||
{
|
||||
public Dictionary<string,TransactionResponse> Txs { get; set; }
|
||||
public Dictionary<string,string> Blocks { get; set; }
|
||||
public Dictionary<string,int> BlockHeghts { get; set; }
|
||||
}
|
||||
|
||||
public class TransactionResponse
|
||||
{
|
||||
public string? BlockHash { get; set; }
|
||||
public int? BlockHeight { get; set; }
|
||||
public string Transaction { get; set; }
|
||||
}
|
||||
|
||||
public class BestBlockResponse
|
||||
{
|
||||
public required string BlockHash { get; set; }
|
||||
public required int BlockHeight { get; set; }
|
||||
public string BlockHeader { get; set; }
|
||||
}
|
||||
|
||||
public class AppHandshake
|
||||
{
|
||||
public string[] Identifiers { get; set; }
|
||||
}
|
||||
|
||||
public class AppHandshakeResponse
|
||||
{
|
||||
//response about identifiers being tracked successfully
|
||||
public string[] IdentifiersAcknowledged { get; set; }
|
||||
}
|
||||
|
||||
|
||||
public class PairRequest
|
||||
{
|
||||
public Dictionary<string, string?> Derivations { get; set; } = new();
|
||||
}
|
12
BTCPayApp.CommonServer/Models/AcceptInviteRequest.cs
Normal file
12
BTCPayApp.CommonServer/Models/AcceptInviteRequest.cs
Normal file
@ -0,0 +1,12 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace BTCPayApp.CommonServer.Models;
|
||||
|
||||
public class AcceptInviteRequest
|
||||
{
|
||||
[Required]
|
||||
public string? UserId { get; init; }
|
||||
|
||||
[Required]
|
||||
public string? Code { get; init; }
|
||||
}
|
@ -1,9 +1,8 @@
|
||||
#nullable enable
|
||||
namespace BTCPayServer.Client.App.Models;
|
||||
namespace BTCPayApp.CommonServer.Models;
|
||||
|
||||
public class AcceptInviteResult
|
||||
public class AcceptInviteResult(string email)
|
||||
{
|
||||
public string? Email { get; set; }
|
||||
public string Email { get; init; } = email;
|
||||
public bool? RequiresUserApproval { get; set; }
|
||||
public bool? EmailHasBeenConfirmed { get; set; }
|
||||
public string? PasswordSetCode { get; set; }
|
10
BTCPayApp.CommonServer/Models/AccessTokenResult.cs
Normal file
10
BTCPayApp.CommonServer/Models/AccessTokenResult.cs
Normal file
@ -0,0 +1,10 @@
|
||||
using System;
|
||||
|
||||
namespace BTCPayApp.CommonServer.Models;
|
||||
|
||||
public class AccessTokenResult(string accessToken, string refreshToken, DateTimeOffset expiry)
|
||||
{
|
||||
public string AccessToken { get; init; } = accessToken;
|
||||
public string RefreshToken { get; init; } = refreshToken;
|
||||
public DateTimeOffset Expiry { get; init; } = expiry;
|
||||
}
|
@ -1,10 +1,9 @@
|
||||
#nullable enable
|
||||
namespace BTCPayServer.Client.App.Models;
|
||||
namespace BTCPayApp.CommonServer.Models;
|
||||
|
||||
public class AppInstanceInfo
|
||||
{
|
||||
public string BaseUrl { get; set; } = null!;
|
||||
public string ServerName { get; set; } = null!;
|
||||
public string BaseUrl { get; set; }
|
||||
public string ServerName { get; set; }
|
||||
public string? ContactUrl { get; set; }
|
||||
public string? LogoUrl { get; set; }
|
||||
public string? CustomThemeCssUrl { get; set; }
|
@ -1,7 +1,31 @@
|
||||
#nullable enable
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Text.Json;
|
||||
using BTCPayServer.Lightning;
|
||||
using NBitcoin;
|
||||
using NBitcoin.JsonConverters;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace BTCPayServer.Client.App.Models;
|
||||
namespace BTCPayApp.CommonServer.Models;
|
||||
|
||||
// public partial class LightningPayment
|
||||
// {
|
||||
// public string PaymentHash { get; set; }
|
||||
// public string? PaymentId { get; set; }
|
||||
// public string? Preimage { get; set; }
|
||||
// public string? Secret { get; set; }
|
||||
// public bool Inbound { get; set; }
|
||||
// public DateTimeOffset Timestamp { get; set; }
|
||||
// public long Value { get; set; }
|
||||
// public LightningPaymentStatus Status { get; set; }
|
||||
//
|
||||
// //you can have multiple requests generated for the same payment hash, but once you reveal the preimage, you should reject any attempt to pay the same payment hash
|
||||
// public List<string> PaymentRequests { get; set; }
|
||||
// [JsonIgnore]
|
||||
// public Dictionary<string, JsonDocument> AdditionalData { get; set; }
|
||||
//
|
||||
// }
|
||||
|
||||
public class AppUserInfo
|
||||
{
|
||||
@ -33,7 +57,7 @@ public class AppUserInfo
|
||||
|
||||
public class AppUserStoreInfo
|
||||
{
|
||||
public string Id { get; set; } = null!;
|
||||
public string? Id { get; set; }
|
||||
public string? Name { get; set; }
|
||||
public string? LogoUrl { get; set; }
|
||||
public string? RoleId { get; set; }
|
@ -1,7 +1,6 @@
|
||||
#nullable enable
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace BTCPayServer.Client.App.Models;
|
||||
namespace BTCPayApp.CommonServer.Models;
|
||||
|
||||
public class CreateStoreData
|
||||
{
|
12
BTCPayApp.CommonServer/Models/SignupRequest.cs
Normal file
12
BTCPayApp.CommonServer/Models/SignupRequest.cs
Normal file
@ -0,0 +1,12 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace BTCPayApp.CommonServer.Models;
|
||||
|
||||
public class SignupRequest
|
||||
{
|
||||
[Required]
|
||||
public string? Email { get; init; }
|
||||
|
||||
[Required]
|
||||
public string? Password { get; init; }
|
||||
}
|
8
BTCPayApp.CommonServer/Models/SignupResult.cs
Normal file
8
BTCPayApp.CommonServer/Models/SignupResult.cs
Normal file
@ -0,0 +1,8 @@
|
||||
namespace BTCPayApp.CommonServer.Models;
|
||||
|
||||
public class SignupResult
|
||||
{
|
||||
public string? Email { get; set; }
|
||||
public bool RequiresConfirmedEmail { get; set; }
|
||||
public bool RequiresUserApproval { get; set; }
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
using System;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
|
||||
namespace BTCPayServer.Security
|
||||
namespace BTCPayApp.CommonServer
|
||||
{
|
||||
public class PolicyRequirement : IAuthorizationRequirement
|
||||
{
|
@ -1,9 +1,8 @@
|
||||
#nullable enable
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace BTCPayServer.Client;
|
||||
namespace BTCPayApp.CommonServer;
|
||||
|
||||
public static class PosDataParser
|
||||
{
|
@ -2,13 +2,13 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace BTCPayServer;
|
||||
namespace BTCPayApp.CommonServer;
|
||||
|
||||
public class Roles
|
||||
{
|
||||
public const string ServerAdmin = "ServerAdmin";
|
||||
public static bool HasServerAdmin(IList<string> roles)
|
||||
{
|
||||
return roles.Contains(ServerAdmin, StringComparer.Ordinal);
|
||||
return roles.Contains(Roles.ServerAdmin, StringComparer.Ordinal);
|
||||
}
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
using BTCPayServer.Client;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
|
||||
namespace BTCPayServer.Security
|
||||
namespace BTCPayApp.CommonServer
|
||||
{
|
||||
public static class ServerPolicies
|
||||
{
|
@ -32,10 +32,11 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="HtmlSanitizer" Version="8.0.838" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.11" />
|
||||
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="8.0.11" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.6" />
|
||||
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="8.0.4" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\BTCPayApp.CommonServer\BTCPayApp.CommonServer.csproj" />
|
||||
<ProjectReference Include="..\BTCPayServer.Client\BTCPayServer.Client.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
@ -2,7 +2,6 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using BTCPayServer.Abstractions.Models;
|
||||
|
||||
namespace BTCPayServer.Abstractions.Contracts;
|
||||
|
||||
@ -15,5 +14,4 @@ public interface IFileService
|
||||
Task<string?> GetTemporaryFileUrl(Uri baseUri, string fileId, DateTimeOffset expiry,
|
||||
bool isDownload);
|
||||
Task RemoveFile(string fileId, string userId);
|
||||
Task<UploadImageResultModel> UploadImage(IFormFile file, string userId, long maxFileSizeInBytes = 1_000_000);
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ namespace BTCPayServer.Abstractions.Contracts
|
||||
|
||||
public interface ISyncStatus
|
||||
{
|
||||
public string PaymentMethodId { get; set; }
|
||||
public string CryptoCode { get; set; }
|
||||
public bool Available { get; }
|
||||
}
|
||||
}
|
||||
|
@ -8,14 +8,6 @@ namespace BTCPayServer.Abstractions.Extensions;
|
||||
|
||||
public static class SetStatusMessageModelExtensions
|
||||
{
|
||||
public static void SetStatusSuccess(this ITempDataDictionary tempData, string statusMessage)
|
||||
{
|
||||
tempData.SetStatusMessageModel(new StatusMessageModel
|
||||
{
|
||||
Severity = StatusMessageModel.StatusSeverity.Success,
|
||||
Message = statusMessage
|
||||
});
|
||||
}
|
||||
public static void SetStatusMessageModel(this ITempDataDictionary tempData, StatusMessageModel statusMessage)
|
||||
{
|
||||
if (statusMessage == null)
|
||||
@ -34,14 +26,19 @@ public static class SetStatusMessageModelExtensions
|
||||
tempData.TryGetValue("StatusMessageModel", out var model);
|
||||
if (successMessage != null || errorMessage != null)
|
||||
{
|
||||
var parsedModel = new StatusMessageModel
|
||||
var parsedModel = new StatusMessageModel();
|
||||
parsedModel.Message = (string)successMessage ?? (string)errorMessage;
|
||||
if (successMessage != null)
|
||||
{
|
||||
Message = (string)successMessage ?? (string)errorMessage,
|
||||
Severity = successMessage != null ? StatusMessageModel.StatusSeverity.Success : StatusMessageModel.StatusSeverity.Error
|
||||
};
|
||||
parsedModel.Severity = StatusMessageModel.StatusSeverity.Success;
|
||||
}
|
||||
else
|
||||
{
|
||||
parsedModel.Severity = StatusMessageModel.StatusSeverity.Error;
|
||||
}
|
||||
return parsedModel;
|
||||
}
|
||||
if (model is string str)
|
||||
else if (model != null && model is string str)
|
||||
{
|
||||
return JObject.Parse(str).ToObject<StatusMessageModel>();
|
||||
}
|
||||
|
@ -55,7 +55,7 @@ namespace BTCPayServer.Abstractions.Extensions
|
||||
viewData[ACTIVE_CATEGORY_KEY] = activeCategory;
|
||||
}
|
||||
|
||||
public static bool IsCategoryActive(this ViewDataDictionary viewData, string category, object id = null)
|
||||
public static bool IsActiveCategory(this ViewDataDictionary viewData, string category, object id = null)
|
||||
{
|
||||
if (!viewData.ContainsKey(ACTIVE_CATEGORY_KEY)) return false;
|
||||
var activeId = viewData[ACTIVE_ID_KEY];
|
||||
@ -65,12 +65,12 @@ namespace BTCPayServer.Abstractions.Extensions
|
||||
return categoryMatch && idMatch;
|
||||
}
|
||||
|
||||
public static bool IsCategoryActive<T>(this ViewDataDictionary viewData, T category, object id = null)
|
||||
public static bool IsActiveCategory<T>(this ViewDataDictionary viewData, T category, object id = null)
|
||||
{
|
||||
return IsCategoryActive(viewData, category.ToString(), id);
|
||||
return IsActiveCategory(viewData, category.ToString(), id);
|
||||
}
|
||||
|
||||
public static bool IsPageActive(this ViewDataDictionary viewData, string page, string category, object id = null)
|
||||
public static bool IsActivePage(this ViewDataDictionary viewData, string page, string category, object id = null)
|
||||
{
|
||||
if (!viewData.ContainsKey(ACTIVE_PAGE_KEY)) return false;
|
||||
var activeId = viewData[ACTIVE_ID_KEY];
|
||||
@ -82,7 +82,7 @@ namespace BTCPayServer.Abstractions.Extensions
|
||||
return categoryAndPageMatch && idMatch;
|
||||
}
|
||||
|
||||
public static bool IsPageActive<T>(this ViewDataDictionary viewData, IEnumerable<T> pages, object id = null)
|
||||
public static bool IsActivePage<T>(this ViewDataDictionary viewData, IEnumerable<T> pages, object id = null)
|
||||
where T : IConvertible
|
||||
{
|
||||
return pages.Any(page => ActivePageClass(viewData, page.ToString(), page.GetType().ToString(), id) == ACTIVE_CLASS);
|
||||
@ -95,7 +95,7 @@ namespace BTCPayServer.Abstractions.Extensions
|
||||
|
||||
public static string ActiveCategoryClass(this ViewDataDictionary viewData, string category, object id = null)
|
||||
{
|
||||
return IsCategoryActive(viewData, category, id) ? ACTIVE_CLASS : null;
|
||||
return IsActiveCategory(viewData, category, id) ? ACTIVE_CLASS : null;
|
||||
}
|
||||
|
||||
public static string ActivePageClass<T>(this ViewDataDictionary viewData, T page, object id = null)
|
||||
@ -106,42 +106,12 @@ namespace BTCPayServer.Abstractions.Extensions
|
||||
|
||||
public static string ActivePageClass(this ViewDataDictionary viewData, string page, string category, object id = null)
|
||||
{
|
||||
return IsPageActive(viewData, page, category, id) ? ACTIVE_CLASS : null;
|
||||
return IsActivePage(viewData, page, category, id) ? ACTIVE_CLASS : null;
|
||||
}
|
||||
|
||||
|
||||
public static string ActivePageClass<T>(this ViewDataDictionary viewData, IEnumerable<T> pages, object id = null) where T : IConvertible
|
||||
{
|
||||
return IsPageActive(viewData, pages, id) ? ACTIVE_CLASS : null;
|
||||
}
|
||||
|
||||
[Obsolete("Use ActiveCategoryClass instead")]
|
||||
public static string IsActiveCategory<T>(this ViewDataDictionary viewData, T category, object id = null)
|
||||
{
|
||||
return ActiveCategoryClass(viewData, category, id);
|
||||
}
|
||||
|
||||
[Obsolete("Use ActiveCategoryClass instead")]
|
||||
public static string IsActiveCategory(this ViewDataDictionary viewData, string category, object id = null)
|
||||
{
|
||||
return ActiveCategoryClass(viewData, category, id);
|
||||
}
|
||||
|
||||
[Obsolete("Use ActivePageClass instead")]
|
||||
public static string IsActivePage<T>(this ViewDataDictionary viewData, T page, object id = null) where T : IConvertible
|
||||
{
|
||||
return ActivePageClass(viewData, page, id);
|
||||
}
|
||||
|
||||
[Obsolete("Use ActivePageClass instead")]
|
||||
public static string IsActivePage<T>(this ViewDataDictionary viewData, IEnumerable<T> pages, object id = null) where T : IConvertible
|
||||
{
|
||||
return ActivePageClass(viewData, pages, id);
|
||||
}
|
||||
|
||||
[Obsolete("Use ActivePageClass instead")]
|
||||
public static string IsActivePage(this ViewDataDictionary viewData, string page, string category, object id = null)
|
||||
{
|
||||
return ActivePageClass(viewData, page, category, id);
|
||||
return IsActivePage(viewData, pages, id) ? ACTIVE_CLASS : null;
|
||||
}
|
||||
|
||||
public static HtmlString ToBrowserDate(this DateTimeOffset date, string netFormat, string jsDateFormat = "short", string jsTimeFormat = "short")
|
||||
|
@ -14,6 +14,14 @@ namespace BTCPayServer.Abstractions.Models
|
||||
|
||||
public string SeverityCSS => ToString(Severity);
|
||||
|
||||
private void ParseNonJsonStatus(string s)
|
||||
{
|
||||
Message = s;
|
||||
Severity = s.StartsWith("Error", StringComparison.InvariantCultureIgnoreCase)
|
||||
? StatusSeverity.Error
|
||||
: StatusSeverity.Success;
|
||||
}
|
||||
|
||||
public static string ToString(StatusSeverity severity)
|
||||
{
|
||||
switch (severity)
|
||||
|
@ -1,16 +0,0 @@
|
||||
#nullable enable
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Abstractions.Contracts;
|
||||
|
||||
namespace BTCPayServer.Abstractions.Models;
|
||||
|
||||
public class UploadImageResultModel
|
||||
{
|
||||
public bool Success { get; set; }
|
||||
public string Response { get; set; } = string.Empty;
|
||||
public IStoredFile? StoredFile { get; set; }
|
||||
}
|
@ -1,3 +1,4 @@
|
||||
using BTCPayApp.CommonServer;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
|
@ -1,11 +1,9 @@
|
||||
using System;
|
||||
using BTCPayServer.Abstractions.Contracts;
|
||||
|
||||
namespace BTCPayServer.Abstractions.Services
|
||||
{
|
||||
public class UIExtension : IUIExtension
|
||||
{
|
||||
[Obsolete("Use extension method BTCPayServer.Extensions.AddUIExtension(this IServiceCollection services, string location, string partialViewName) instead")]
|
||||
public UIExtension(string partial, string location)
|
||||
{
|
||||
Partial = partial;
|
||||
|
@ -1,139 +0,0 @@
|
||||
#nullable enable
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Client.Models;
|
||||
using BTCPayServer.Lightning;
|
||||
using NBitcoin;
|
||||
|
||||
namespace BTCPayServer.Client.App;
|
||||
|
||||
//methods available on the hub in the client
|
||||
public interface IBTCPayAppHubClient
|
||||
{
|
||||
Task NotifyServerEvent(ServerEvent ev);
|
||||
Task NotifyNetwork(string network);
|
||||
Task NotifyServerNode(string nodeInfo);
|
||||
Task TransactionDetected(TransactionDetectedRequest request);
|
||||
Task NewBlock(string block);
|
||||
Task StartListen(string key);
|
||||
|
||||
Task<LightningInvoice> CreateInvoice(string key, CreateLightningInvoiceRequest createLightningInvoiceRequest);
|
||||
Task<LightningInvoice?> GetLightningInvoice(string key, uint256 paymentHash);
|
||||
Task<LightningPayment?> GetLightningPayment(string key, uint256 paymentHash);
|
||||
Task CancelInvoice(string key, uint256 paymentHash);
|
||||
Task<List<LightningPayment>> GetLightningPayments(string key, ListPaymentsParams request);
|
||||
Task<List<LightningInvoice>> GetLightningInvoices(string key, ListInvoicesParams request);
|
||||
Task<PayResponse> PayInvoice(string key, string bolt11, long? amountMilliSatoshi);
|
||||
Task MasterUpdated(long? deviceIdentifier);
|
||||
Task<LightningNodeInformation> GetLightningNodeInfo(string key);
|
||||
Task<LightningNodeBalance> GetLightningBalance(string key);
|
||||
}
|
||||
|
||||
//methods available on the hub in the server
|
||||
public interface IBTCPayAppHubServer
|
||||
{
|
||||
Task<bool> DeviceMasterSignal(long deviceIdentifier, bool active);
|
||||
|
||||
Task<Dictionary<string,string>> Pair(PairRequest request);
|
||||
Task<AppHandshakeResponse> Handshake(AppHandshake request);
|
||||
Task<bool> BroadcastTransaction(string tx);
|
||||
Task<decimal> GetFeeRate(int blockTarget);
|
||||
Task<BestBlockResponse> GetBestBlock();
|
||||
Task<TxInfoResponse> FetchTxsAndTheirBlockHeads(string identifier, string[] txIds, string[] outpoints);
|
||||
Task<string> DeriveScript(string identifier);
|
||||
Task TrackScripts(string identifier, string[] scripts);
|
||||
Task<string> UpdatePsbt(string[] identifiers, string psbt);
|
||||
Task<CoinResponse[]> GetUTXOs(string[] identifiers);
|
||||
Task<Dictionary<string, TxResp[]>> GetTransactions(string[] identifiers);
|
||||
Task SendInvoiceUpdate(LightningInvoice lightningInvoice);
|
||||
Task<long?> GetCurrentMaster();
|
||||
}
|
||||
|
||||
public class ServerEvent
|
||||
{
|
||||
public string? Type { get; set; }
|
||||
public string? StoreId { get; set; }
|
||||
public string? UserId { get; set; }
|
||||
public string? AppId { get; set; }
|
||||
public string? InvoiceId { get; set; }
|
||||
public string? Detail { get; set; }
|
||||
}
|
||||
|
||||
public record TxResp
|
||||
{
|
||||
public TxResp(long confirmations, long? height, decimal balanceChange, DateTimeOffset timestamp, string transactionId)
|
||||
{
|
||||
Confirmations = confirmations;
|
||||
Height = height;
|
||||
BalanceChange = balanceChange;
|
||||
Timestamp = timestamp;
|
||||
TransactionId = transactionId;
|
||||
}
|
||||
|
||||
public long Confirmations { get; set; }
|
||||
public long? Height { get; set; }
|
||||
public decimal BalanceChange { get; set; }
|
||||
public DateTimeOffset Timestamp { get; set; }
|
||||
public string TransactionId { get; set; }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"{{ Confirmations = {Confirmations}, Height = {Height}, BalanceChange = {BalanceChange}, Timestamp = {Timestamp}, TransactionId = {TransactionId} }}";
|
||||
}
|
||||
}
|
||||
|
||||
public class TransactionDetectedRequest
|
||||
{
|
||||
public string? Identifier { get; set; }
|
||||
public string? TxId { get; set; }
|
||||
public string[]? SpentScripts { get; set; }
|
||||
public string[]? ReceivedScripts { get; set; }
|
||||
public bool Confirmed { get; set; }
|
||||
}
|
||||
|
||||
public class CoinResponse
|
||||
{
|
||||
public string? Identifier{ get; set; }
|
||||
public bool Confirmed { get; set; }
|
||||
public string? Script { get; set; }
|
||||
public string? Outpoint { get; set; }
|
||||
public decimal Value { get; set; }
|
||||
public string? Path { get; set; }
|
||||
}
|
||||
|
||||
public class TxInfoResponse
|
||||
{
|
||||
public Dictionary<string,TransactionResponse>? Txs { get; set; }
|
||||
public Dictionary<string,string>? BlockHeaders { get; set; }
|
||||
public Dictionary<string,int>? BlockHeghts { get; set; }
|
||||
}
|
||||
|
||||
public class TransactionResponse
|
||||
{
|
||||
public string? BlockHash { get; set; }
|
||||
public string? Transaction { get; set; }
|
||||
}
|
||||
|
||||
public class BestBlockResponse
|
||||
{
|
||||
public string? BlockHash { get; set; }
|
||||
public int BlockHeight { get; set; }
|
||||
public string? BlockHeader { get; set; }
|
||||
}
|
||||
|
||||
public class AppHandshake
|
||||
{
|
||||
public string[]? Identifiers { get; set; }
|
||||
}
|
||||
|
||||
public class AppHandshakeResponse
|
||||
{
|
||||
//response about identifiers being tracked successfully
|
||||
public string[]? IdentifiersAcknowledged { get; set; }
|
||||
}
|
||||
|
||||
public class PairRequest
|
||||
{
|
||||
public Dictionary<string, string?> Derivations { get; set; } = new();
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
#nullable enable
|
||||
namespace BTCPayServer.Client.App.Models;
|
||||
|
||||
public class AcceptInviteRequest
|
||||
{
|
||||
public string? UserId { get; set; }
|
||||
public string? Code { get; set; }
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace BTCPayServer.Client.App.Models;
|
||||
|
||||
public class AccessTokenResult
|
||||
{
|
||||
public string AccessToken { get; set; }
|
||||
public string RefreshToken { get; set; }
|
||||
public DateTimeOffset Expiry { get; set; }
|
||||
}
|
@ -12,11 +12,11 @@
|
||||
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
||||
<RepositoryUrl>https://github.com/btcpayserver/btcpayserver</RepositoryUrl>
|
||||
<RepositoryType>git</RepositoryType>
|
||||
<Configurations>Debug;Release</Configurations>
|
||||
<Configurations>Debug;Release;Altcoins-Debug;Altcoins-Release</Configurations>
|
||||
<Platforms>AnyCPU</Platforms>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<Version Condition=" '$(Version)' == '' ">2.0.1</Version>
|
||||
<Version Condition=" '$(Version)' == '' ">1.7.4</Version>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
|
||||
<PublishRepositoryUrl>true</PublishRepositoryUrl>
|
||||
@ -30,8 +30,8 @@
|
||||
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="All" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="BTCPayServer.Lightning.Common" Version="1.5.2" />
|
||||
<PackageReference Include="NBitcoin" Version="7.0.46" />
|
||||
<PackageReference Include="BTCPayServer.Lightning.Common" Version="1.5.1" />
|
||||
<PackageReference Include="NBitcoin" Version="7.0.37" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net.Http;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
@ -59,33 +58,9 @@ public partial class BTCPayServerClient
|
||||
return await SendHttpRequest<CrowdfundAppData>($"api/v1/apps/crowdfund/{appId}", null, HttpMethod.Get, token);
|
||||
}
|
||||
|
||||
public virtual async Task<AppSalesStats> GetAppSales(string appId, int numberOfDays = 7, CancellationToken token = default)
|
||||
{
|
||||
if (appId == null) throw new ArgumentNullException(nameof(appId));
|
||||
var queryPayload = new Dictionary<string, object> { { nameof(numberOfDays), numberOfDays } };
|
||||
return await SendHttpRequest<AppSalesStats>($"api/v1/apps/{appId}/sales", queryPayload, HttpMethod.Get, token);
|
||||
}
|
||||
|
||||
public virtual async Task<List<AppItemStats>> GetAppTopItems(string appId, int offset = 0, int count = 10, CancellationToken token = default)
|
||||
{
|
||||
if (appId == null) throw new ArgumentNullException(nameof(appId));
|
||||
var queryPayload = new Dictionary<string, object> { { nameof(offset), offset }, { nameof(count), count } };
|
||||
return await SendHttpRequest<List<AppItemStats>>($"api/v1/apps/{appId}/top-items", queryPayload, HttpMethod.Get, token);
|
||||
}
|
||||
|
||||
public virtual async Task DeleteApp(string appId, CancellationToken token = default)
|
||||
{
|
||||
if (appId == null) throw new ArgumentNullException(nameof(appId));
|
||||
await SendHttpRequest($"api/v1/apps/{appId}", null, HttpMethod.Delete, token);
|
||||
}
|
||||
|
||||
public virtual async Task<FileData> UploadAppItemImage(string appId, string filePath, string mimeType, CancellationToken token = default)
|
||||
{
|
||||
return await UploadFileRequest<FileData>($"api/v1/apps/{appId}/image", filePath, mimeType, "file", HttpMethod.Post, token);
|
||||
}
|
||||
|
||||
public virtual async Task DeleteAppItemImage(string appId, string fileId, CancellationToken token = default)
|
||||
{
|
||||
await SendHttpRequest($"api/v1/apps/{appId}/image/{fileId}", null, HttpMethod.Delete, token);
|
||||
}
|
||||
}
|
||||
|
@ -46,15 +46,9 @@ public partial class BTCPayServerClient
|
||||
return await SendHttpRequest<InvoiceData>($"api/v1/stores/{storeId}/invoices/{invoiceId}", null, HttpMethod.Get, token);
|
||||
}
|
||||
public virtual async Task<InvoicePaymentMethodDataModel[]> GetInvoicePaymentMethods(string storeId, string invoiceId,
|
||||
bool onlyAccountedPayments = true, bool includeSensitive = false,
|
||||
CancellationToken token = default)
|
||||
{
|
||||
var queryPayload = new Dictionary<string, object>
|
||||
{
|
||||
{ nameof(onlyAccountedPayments), onlyAccountedPayments },
|
||||
{ nameof(includeSensitive), includeSensitive }
|
||||
};
|
||||
return await SendHttpRequest<InvoicePaymentMethodDataModel[]>($"api/v1/stores/{storeId}/invoices/{invoiceId}/payment-methods", queryPayload, HttpMethod.Get, token);
|
||||
return await SendHttpRequest<InvoicePaymentMethodDataModel[]>($"api/v1/stores/{storeId}/invoices/{invoiceId}/payment-methods", null, HttpMethod.Get, token);
|
||||
}
|
||||
|
||||
public virtual async Task ArchiveInvoice(string storeId, string invoiceId,
|
||||
|
@ -21,13 +21,6 @@ public partial class BTCPayServerClient
|
||||
return await SendHttpRequest<LightningNodeBalanceData>($"api/v1/server/lightning/{cryptoCode}/balance", null, HttpMethod.Get, token);
|
||||
}
|
||||
|
||||
public virtual async Task<HistogramData> GetLightningNodeHistogram(string cryptoCode, HistogramType? type = null,
|
||||
CancellationToken token = default)
|
||||
{
|
||||
var queryPayload = type == null ? null : new Dictionary<string, object> { { "type", type.ToString() } };
|
||||
return await SendHttpRequest<HistogramData>($"api/v1/server/lightning/{cryptoCode}/histogram", queryPayload, HttpMethod.Get, token);
|
||||
}
|
||||
|
||||
public virtual async Task ConnectToLightningNode(string cryptoCode, ConnectToNodeRequest request,
|
||||
CancellationToken token = default)
|
||||
{
|
||||
|
@ -21,13 +21,6 @@ public partial class BTCPayServerClient
|
||||
return await SendHttpRequest<LightningNodeBalanceData>($"api/v1/stores/{storeId}/lightning/{cryptoCode}/balance", null, HttpMethod.Get, token);
|
||||
}
|
||||
|
||||
public virtual async Task<HistogramData> GetLightningNodeHistogram(string storeId, string cryptoCode, HistogramType? type = null,
|
||||
CancellationToken token = default)
|
||||
{
|
||||
var queryPayload = type == null ? null : new Dictionary<string, object> { { "type", type.ToString() } };
|
||||
return await SendHttpRequest<HistogramData>($"api/v1/stores/{storeId}/lightning/{cryptoCode}/histogram", queryPayload, HttpMethod.Get, token);
|
||||
}
|
||||
|
||||
public virtual async Task ConnectToLightningNode(string storeId, string cryptoCode, ConnectToNodeRequest request,
|
||||
CancellationToken token = default)
|
||||
{
|
||||
|
@ -15,7 +15,7 @@ public partial class BTCPayServerClient
|
||||
int amount = 10,
|
||||
CancellationToken token = default)
|
||||
{
|
||||
return await SendHttpRequest<UpdatePaymentMethodRequest, OnChainPaymentMethodPreviewResultData>($"api/v1/stores/{storeId}/payment-methods/{paymentMethodId}/wallet/preview",
|
||||
return await SendHttpRequest<UpdatePaymentMethodRequest, OnChainPaymentMethodPreviewResultData>($"api/v1/stores/{storeId}/payment-methods/{paymentMethodId}/preview",
|
||||
new Dictionary<string, object> { { "offset", offset }, { "amount", amount } },
|
||||
new UpdatePaymentMethodRequest { Config = JValue.CreateString(derivationScheme) },
|
||||
HttpMethod.Post, token);
|
||||
@ -25,7 +25,7 @@ public partial class BTCPayServerClient
|
||||
string storeId, string paymentMethodId, int offset = 0, int amount = 10,
|
||||
CancellationToken token = default)
|
||||
{
|
||||
return await SendHttpRequest<OnChainPaymentMethodPreviewResultData>($"api/v1/stores/{storeId}/payment-methods/{paymentMethodId}/wallet/preview",
|
||||
return await SendHttpRequest<OnChainPaymentMethodPreviewResultData>($"api/v1/stores/{storeId}/payment-methods/{paymentMethodId}/preview",
|
||||
new Dictionary<string, object> { { "offset", offset }, { "amount", amount } }, HttpMethod.Get, token);
|
||||
}
|
||||
|
||||
@ -33,7 +33,7 @@ public partial class BTCPayServerClient
|
||||
string paymentMethodId, GenerateOnChainWalletRequest request,
|
||||
CancellationToken token = default)
|
||||
{
|
||||
return await SendHttpRequest<GenerateOnChainWalletResponse>($"api/v1/stores/{storeId}/payment-methods/{paymentMethodId}/wallet/generate", request, HttpMethod.Post, token);
|
||||
return await SendHttpRequest<GenerateOnChainWalletResponse>($"api/v1/stores/{storeId}/payment-methods/{paymentMethodId}/generate", request, HttpMethod.Post, token);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -15,7 +15,7 @@ public partial class BTCPayServerClient
|
||||
parameters.Add("includeNeighbourData", v);
|
||||
try
|
||||
{
|
||||
return await SendHttpRequest<OnChainWalletObjectData>($"api/v1/stores/{storeId}/payment-methods/{cryptoCode}-CHAIN/wallet/objects/{objectId.Type}/{objectId.Id}", parameters, HttpMethod.Get, token);
|
||||
return await SendHttpRequest<OnChainWalletObjectData>($"api/v1/stores/{storeId}/payment-methods/onchain/{cryptoCode}/wallet/objects/{objectId.Type}/{objectId.Id}", parameters, HttpMethod.Get, token);
|
||||
}
|
||||
catch (GreenfieldAPIException err) when (err.APIError.Code == "wallet-object-not-found")
|
||||
{
|
||||
@ -31,17 +31,17 @@ public partial class BTCPayServerClient
|
||||
parameters.Add("ids", ids);
|
||||
if (query?.IncludeNeighbourData is bool v)
|
||||
parameters.Add("includeNeighbourData", v);
|
||||
return await SendHttpRequest<OnChainWalletObjectData[]>($"api/v1/stores/{storeId}/payment-methods/{cryptoCode}-CHAIN/wallet/objects", parameters, HttpMethod.Get, token);
|
||||
return await SendHttpRequest<OnChainWalletObjectData[]>($"api/v1/stores/{storeId}/payment-methods/onchain/{cryptoCode}/wallet/objects", parameters, HttpMethod.Get, token);
|
||||
}
|
||||
public virtual async Task RemoveOnChainWalletObject(string storeId, string cryptoCode, OnChainWalletObjectId objectId,
|
||||
CancellationToken token = default)
|
||||
{
|
||||
await SendHttpRequest($"api/v1/stores/{storeId}/payment-methods/{cryptoCode}-CHAIN/wallet/objects/{objectId.Type}/{objectId.Id}", null, HttpMethod.Delete, token);
|
||||
await SendHttpRequest($"api/v1/stores/{storeId}/payment-methods/onchain/{cryptoCode}/wallet/objects/{objectId.Type}/{objectId.Id}", null, HttpMethod.Delete, token);
|
||||
}
|
||||
public virtual async Task<OnChainWalletObjectData> AddOrUpdateOnChainWalletObject(string storeId, string cryptoCode, AddOnChainWalletObjectRequest request,
|
||||
CancellationToken token = default)
|
||||
{
|
||||
return await SendHttpRequest<OnChainWalletObjectData>($"api/v1/stores/{storeId}/payment-methods/{cryptoCode}-CHAIN/wallet/objects", request, HttpMethod.Post, token);
|
||||
return await SendHttpRequest<OnChainWalletObjectData>($"api/v1/stores/{storeId}/payment-methods/onchain/{cryptoCode}/wallet/objects", request, HttpMethod.Post, token);
|
||||
}
|
||||
|
||||
public virtual async Task AddOrUpdateOnChainWalletLink(string storeId, string cryptoCode,
|
||||
@ -49,7 +49,7 @@ public partial class BTCPayServerClient
|
||||
AddOnChainWalletObjectLinkRequest request = null,
|
||||
CancellationToken token = default)
|
||||
{
|
||||
await SendHttpRequest($"api/v1/stores/{storeId}/payment-methods/{cryptoCode}-CHAIN/wallet/objects/{objectId.Type}/{objectId.Id}/links", request, HttpMethod.Post, token);
|
||||
await SendHttpRequest($"api/v1/stores/{storeId}/payment-methods/onchain/{cryptoCode}/wallet/objects/{objectId.Type}/{objectId.Id}/links", request, HttpMethod.Post, token);
|
||||
}
|
||||
|
||||
public virtual async Task RemoveOnChainWalletLinks(string storeId, string cryptoCode,
|
||||
@ -57,6 +57,6 @@ public partial class BTCPayServerClient
|
||||
OnChainWalletObjectId link,
|
||||
CancellationToken token = default)
|
||||
{
|
||||
await SendHttpRequest($"api/v1/stores/{storeId}/payment-methods/{cryptoCode}-CHAIN/wallet/objects/{objectId.Type}/{objectId.Id}/links/{link.Type}/{link.Id}", null, HttpMethod.Delete, token);
|
||||
await SendHttpRequest($"api/v1/stores/{storeId}/payment-methods/onchain/{cryptoCode}/wallet/objects/{objectId.Type}/{objectId.Id}/links/{link.Type}/{link.Id}", null, HttpMethod.Delete, token);
|
||||
}
|
||||
}
|
||||
|
@ -14,16 +14,8 @@ public partial class BTCPayServerClient
|
||||
public virtual async Task<OnChainWalletOverviewData> ShowOnChainWalletOverview(string storeId, string cryptoCode,
|
||||
CancellationToken token = default)
|
||||
{
|
||||
return await SendHttpRequest<OnChainWalletOverviewData>($"api/v1/stores/{storeId}/payment-methods/{cryptoCode}-CHAIN/wallet", null, HttpMethod.Get, token);
|
||||
return await SendHttpRequest<OnChainWalletOverviewData>($"api/v1/stores/{storeId}/payment-methods/onchain/{cryptoCode}/wallet", null, HttpMethod.Get, token);
|
||||
}
|
||||
|
||||
public virtual async Task<HistogramData> GetOnChainWalletHistogram(string storeId, string cryptoCode, HistogramType? type = null,
|
||||
CancellationToken token = default)
|
||||
{
|
||||
var queryPayload = type == null ? null : new Dictionary<string, object> { { "type", type.ToString() } };
|
||||
return await SendHttpRequest<HistogramData>($"api/v1/stores/{storeId}/payment-methods/{cryptoCode}-CHAIN/wallet/histogram", queryPayload, HttpMethod.Get, token);
|
||||
}
|
||||
|
||||
public virtual async Task<OnChainWalletFeeRateData> GetOnChainFeeRate(string storeId, string cryptoCode, int? blockTarget = null,
|
||||
CancellationToken token = default)
|
||||
{
|
||||
@ -32,13 +24,13 @@ public partial class BTCPayServerClient
|
||||
{
|
||||
queryParams.Add("blockTarget", blockTarget);
|
||||
}
|
||||
return await SendHttpRequest<OnChainWalletFeeRateData>($"api/v1/stores/{storeId}/payment-methods/{cryptoCode}-CHAIN/wallet/feerate", queryParams, HttpMethod.Get, token);
|
||||
return await SendHttpRequest<OnChainWalletFeeRateData>($"api/v1/stores/{storeId}/payment-methods/onchain/{cryptoCode}/wallet/feeRate", queryParams, HttpMethod.Get, token);
|
||||
}
|
||||
|
||||
public virtual async Task<OnChainWalletAddressData> GetOnChainWalletReceiveAddress(string storeId, string cryptoCode, bool forceGenerate = false,
|
||||
CancellationToken token = default)
|
||||
{
|
||||
return await SendHttpRequest<OnChainWalletAddressData>($"api/v1/stores/{storeId}/payment-methods/{cryptoCode}-CHAIN/wallet/address", new Dictionary<string, object>
|
||||
return await SendHttpRequest<OnChainWalletAddressData>($"api/v1/stores/{storeId}/payment-methods/onchain/{cryptoCode}/wallet/address", new Dictionary<string, object>
|
||||
{
|
||||
{"forceGenerate", forceGenerate}
|
||||
}, HttpMethod.Get, token);
|
||||
@ -47,7 +39,7 @@ public partial class BTCPayServerClient
|
||||
public virtual async Task UnReserveOnChainWalletReceiveAddress(string storeId, string cryptoCode,
|
||||
CancellationToken token = default)
|
||||
{
|
||||
await SendHttpRequest($"api/v1/stores/{storeId}/payment-methods/{cryptoCode}-CHAIN/wallet/address", null, HttpMethod.Delete, token);
|
||||
await SendHttpRequest($"api/v1/stores/{storeId}/payment-methods/onchain/{cryptoCode}/wallet/address", null, HttpMethod.Delete, token);
|
||||
}
|
||||
|
||||
public virtual async Task<IEnumerable<OnChainWalletTransactionData>> ShowOnChainWalletTransactions(
|
||||
@ -67,14 +59,14 @@ public partial class BTCPayServerClient
|
||||
{
|
||||
query.Add(nameof(skip), skip);
|
||||
}
|
||||
return await SendHttpRequest<IEnumerable<OnChainWalletTransactionData>>($"api/v1/stores/{storeId}/payment-methods/{cryptoCode}-CHAIN/wallet/transactions", query, HttpMethod.Get, token);
|
||||
return await SendHttpRequest<IEnumerable<OnChainWalletTransactionData>>($"api/v1/stores/{storeId}/payment-methods/onchain/{cryptoCode}/wallet/transactions", query, HttpMethod.Get, token);
|
||||
}
|
||||
|
||||
public virtual async Task<OnChainWalletTransactionData> GetOnChainWalletTransaction(
|
||||
string storeId, string cryptoCode, string transactionId,
|
||||
CancellationToken token = default)
|
||||
{
|
||||
return await SendHttpRequest<OnChainWalletTransactionData>($"api/v1/stores/{storeId}/payment-methods/{cryptoCode}-CHAIN/wallet/transactions/{transactionId}", null, HttpMethod.Get, token);
|
||||
return await SendHttpRequest<OnChainWalletTransactionData>($"api/v1/stores/{storeId}/payment-methods/onchain/{cryptoCode}/wallet/transactions/{transactionId}", null, HttpMethod.Get, token);
|
||||
}
|
||||
|
||||
public virtual async Task<OnChainWalletTransactionData> PatchOnChainWalletTransaction(
|
||||
@ -82,7 +74,7 @@ public partial class BTCPayServerClient
|
||||
PatchOnChainTransactionRequest request,
|
||||
bool force = false, CancellationToken token = default)
|
||||
{
|
||||
return await SendHttpRequest<PatchOnChainTransactionRequest, OnChainWalletTransactionData>($"api/v1/stores/{storeId}/payment-methods/{cryptoCode}-CHAIN/wallet/transactions/{transactionId}",
|
||||
return await SendHttpRequest<PatchOnChainTransactionRequest, OnChainWalletTransactionData>($"api/v1/stores/{storeId}/payment-methods/onchain/{cryptoCode}/wallet/transactions/{transactionId}",
|
||||
new Dictionary<string, object> { {"force", force} }, request, HttpMethod.Patch, token);
|
||||
}
|
||||
|
||||
@ -90,7 +82,7 @@ public partial class BTCPayServerClient
|
||||
string cryptoCode,
|
||||
CancellationToken token = default)
|
||||
{
|
||||
return await SendHttpRequest<IEnumerable<OnChainWalletUTXOData>>($"api/v1/stores/{storeId}/payment-methods/{cryptoCode}-CHAIN/wallet/utxos", null, HttpMethod.Get, token);
|
||||
return await SendHttpRequest<IEnumerable<OnChainWalletUTXOData>>($"api/v1/stores/{storeId}/payment-methods/onchain/{cryptoCode}/wallet/utxos", null, HttpMethod.Get, token);
|
||||
}
|
||||
|
||||
public virtual async Task<OnChainWalletTransactionData> CreateOnChainTransaction(string storeId,
|
||||
@ -102,7 +94,7 @@ public partial class BTCPayServerClient
|
||||
throw new ArgumentOutOfRangeException(nameof(request.ProceedWithBroadcast),
|
||||
"Please use CreateOnChainTransactionButDoNotBroadcast when wanting to only create the transaction");
|
||||
}
|
||||
return await SendHttpRequest<OnChainWalletTransactionData>($"api/v1/stores/{storeId}/payment-methods/{cryptoCode}-CHAIN/wallet/transactions", request, HttpMethod.Post, token);
|
||||
return await SendHttpRequest<OnChainWalletTransactionData>($"api/v1/stores/{storeId}/payment-methods/onchain/{cryptoCode}/wallet/transactions", request, HttpMethod.Post, token);
|
||||
}
|
||||
|
||||
public virtual async Task<Transaction> CreateOnChainTransactionButDoNotBroadcast(string storeId,
|
||||
@ -114,6 +106,6 @@ public partial class BTCPayServerClient
|
||||
throw new ArgumentOutOfRangeException(nameof(request.ProceedWithBroadcast),
|
||||
"Please use CreateOnChainTransaction when wanting to also broadcast the transaction");
|
||||
}
|
||||
return Transaction.Parse(await SendHttpRequest<string>($"api/v1/stores/{storeId}/payment-methods/{cryptoCode}-CHAIN/wallet/transactions", request, HttpMethod.Post, token), network);
|
||||
return Transaction.Parse(await SendHttpRequest<string>($"api/v1/stores/{storeId}/payment-methods/onchain/{cryptoCode}/wallet/transactions", request, HttpMethod.Post, token), network);
|
||||
}
|
||||
}
|
||||
|
@ -19,14 +19,14 @@ public partial class BTCPayServerClient
|
||||
await SendHttpRequest($"api/v1/stores/{storeId}/payout-processors/{processor}/{paymentMethod}", null, HttpMethod.Delete, token);
|
||||
}
|
||||
|
||||
public virtual async Task<IEnumerable<LightningAutomatedPayoutSettings>> GetStoreLightningAutomatedPayoutProcessors(string storeId, string? payoutMethodId = null, CancellationToken token = default)
|
||||
public virtual async Task<IEnumerable<LightningAutomatedPayoutSettings>> GetStoreLightningAutomatedPayoutProcessors(string storeId, string? paymentMethod = null, CancellationToken token = default)
|
||||
{
|
||||
return await SendHttpRequest<IEnumerable<LightningAutomatedPayoutSettings>>($"api/v1/stores/{storeId}/payout-processors/LightningAutomatedPayoutSenderFactory{(payoutMethodId is null ? string.Empty : $"/{payoutMethodId}")}", null, HttpMethod.Get, token);
|
||||
return await SendHttpRequest<IEnumerable<LightningAutomatedPayoutSettings>>($"api/v1/stores/{storeId}/payout-processors/LightningAutomatedPayoutSenderFactory{(paymentMethod is null ? string.Empty : $"/{paymentMethod}")}", null, HttpMethod.Get, token);
|
||||
}
|
||||
|
||||
public virtual async Task<LightningAutomatedPayoutSettings> UpdateStoreLightningAutomatedPayoutProcessors(string storeId, string payoutMethodId, LightningAutomatedPayoutSettings request, CancellationToken token = default)
|
||||
public virtual async Task<LightningAutomatedPayoutSettings> UpdateStoreLightningAutomatedPayoutProcessors(string storeId, string paymentMethod, LightningAutomatedPayoutSettings request, CancellationToken token = default)
|
||||
{
|
||||
return await SendHttpRequest<LightningAutomatedPayoutSettings>($"api/v1/stores/{storeId}/payout-processors/LightningAutomatedPayoutSenderFactory/{payoutMethodId}", request, HttpMethod.Put, token);
|
||||
return await SendHttpRequest<LightningAutomatedPayoutSettings>($"api/v1/stores/{storeId}/payout-processors/LightningAutomatedPayoutSenderFactory/{paymentMethod}", request, HttpMethod.Put, token);
|
||||
}
|
||||
|
||||
public virtual async Task<OnChainAutomatedPayoutSettings> UpdateStoreOnChainAutomatedPayoutProcessors(string storeId, string paymentMethod, OnChainAutomatedPayoutSettings request, CancellationToken token = default)
|
||||
|
@ -29,10 +29,4 @@ public partial class BTCPayServerClient
|
||||
if (request == null) throw new ArgumentNullException(nameof(request));
|
||||
await SendHttpRequest<StoreUserData>($"api/v1/stores/{storeId}/users", request, HttpMethod.Post, token);
|
||||
}
|
||||
|
||||
public virtual async Task UpdateStoreUser(string storeId, string userId, StoreUserData request, CancellationToken token = default)
|
||||
{
|
||||
if (request == null) throw new ArgumentNullException(nameof(request));
|
||||
await SendHttpRequest<StoreUserData>($"api/v1/stores/{storeId}/users/{userId}", request, HttpMethod.Put, token);
|
||||
}
|
||||
}
|
||||
|
@ -156,7 +156,7 @@ public partial class BTCPayServerClient
|
||||
protected virtual async Task<T> UploadFileRequest<T>(string apiPath, string filePath, string mimeType, string formFieldName, HttpMethod method = null, CancellationToken token = default)
|
||||
{
|
||||
using MultipartFormDataContent multipartContent = new();
|
||||
using var fileContent = new StreamContent(File.OpenRead(filePath));
|
||||
var fileContent = new StreamContent(File.OpenRead(filePath));
|
||||
var fileName = Path.GetFileName(filePath);
|
||||
fileContent.Headers.ContentType = MediaTypeHeaderValue.Parse(mimeType);
|
||||
multipartContent.Add(fileContent, formFieldName, fileName);
|
||||
|
@ -1,13 +0,0 @@
|
||||
using BTCPayServer.JsonConverters;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace BTCPayServer.Client.Models;
|
||||
|
||||
public class AppCartItem
|
||||
{
|
||||
public string Id { get; set; }
|
||||
public string Title { get; set; }
|
||||
public int Count { get; set; }
|
||||
[JsonConverter(typeof(NumericStringJsonConverter))]
|
||||
public decimal Price { get; set; }
|
||||
}
|
@ -1,35 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using BTCPayServer.JsonConverters;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Converters;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace BTCPayServer.Client.Models;
|
||||
|
||||
public enum AppItemPriceType
|
||||
{
|
||||
Fixed,
|
||||
Topup,
|
||||
Minimum
|
||||
}
|
||||
|
||||
public class AppItem
|
||||
{
|
||||
public string Id { get; set; }
|
||||
public string Title { get; set; }
|
||||
public bool Disabled { get; set; }
|
||||
public string Description { get; set; }
|
||||
public string[] Categories { get; set; }
|
||||
public string Image { get; set; }
|
||||
|
||||
[JsonConverter(typeof(StringEnumConverter))]
|
||||
public AppItemPriceType PriceType { get; set; }
|
||||
|
||||
[JsonConverter(typeof(NumericStringJsonConverter))]
|
||||
public decimal? Price { get; set; }
|
||||
public string BuyButtonText { get; set; }
|
||||
public int? Inventory { get; set; }
|
||||
|
||||
[JsonExtensionData]
|
||||
public Dictionary<string, JToken> AdditionalData { get; set; }
|
||||
}
|
@ -1,15 +0,0 @@
|
||||
using BTCPayServer.JsonConverters;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace BTCPayServer.Client.Models;
|
||||
|
||||
public class AppItemStats
|
||||
{
|
||||
public string ItemCode { get; set; }
|
||||
public string Title { get; set; }
|
||||
public int SalesCount { get; set; }
|
||||
|
||||
[JsonConverter(typeof(NumericStringJsonConverter))]
|
||||
public decimal Total { get; set; }
|
||||
public string TotalFormatted { get; set; }
|
||||
}
|
@ -1,19 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace BTCPayServer.Client.Models;
|
||||
|
||||
public class AppSalesStats
|
||||
{
|
||||
public int SalesCount { get; set; }
|
||||
public IEnumerable<AppSalesStatsItem> Series { get; set; }
|
||||
}
|
||||
|
||||
public class AppSalesStatsItem
|
||||
{
|
||||
[JsonConverter(typeof(NBitcoin.JsonConverters.DateTimeToUnixTimeConverter))]
|
||||
public DateTime Date { get; set; }
|
||||
public string Label { get; set; }
|
||||
public int SalesCount { get; set; }
|
||||
}
|
@ -8,6 +8,6 @@ namespace BTCPayServer.Client.Models
|
||||
public string Destination { get; set; }
|
||||
[JsonConverter(typeof(NumericStringJsonConverter))]
|
||||
public decimal? Amount { get; set; }
|
||||
public string PayoutMethodId { get; set; }
|
||||
public string PaymentMethod { get; set; }
|
||||
}
|
||||
}
|
||||
|
@ -1,25 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using BTCPayServer.JsonConverters;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace BTCPayServer.Client.Models;
|
||||
|
||||
public class CreatePosInvoiceRequest
|
||||
{
|
||||
public string AppId { get; set; }
|
||||
public List<AppCartItem> Cart { get; set; }
|
||||
[JsonProperty(ItemConverterType = typeof(NumericStringJsonConverter))]
|
||||
public List<decimal> Amounts { get; set; }
|
||||
public int? DiscountPercent { get; set; }
|
||||
public int? TipPercent { get; set; }
|
||||
[JsonConverter(typeof(NumericStringJsonConverter))]
|
||||
public decimal? DiscountAmount { get; set; }
|
||||
[JsonConverter(typeof(NumericStringJsonConverter))]
|
||||
public decimal? Tip { get; set; }
|
||||
[JsonConverter(typeof(NumericStringJsonConverter))]
|
||||
public decimal? Subtotal { get; set; }
|
||||
[JsonConverter(typeof(NumericStringJsonConverter))]
|
||||
public decimal? Total { get; set; }
|
||||
public string PosData { get; set; }
|
||||
}
|
||||
|
@ -19,7 +19,7 @@ namespace BTCPayServer.Client.Models
|
||||
public DateTimeOffset? ExpiresAt { get; set; }
|
||||
[JsonConverter(typeof(NBitcoin.JsonConverters.DateTimeToUnixTimeConverter))]
|
||||
public DateTimeOffset? StartsAt { get; set; }
|
||||
public string[] PayoutMethods { get; set; }
|
||||
public string[] PaymentMethods { get; set; }
|
||||
public bool AutoApproveClaims { get; set; }
|
||||
}
|
||||
}
|
||||
|
@ -37,7 +37,7 @@ public abstract class CrowdfundBaseData : AppBaseData
|
||||
|
||||
public class CrowdfundAppData : CrowdfundBaseData
|
||||
{
|
||||
public AppItem[]? Perks { get; set; }
|
||||
public object? Perks { get; set; }
|
||||
}
|
||||
|
||||
public class CrowdfundAppRequest : CrowdfundBaseData, IAppRequest
|
||||
|
@ -10,7 +10,6 @@ namespace BTCPayServer.Client
|
||||
{
|
||||
public class GenerateOnChainWalletRequest
|
||||
{
|
||||
public string Label { get; set; }
|
||||
public int AccountNumber { get; set; } = 0;
|
||||
[JsonConverter(typeof(MnemonicJsonConverter))]
|
||||
public Mnemonic ExistingMnemonic { get; set; }
|
||||
@ -30,7 +29,6 @@ namespace BTCPayServer.Client
|
||||
{
|
||||
public class ConfigData
|
||||
{
|
||||
public string Label { get; set; }
|
||||
public string AccountDerivation { get; set; }
|
||||
[JsonExtensionData]
|
||||
IDictionary<string, JToken> AdditionalData { get; set; }
|
||||
|
@ -1,30 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using BTCPayServer.JsonConverters;
|
||||
using NBitcoin.JsonConverters;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Converters;
|
||||
|
||||
namespace BTCPayServer.Client.Models;
|
||||
|
||||
public enum HistogramType
|
||||
{
|
||||
Week,
|
||||
Month,
|
||||
YTD,
|
||||
Year,
|
||||
TwoYears,
|
||||
Day
|
||||
}
|
||||
|
||||
public class HistogramData
|
||||
{
|
||||
[JsonConverter(typeof(StringEnumConverter))]
|
||||
public HistogramType Type { get; set; }
|
||||
[JsonProperty(ItemConverterType = typeof(NumericStringJsonConverter))]
|
||||
public List<decimal> Series { get; set; }
|
||||
[JsonProperty(ItemConverterType = typeof(DateTimeToUnixTimeConverter))]
|
||||
public List<DateTimeOffset> Labels { get; set; }
|
||||
[JsonConverter(typeof(NumericStringJsonConverter))]
|
||||
public decimal Balance { get; set; }
|
||||
}
|
@ -6,11 +6,12 @@ namespace BTCPayServer.Client.Models;
|
||||
|
||||
public class LightningAutomatedPayoutSettings
|
||||
{
|
||||
public string PayoutMethodId { get; set; }
|
||||
public string PaymentMethod { get; set; }
|
||||
|
||||
[JsonConverter(typeof(TimeSpanJsonConverter.Seconds))]
|
||||
public TimeSpan IntervalSeconds { get; set; }
|
||||
|
||||
public int? CancelPayoutAfterFailures { get; set; }
|
||||
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Populate)]
|
||||
public bool ProcessNewPayoutsInstantly { get; set; }
|
||||
|
||||
|
@ -11,7 +11,7 @@ namespace BTCPayServer.Client.Models
|
||||
public string Body { get; set; }
|
||||
public string StoreId { get; set; }
|
||||
public bool Seen { get; set; }
|
||||
public string Link { get; set; }
|
||||
public Uri Link { get; set; }
|
||||
|
||||
[JsonConverter(typeof(NBitcoin.JsonConverters.DateTimeToUnixTimeConverter))]
|
||||
public DateTimeOffset CreatedTime { get; set; }
|
||||
|
@ -6,7 +6,7 @@ namespace BTCPayServer.Client.Models;
|
||||
|
||||
public class OnChainAutomatedPayoutSettings
|
||||
{
|
||||
public string PayoutMethodId { get; set; }
|
||||
public string PaymentMethod { get; set; }
|
||||
|
||||
[JsonConverter(typeof(TimeSpanJsonConverter.Seconds))]
|
||||
public TimeSpan IntervalSeconds { get; set; }
|
||||
|
@ -5,7 +5,7 @@ namespace BTCPayServer.Client.Models;
|
||||
|
||||
public class PaymentMethodCriteriaData
|
||||
{
|
||||
public string PaymentMethodId { get; set; }
|
||||
public string PaymentMethod { get; set; }
|
||||
public string CurrencyCode { get; set; }
|
||||
[JsonConverter(typeof(NumericStringJsonConverter))]
|
||||
public decimal Amount { get; set; }
|
||||
|
@ -21,13 +21,12 @@ namespace BTCPayServer.Client.Models
|
||||
public string Id { get; set; }
|
||||
public string PullPaymentId { get; set; }
|
||||
public string Destination { get; set; }
|
||||
public string PayoutMethodId { get; set; }
|
||||
public string PaymentMethod { get; set; }
|
||||
public string CryptoCode { get; set; }
|
||||
[JsonConverter(typeof(NumericStringJsonConverter))]
|
||||
public decimal OriginalAmount { get; set; }
|
||||
public string OriginalCurrency { get; set; }
|
||||
public string PayoutCurrency { get; set; }
|
||||
public decimal Amount { get; set; }
|
||||
[JsonConverter(typeof(NumericStringJsonConverter))]
|
||||
public decimal? PayoutAmount { get; set; }
|
||||
public decimal? PaymentMethodAmount { get; set; }
|
||||
[JsonConverter(typeof(StringEnumConverter))]
|
||||
public PayoutState State { get; set; }
|
||||
public int Revision { get; set; }
|
||||
|
@ -4,6 +4,6 @@ namespace BTCPayServer.Client.Models
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public string FriendlyName { get; set; }
|
||||
public string[] PayoutMethods { get; set; }
|
||||
public string[] PaymentMethods { get; set; }
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace BTCPayServer.Client.Models
|
||||
@ -10,17 +11,17 @@ namespace BTCPayServer.Client.Models
|
||||
static PermissionMetadata()
|
||||
{
|
||||
Dictionary<string, PermissionMetadata> nodes = new Dictionary<string, PermissionMetadata>();
|
||||
foreach (var policy in Policies.AllPolicies)
|
||||
foreach (var policy in Client.Policies.AllPolicies)
|
||||
{
|
||||
nodes.Add(policy, new PermissionMetadata() { PermissionName = policy });
|
||||
}
|
||||
foreach (var n in nodes)
|
||||
{
|
||||
foreach (var policy in Policies.AllPolicies)
|
||||
foreach (var policy in Client.Policies.AllPolicies)
|
||||
{
|
||||
if (policy.Equals(n.Key, StringComparison.OrdinalIgnoreCase))
|
||||
continue;
|
||||
if (Permission.Create(n.Key).Contains(Permission.Create(policy)))
|
||||
if (Client.Permission.Create(n.Key).Contains(Client.Permission.Create(policy)))
|
||||
n.Value.SubPermissions.Add(policy);
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,8 @@
|
||||
#nullable enable
|
||||
using System.Collections.Generic;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Converters;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace BTCPayServer.Client.Models;
|
||||
|
||||
@ -29,7 +31,7 @@ public abstract class PointOfSaleBaseData : AppBaseData
|
||||
|
||||
public class PointOfSaleAppData : PointOfSaleBaseData
|
||||
{
|
||||
public AppItem[]? Items { get; set; }
|
||||
public object? Items { get; set; }
|
||||
}
|
||||
|
||||
public class PointOfSaleAppRequest : PointOfSaleBaseData, IAppRequest
|
||||
|
@ -17,7 +17,7 @@ namespace BTCPayServer.Client.Models
|
||||
public class RefundInvoiceRequest
|
||||
{
|
||||
public string? Name { get; set; } = null;
|
||||
public string? PayoutMethodId { get; set; }
|
||||
public string? PaymentMethod { get; set; }
|
||||
public string? Description { get; set; } = null;
|
||||
|
||||
[JsonConverter(typeof(StringEnumConverter))]
|
||||
|
@ -32,7 +32,7 @@ namespace BTCPayServer.Client.Models
|
||||
|
||||
public class SyncStatus
|
||||
{
|
||||
public string PaymentMethodId { get; set; }
|
||||
public string CryptoCode { get; set; }
|
||||
public virtual bool Available { get; set; }
|
||||
}
|
||||
|
||||
|
@ -17,7 +17,6 @@ namespace BTCPayServer.Client.Models
|
||||
public string Website { get; set; }
|
||||
|
||||
public string BrandColor { get; set; }
|
||||
public bool ApplyBrandColorToBackend { get; set; }
|
||||
public string LogoUrl { get; set; }
|
||||
public string CssUrl { get; set; }
|
||||
public string PaymentSoundUrl { get; set; }
|
||||
|
@ -17,25 +17,7 @@ namespace BTCPayServer.Client.Models
|
||||
/// </summary>
|
||||
public string UserId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// the store role of the user
|
||||
/// </summary>
|
||||
public string Role { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// the email AND username of the user
|
||||
/// </summary>
|
||||
public string Email { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// the name of the user
|
||||
/// </summary>
|
||||
public string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// the image url of the user
|
||||
/// </summary>
|
||||
public string ImageUrl { get; set; }
|
||||
}
|
||||
|
||||
public class RoleData
|
||||
|
@ -1,9 +1,8 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Linq.Expressions;
|
||||
|
||||
namespace BTCPayServer.Client
|
||||
{
|
||||
@ -17,7 +16,7 @@ namespace BTCPayServer.Client
|
||||
public const string CanUseLightningNodeInStore = "btcpay.store.canuselightningnode";
|
||||
public const string CanModifyServerSettings = "btcpay.server.canmodifyserversettings";
|
||||
public const string CanModifyStoreSettings = "btcpay.store.canmodifystoresettings";
|
||||
public const string CanModifyWebhooks = "btcpay.store.webhooks.canmodifywebhooks";
|
||||
public const string CanModifyStoreWebhooks = "btcpay.store.webhooks.canmodifywebhooks";
|
||||
public const string CanModifyStoreSettingsUnscoped = "btcpay.store.canmodifystoresettings:";
|
||||
public const string CanViewStoreSettings = "btcpay.store.canviewstoresettings";
|
||||
public const string CanViewReports = "btcpay.store.canviewreports";
|
||||
@ -49,7 +48,7 @@ namespace BTCPayServer.Client
|
||||
yield return CanViewInvoices;
|
||||
yield return CanCreateInvoice;
|
||||
yield return CanModifyInvoices;
|
||||
yield return CanModifyWebhooks;
|
||||
yield return CanModifyStoreWebhooks;
|
||||
yield return CanModifyServerSettings;
|
||||
yield return CanModifyStoreSettings;
|
||||
yield return CanViewStoreSettings;
|
||||
@ -105,16 +104,6 @@ namespace BTCPayServer.Client
|
||||
{
|
||||
return policy.StartsWith("btcpay.user", StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
private static readonly CultureInfo _culture = new (CultureInfo.InvariantCulture.Name);
|
||||
public static string DisplayName(string policy)
|
||||
{
|
||||
var p = policy.Split(".");
|
||||
if (p.Length < 3 || p[0] != "btcpay") return policy;
|
||||
var constName = typeof(Policies).GetFields().Select(f => f.Name).FirstOrDefault(f => f.Equals(p[^1], StringComparison.OrdinalIgnoreCase));
|
||||
var perm = string.IsNullOrEmpty(constName) ? string.Join(' ', p[2..]) : Regex.Replace(constName, "([A-Z])", " $1", RegexOptions.Compiled).Trim();
|
||||
return $"{_culture.TextInfo.ToTitleCase(p[1])}: {_culture.TextInfo.ToTitleCase(perm)}";
|
||||
}
|
||||
}
|
||||
|
||||
public class PermissionSet
|
||||
@ -258,7 +247,7 @@ namespace BTCPayServer.Client
|
||||
Policies.CanManagePullPayments,
|
||||
Policies.CanModifyInvoices,
|
||||
Policies.CanViewStoreSettings,
|
||||
Policies.CanModifyWebhooks,
|
||||
Policies.CanModifyStoreWebhooks,
|
||||
Policies.CanModifyPaymentRequests,
|
||||
Policies.CanManagePayouts,
|
||||
Policies.CanUseLightningNodeInStore);
|
||||
|
@ -131,7 +131,7 @@ namespace BTCPayServer
|
||||
|
||||
public string GetTrackedDestination(Script scriptPubKey)
|
||||
{
|
||||
return scriptPubKey.Hash.ToString();
|
||||
return scriptPubKey.Hash.ToString() + "#" + CryptoCode.ToUpperInvariant();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -30,6 +30,11 @@ namespace BTCPayServer
|
||||
Logs logs)
|
||||
{
|
||||
var networksList = networks.ToList();
|
||||
#if !ALTCOINS
|
||||
var onlyBTC = networksList.Count == 1 && networksList.First().IsBTC;
|
||||
if (!onlyBTC)
|
||||
throw new ConfigException($"This build of BTCPay Server does not support altcoins. Configured networks: {string.Join(',', networksList.Select(n => n.CryptoCode).ToArray())}");
|
||||
#endif
|
||||
_NBXplorerNetworkProvider = nbxplorerNetworkProvider;
|
||||
NetworkType = nbxplorerNetworkProvider.NetworkType;
|
||||
foreach (var network in networksList)
|
||||
|
@ -2,7 +2,13 @@
|
||||
<Import Project="../Build/Version.csproj" Condition="Exists('../Build/Version.csproj')" />
|
||||
<Import Project="../Build/Common.csproj" />
|
||||
<ItemGroup>
|
||||
<PackageReference Include="NBXplorer.Client" Version="4.3.6" />
|
||||
<PackageReference Include="NBXplorer.Client" Version="4.3.1" />
|
||||
<PackageReference Include="NicolasDorier.StandardConfiguration" Version="2.0.1" />
|
||||
</ItemGroup>
|
||||
<ItemGroup Condition="'$(Altcoins)' != 'true'">
|
||||
<Compile Remove="Altcoins\**\*.cs"></Compile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="Altcoins\" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
97
BTCPayServer.Common/CustomThreadPool.cs
Normal file
97
BTCPayServer.Common/CustomThreadPool.cs
Normal file
@ -0,0 +1,97 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BTCPayServer
|
||||
{
|
||||
public class CustomThreadPool : IDisposable
|
||||
{
|
||||
readonly CancellationTokenSource _Cancel = new CancellationTokenSource();
|
||||
readonly TaskCompletionSource<bool> _Exited;
|
||||
int _ExitedCount = 0;
|
||||
readonly Thread[] _Threads;
|
||||
Exception _UnhandledException;
|
||||
readonly BlockingCollection<(Action, TaskCompletionSource<object>)> _Actions = new BlockingCollection<(Action, TaskCompletionSource<object>)>(new ConcurrentQueue<(Action, TaskCompletionSource<object>)>());
|
||||
|
||||
public CustomThreadPool(int threadCount, string threadName)
|
||||
{
|
||||
if (threadCount <= 0)
|
||||
throw new ArgumentOutOfRangeException(nameof(threadCount));
|
||||
_Exited = new TaskCompletionSource<bool>();
|
||||
_Threads = Enumerable.Range(0, threadCount).Select(_ => new Thread(RunLoop) { Name = threadName }).ToArray();
|
||||
foreach (var t in _Threads)
|
||||
t.Start();
|
||||
}
|
||||
|
||||
public void Do(Action act)
|
||||
{
|
||||
DoAsync(act).GetAwaiter().GetResult();
|
||||
}
|
||||
|
||||
public T Do<T>(Func<T> act)
|
||||
{
|
||||
return DoAsync(act).GetAwaiter().GetResult();
|
||||
}
|
||||
|
||||
public async Task<T> DoAsync<T>(Func<T> act)
|
||||
{
|
||||
TaskCompletionSource<object> done = new TaskCompletionSource<object>();
|
||||
_Actions.Add((() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
done.TrySetResult(act());
|
||||
}
|
||||
catch (Exception ex) { done.TrySetException(ex); }
|
||||
}
|
||||
, done));
|
||||
return (T)(await done.Task.ConfigureAwait(false));
|
||||
}
|
||||
|
||||
public Task DoAsync(Action act)
|
||||
{
|
||||
return DoAsync<object>(() =>
|
||||
{
|
||||
act();
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
void RunLoop()
|
||||
{
|
||||
try
|
||||
{
|
||||
foreach (var act in _Actions.GetConsumingEnumerable(_Cancel.Token))
|
||||
{
|
||||
act.Item1();
|
||||
}
|
||||
}
|
||||
catch (OperationCanceledException) when (_Cancel.IsCancellationRequested) { }
|
||||
catch (Exception ex)
|
||||
{
|
||||
_Cancel.Cancel();
|
||||
_UnhandledException = ex;
|
||||
}
|
||||
if (Interlocked.Increment(ref _ExitedCount) == _Threads.Length)
|
||||
{
|
||||
foreach (var action in _Actions)
|
||||
{
|
||||
try
|
||||
{
|
||||
action.Item2.TrySetCanceled();
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
_Exited.TrySetResult(true);
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_Cancel.Cancel();
|
||||
_Exited.Task.GetAwaiter().GetResult();
|
||||
}
|
||||
}
|
||||
}
|
@ -11,12 +11,17 @@ namespace BTCPayServer
|
||||
{
|
||||
HashSet<string> chains = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
||||
bool all = false;
|
||||
public SelectedChains(IConfiguration configuration)
|
||||
public SelectedChains(IConfiguration configuration, Logs logs)
|
||||
{
|
||||
foreach (var chain in (configuration["chains"] ?? "btc")
|
||||
.Split(',', StringSplitOptions.RemoveEmptyEntries)
|
||||
.Select(t => t.ToUpperInvariant()))
|
||||
{
|
||||
if (new[] { "ETH", "USDT20", "FAU" }.Contains(chain, StringComparer.OrdinalIgnoreCase))
|
||||
{
|
||||
logs.Configuration.LogWarning($"'{chain}' is not anymore supported, please remove it from 'chains'");
|
||||
continue;
|
||||
}
|
||||
if (chain == "*")
|
||||
{
|
||||
all = true;
|
||||
|
32
BTCPayServer.Data/App/AppStorageItemData.cs
Normal file
32
BTCPayServer.Data/App/AppStorageItemData.cs
Normal file
@ -0,0 +1,32 @@
|
||||
using BTCPayServer.Data;
|
||||
using Laraue.EfCoreTriggers.Common.Extensions;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace BTCPayServer.App.BackupStorage;
|
||||
|
||||
public class AppStorageItemData
|
||||
{
|
||||
public string Key { get; set; }
|
||||
public long Version { get; set; }
|
||||
public byte[] Value { get; set; }
|
||||
public string UserId { get; set; }
|
||||
|
||||
public static void OnModelCreating(ModelBuilder builder)
|
||||
{
|
||||
builder.Entity<AppStorageItemData>()
|
||||
.HasKey(o => new {o.Key, o.Version, o.UserId});
|
||||
builder.Entity<AppStorageItemData>()
|
||||
.HasIndex(o => new {o.Key, o.UserId}).IsUnique();
|
||||
|
||||
builder.Entity<ApplicationUser>().HasMany(user => user.AppStorageItems).WithOne(data => data.User)
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
builder.Entity<AppStorageItemData>()
|
||||
.BeforeInsert(trigger => trigger
|
||||
.Action(group => group
|
||||
.Delete<AppStorageItemData>((@ref, entity) => @ref.New.UserId == entity.UserId && @ref.New.Key == entity.Key &&
|
||||
@ref.New.Version > entity.Version)));
|
||||
}
|
||||
|
||||
public ApplicationUser User { get; set; }
|
||||
}
|
@ -1,8 +1,8 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using BTCPayServer.App.BackupStorage;
|
||||
using Laraue.EfCoreTriggers.PostgreSql.Extensions;
|
||||
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Design;
|
||||
@ -17,6 +17,7 @@ namespace BTCPayServer.Data
|
||||
var builder = new DbContextOptionsBuilder<ApplicationDbContext>();
|
||||
// Same as launchsettings.json, it's connecting to the docker's postgres.
|
||||
builder.UseNpgsql("User ID=postgres;Include Error Detail=true;Host=127.0.0.1;Port=39372;Database=btcpayserver");
|
||||
builder.UsePostgreSqlTriggers();
|
||||
return new ApplicationDbContext(builder.Options);
|
||||
}
|
||||
}
|
||||
@ -27,6 +28,8 @@ namespace BTCPayServer.Data
|
||||
{
|
||||
}
|
||||
public DbSet<AddressInvoiceData> AddressInvoices { get; set; }
|
||||
public DbSet<AppStorageItemData> AppStorageItems { get; set; }
|
||||
|
||||
public DbSet<APIKeyData> ApiKeys { get; set; }
|
||||
public DbSet<AppData> Apps { get; set; }
|
||||
public DbSet<StoredFile> Files { get; set; }
|
||||
@ -41,6 +44,7 @@ namespace BTCPayServer.Data
|
||||
public DbSet<PaymentRequestData> PaymentRequests { get; set; }
|
||||
public DbSet<PaymentData> Payments { get; set; }
|
||||
public DbSet<PayoutData> Payouts { get; set; }
|
||||
public DbSet<PendingInvoiceData> PendingInvoices { get; set; }
|
||||
public DbSet<PlannedTransaction> PlannedTransactions { get; set; }
|
||||
public DbSet<PullPaymentData> PullPayments { get; set; }
|
||||
public DbSet<RefundData> Refunds { get; set; }
|
||||
@ -63,14 +67,13 @@ namespace BTCPayServer.Data
|
||||
public DbSet<LightningAddressData> LightningAddresses { get; set; }
|
||||
public DbSet<PayoutProcessorData> PayoutProcessors { get; set; }
|
||||
public DbSet<FormData> Forms { get; set; }
|
||||
public DbSet<PendingTransaction> PendingTransactions { get; set; }
|
||||
|
||||
protected override void OnModelCreating(ModelBuilder builder)
|
||||
{
|
||||
base.OnModelCreating(builder);
|
||||
|
||||
// some of the data models don't have OnModelCreating for now, commenting them
|
||||
|
||||
AppStorageItemData.OnModelCreating(builder);
|
||||
ApplicationUser.OnModelCreating(builder, Database);
|
||||
AddressInvoiceData.OnModelCreating(builder);
|
||||
APIKeyData.OnModelCreating(builder, Database);
|
||||
@ -85,8 +88,9 @@ namespace BTCPayServer.Data
|
||||
PairingCodeData.OnModelCreating(builder);
|
||||
//PayjoinLock.OnModelCreating(builder);
|
||||
PaymentRequestData.OnModelCreating(builder, Database);
|
||||
PaymentData.OnModelCreating(builder);
|
||||
PaymentData.OnModelCreating(builder, Database);
|
||||
PayoutData.OnModelCreating(builder, Database);
|
||||
PendingInvoiceData.OnModelCreating(builder);
|
||||
//PlannedTransaction.OnModelCreating(builder);
|
||||
PullPaymentData.OnModelCreating(builder, Database);
|
||||
RefundData.OnModelCreating(builder);
|
||||
@ -109,7 +113,7 @@ namespace BTCPayServer.Data
|
||||
WebhookData.OnModelCreating(builder, Database);
|
||||
FormData.OnModelCreating(builder, Database);
|
||||
StoreRole.OnModelCreating(builder, Database);
|
||||
PendingTransaction.OnModelCreating(builder, Database);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,8 +1,10 @@
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Abstractions.Contracts;
|
||||
using BTCPayServer.Abstractions.Models;
|
||||
using Laraue.EfCoreTriggers.PostgreSql.Extensions;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Npgsql.EntityFrameworkCore.PostgreSQL.Infrastructure;
|
||||
|
||||
@ -10,20 +12,20 @@ namespace BTCPayServer.Data
|
||||
{
|
||||
public class ApplicationDbContextFactory : BaseDbContextFactory<ApplicationDbContext>
|
||||
{
|
||||
public ApplicationDbContextFactory(IOptions<DatabaseOptions> options, ILoggerFactory loggerFactory) : base(options, "")
|
||||
public ApplicationDbContextFactory(IOptions<DatabaseOptions> options) : base(options, "")
|
||||
{
|
||||
LoggerFactory = loggerFactory;
|
||||
}
|
||||
|
||||
public ILoggerFactory LoggerFactory { get; }
|
||||
|
||||
public override ApplicationDbContext CreateContext(Action<NpgsqlDbContextOptionsBuilder> npgsqlOptionsAction = null)
|
||||
{
|
||||
var builder = new DbContextOptionsBuilder<ApplicationDbContext>();
|
||||
builder.UseLoggerFactory(LoggerFactory);
|
||||
builder.AddInterceptors(MigrationInterceptor.Instance);
|
||||
builder.AddInterceptors(Data.InvoiceData.MigrationInterceptor.Instance);
|
||||
ConfigureBuilder(builder, npgsqlOptionsAction);
|
||||
|
||||
builder.UsePostgreSqlTriggers();
|
||||
return new ApplicationDbContext(builder.Options);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -3,12 +3,13 @@
|
||||
<Import Project="../Build/Common.csproj" />
|
||||
<ItemGroup>
|
||||
<FrameworkReference Include="Microsoft.AspNetCore.App" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.11">
|
||||
<PackageReference Include="Laraue.EfCoreTriggers.PostgreSql" Version="8.0.3" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.6">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="8.0.11" />
|
||||
<PackageReference Include="NBitcoin.Altcoins" Version="3.0.31" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="8.0.7" />
|
||||
<PackageReference Include="NBitcoin.Altcoins" Version="3.0.24" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\BTCPayServer.Abstractions\BTCPayServer.Abstractions.csproj" />
|
||||
@ -17,10 +18,4 @@
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="DBScripts\*.sql" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Remove="DBScripts\001.InvoiceFunctions.sql" />
|
||||
<None Remove="DBScripts\002.RefactorPayouts.sql" />
|
||||
<None Remove="DBScripts\003.RefactorPendingInvoicesPayments.sql" />
|
||||
<None Remove="DBScripts\004.MonitoredInvoices.sql" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
@ -1,12 +0,0 @@
|
||||
CREATE OR REPLACE FUNCTION get_orderid(invoice_blob jsonb)
|
||||
RETURNS text AS $$
|
||||
SELECT invoice_blob->'metadata'->>'orderId';
|
||||
$$ LANGUAGE sql IMMUTABLE;
|
||||
|
||||
CREATE OR REPLACE FUNCTION get_itemcode(invoice_blob jsonb)
|
||||
RETURNS text AS $$
|
||||
SELECT invoice_blob->'metadata'->>'itemCode';
|
||||
$$ LANGUAGE sql IMMUTABLE;
|
||||
|
||||
CREATE INDEX IF NOT EXISTS "IX_Invoices_Metadata_OrderId" ON "Invoices" (get_orderid("Blob2")) WHERE get_orderid("Blob2") IS NOT NULL;
|
||||
CREATE INDEX IF NOT EXISTS "IX_Invoices_Metadata_ItemCode" ON "Invoices" (get_itemcode("Blob2")) WHERE get_itemcode("Blob2") IS NOT NULL;
|
@ -1,62 +0,0 @@
|
||||
-- Rename column
|
||||
ALTER TABLE "Payouts" RENAME COLUMN "PaymentMethodId" TO "PayoutMethodId";
|
||||
|
||||
-- Add Currency column, guessed from the PaymentMethodId
|
||||
ALTER TABLE "Payouts" ADD COLUMN "Currency" TEXT;
|
||||
UPDATE "Payouts" SET
|
||||
"Currency" = split_part("PayoutMethodId", '_', 1),
|
||||
"PayoutMethodId"=
|
||||
CASE
|
||||
WHEN ("Blob"->>'Amount')::NUMERIC < 0 THEN 'TOPUP'
|
||||
WHEN split_part("PayoutMethodId", '_', 2) = 'LightningLike' THEN split_part("PayoutMethodId", '_', 1) || '-LN'
|
||||
ELSE split_part("PayoutMethodId", '_', 1) || '-CHAIN'
|
||||
END;
|
||||
ALTER TABLE "Payouts" ALTER COLUMN "Currency" SET NOT NULL;
|
||||
|
||||
-- Remove Currency and Limit from PullPayment Blob, and put it into the columns in the table
|
||||
ALTER TABLE "PullPayments" ADD COLUMN "Currency" TEXT;
|
||||
UPDATE "PullPayments" SET "Currency" = "Blob"->>'Currency';
|
||||
ALTER TABLE "PullPayments" ALTER COLUMN "Currency" SET NOT NULL;
|
||||
ALTER TABLE "PullPayments" ADD COLUMN "Limit" NUMERIC;
|
||||
UPDATE "PullPayments" SET "Limit" = ("Blob"->>'Limit')::NUMERIC;
|
||||
ALTER TABLE "PullPayments" ALTER COLUMN "Limit" SET NOT NULL;
|
||||
|
||||
-- Remove unused properties, rename SupportedPaymentMethods, and fix legacy payment methods IDs
|
||||
UPDATE "PullPayments" SET
|
||||
"Blob" = jsonb_set(
|
||||
"Blob" - 'SupportedPaymentMethods' - 'Limit' - 'Currency' - 'Period',
|
||||
'{SupportedPayoutMethods}',
|
||||
(SELECT jsonb_agg(to_jsonb(
|
||||
CASE
|
||||
WHEN split_part(value::TEXT, '_', 2) = 'LightningLike' THEN split_part(value::TEXT, '_', 1) || '-LN'
|
||||
ELSE split_part(value::TEXT, '_', 1) || '-CHAIN'
|
||||
END))
|
||||
FROM jsonb_array_elements_text("Blob"->'SupportedPaymentMethods') AS value
|
||||
));
|
||||
|
||||
--Remove "Amount" and "CryptoAmount" from Payout Blob, and put it into the columns in the table
|
||||
-- Respectively "OriginalAmount" and "Amount"
|
||||
|
||||
ALTER TABLE "Payouts" ADD COLUMN "Amount" NUMERIC;
|
||||
UPDATE "Payouts" SET "Amount" = ("Blob"->>'CryptoAmount')::NUMERIC;
|
||||
|
||||
ALTER TABLE "Payouts" ADD COLUMN "OriginalAmount" NUMERIC;
|
||||
UPDATE "Payouts" SET "OriginalAmount" = ("Blob"->>'Amount')::NUMERIC;
|
||||
ALTER TABLE "Payouts" ALTER COLUMN "OriginalAmount" SET NOT NULL;
|
||||
|
||||
ALTER TABLE "Payouts" ADD COLUMN "OriginalCurrency" TEXT;
|
||||
|
||||
|
||||
UPDATE "Payouts" p
|
||||
SET
|
||||
"OriginalCurrency" = "Currency",
|
||||
"Blob" = "Blob" - 'Amount' - 'CryptoAmount'
|
||||
WHERE "PullPaymentDataId" IS NULL AND "OriginalCurrency" IS NULL;
|
||||
|
||||
UPDATE "Payouts" p
|
||||
SET
|
||||
"OriginalCurrency" = pp."Currency"
|
||||
FROM "PullPayments" pp
|
||||
WHERE "OriginalCurrency" IS NULL AND pp."Id"=p."PullPaymentDataId";
|
||||
|
||||
ALTER TABLE "Payouts" ALTER COLUMN "OriginalCurrency" SET NOT NULL;
|
@ -1,9 +0,0 @@
|
||||
CREATE OR REPLACE FUNCTION is_pending(status TEXT)
|
||||
RETURNS BOOLEAN AS $$
|
||||
SELECT status = 'Processing' OR status = 'New';
|
||||
$$ LANGUAGE sql IMMUTABLE;
|
||||
|
||||
CREATE INDEX "IX_Invoices_Pending" ON "Invoices"((1)) WHERE is_pending("Status");
|
||||
CREATE INDEX "IX_Payments_Pending" ON "Payments"((1)) WHERE is_pending("Status");
|
||||
DROP TABLE "PendingInvoices";
|
||||
ANALYZE "Invoices";
|
@ -1,23 +0,0 @@
|
||||
CREATE OR REPLACE FUNCTION get_prompt(invoice_blob JSONB, payment_method_id TEXT)
|
||||
RETURNS JSONB AS $$
|
||||
SELECT invoice_blob->'prompts'->payment_method_id
|
||||
$$ LANGUAGE sql IMMUTABLE;
|
||||
|
||||
|
||||
CREATE OR REPLACE FUNCTION get_monitored_invoices(arg_payment_method_id TEXT, include_non_activated BOOLEAN)
|
||||
RETURNS TABLE (invoice_id TEXT, payment_id TEXT, payment_method_id TEXT) AS $$
|
||||
WITH cte AS (
|
||||
-- Get all the invoices which are pending. Even if no payments.
|
||||
SELECT i."Id" invoice_id, p."Id" payment_id, p."PaymentMethodId" payment_method_id FROM "Invoices" i LEFT JOIN "Payments" p ON i."Id" = p."InvoiceDataId"
|
||||
WHERE is_pending(i."Status")
|
||||
UNION ALL
|
||||
-- For invoices not pending, take all of those which have pending payments
|
||||
SELECT i."Id" invoice_id, p."Id" payment_id, p."PaymentMethodId" payment_method_id FROM "Invoices" i INNER JOIN "Payments" p ON i."Id" = p."InvoiceDataId"
|
||||
WHERE is_pending(p."Status") AND NOT is_pending(i."Status"))
|
||||
SELECT cte.* FROM cte
|
||||
JOIN "Invoices" i ON cte.invoice_id=i."Id"
|
||||
LEFT JOIN "Payments" p ON cte.payment_id=p."Id" AND cte.payment_method_id=p."PaymentMethodId"
|
||||
WHERE (p."PaymentMethodId" IS NOT NULL AND p."PaymentMethodId" = arg_payment_method_id) OR
|
||||
(p."PaymentMethodId" IS NULL AND get_prompt(i."Blob2", arg_payment_method_id) IS NOT NULL AND
|
||||
(include_non_activated IS TRUE OR (get_prompt(i."Blob2", arg_payment_method_id)->'inactive')::BOOLEAN IS NOT TRUE));
|
||||
$$ LANGUAGE SQL STABLE;
|
@ -9,7 +9,6 @@ namespace BTCPayServer.Data
|
||||
public string Address { get; set; }
|
||||
public InvoiceData InvoiceData { get; set; }
|
||||
public string InvoiceDataId { get; set; }
|
||||
public string PaymentMethodId { get; set; }
|
||||
|
||||
|
||||
internal static void OnModelCreating(ModelBuilder builder)
|
||||
@ -19,7 +18,7 @@ namespace BTCPayServer.Data
|
||||
.WithMany(i => i.AddressInvoices).OnDelete(DeleteBehavior.Cascade);
|
||||
builder.Entity<AddressInvoiceData>()
|
||||
#pragma warning disable CS0618
|
||||
.HasKey(o => new { o.Address, o.PaymentMethodId });
|
||||
.HasKey(o => o.Address);
|
||||
#pragma warning restore CS0618
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using BTCPayServer.App.BackupStorage;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
@ -29,6 +30,9 @@ namespace BTCPayServer.Data
|
||||
|
||||
public List<IdentityUserRole<string>> UserRoles { get; set; }
|
||||
|
||||
public List<AppStorageItemData> AppStorageItems { get; set; }
|
||||
|
||||
|
||||
public static void OnModelCreating(ModelBuilder builder, DatabaseFacade databaseFacade)
|
||||
{
|
||||
builder.Entity<ApplicationUser>()
|
||||
@ -46,6 +50,5 @@ namespace BTCPayServer.Data
|
||||
public bool ShowInvoiceStatusChangeHint { get; set; }
|
||||
public string ImageUrl { get; set; }
|
||||
public string Name { get; set; }
|
||||
public string InvitationToken { get; set; }
|
||||
}
|
||||
}
|
||||
|
@ -15,13 +15,36 @@ using Microsoft.EntityFrameworkCore.Diagnostics;
|
||||
using BTCPayServer.Migrations;
|
||||
using Newtonsoft.Json.Serialization;
|
||||
using Microsoft.AspNetCore.Mvc.ModelBinding.Binders;
|
||||
using System.Threading.Tasks;
|
||||
using System.Threading;
|
||||
|
||||
namespace BTCPayServer.Data
|
||||
{
|
||||
public partial class InvoiceData : MigrationInterceptor.IHasMigration
|
||||
public partial class InvoiceData
|
||||
{
|
||||
/// <summary>
|
||||
/// We have a migration running in the background that will migrate the data from the old blob to the new blob
|
||||
/// Meanwhile, we need to make sure that invoices which haven't been migrated yet are migrated on the fly.
|
||||
/// </summary>
|
||||
public class MigrationInterceptor : IMaterializationInterceptor
|
||||
{
|
||||
public static readonly MigrationInterceptor Instance = new MigrationInterceptor();
|
||||
public object InitializedInstance(MaterializationInterceptionData materializationData, object entity)
|
||||
{
|
||||
if (entity is InvoiceData invoiceData && invoiceData.Currency is null)
|
||||
{
|
||||
invoiceData.Migrate();
|
||||
}
|
||||
else if (entity is PaymentData paymentData && paymentData.Currency is null)
|
||||
{
|
||||
paymentData.Migrate();
|
||||
}
|
||||
else if (entity is PayoutData payoutData && payoutData.Currency is null)
|
||||
{
|
||||
payoutData.Migrate();
|
||||
}
|
||||
return entity;
|
||||
}
|
||||
}
|
||||
|
||||
static HashSet<string> superflousProperties = new HashSet<string>()
|
||||
{
|
||||
"availableAddressHashes",
|
||||
@ -55,14 +78,13 @@ namespace BTCPayServer.Data
|
||||
};
|
||||
|
||||
#pragma warning disable CS0618 // Type or member is obsolete
|
||||
public bool TryMigrate()
|
||||
public void Migrate()
|
||||
{
|
||||
if (Currency is not null)
|
||||
return false;
|
||||
return;
|
||||
if (Blob is not (null or { Length: 0 }))
|
||||
{
|
||||
Blob2 = MigrationExtensions.Unzip(Blob);
|
||||
Blob2 = MigrationExtensions.SanitizeJSON(Blob2);
|
||||
Blob = null;
|
||||
}
|
||||
var blob = JObject.Parse(Blob2);
|
||||
@ -210,10 +232,11 @@ namespace BTCPayServer.Data
|
||||
}
|
||||
|
||||
blob.ConvertNumberToString("price");
|
||||
Currency = blob["currency"].Value<string>().ToUpperInvariant();
|
||||
Currency = blob["currency"].Value<string>();
|
||||
var isTopup = blob["type"]?.Value<string>() is "TopUp";
|
||||
var amount = decimal.Parse(blob["price"].Value<string>(), CultureInfo.InvariantCulture);
|
||||
Amount = isTopup && amount == 0 ? null : decimal.Parse(blob["price"].Value<string>(), CultureInfo.InvariantCulture);
|
||||
CustomerEmail = null;
|
||||
foreach (var prop in superflousProperties)
|
||||
blob.Property(prop)?.Remove();
|
||||
if (blob["speedPolicy"] is JValue { Type: JTokenType.Integer, Value: 0 or 0L })
|
||||
@ -350,11 +373,7 @@ namespace BTCPayServer.Data
|
||||
};
|
||||
blob["version"] = 3;
|
||||
Blob2 = blob.ToString(Formatting.None);
|
||||
return true;
|
||||
}
|
||||
|
||||
[NotMapped]
|
||||
public bool Migrated { get; set; }
|
||||
static string[] detailsRemoveDefault =
|
||||
[
|
||||
"paymentMethodFeeRate",
|
||||
|
@ -3,8 +3,6 @@ using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
|
||||
namespace BTCPayServer.Data
|
||||
{
|
||||
@ -22,17 +20,18 @@ namespace BTCPayServer.Data
|
||||
[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; }
|
||||
public string ExceptionStatus { get; set; }
|
||||
[Obsolete("Unused")]
|
||||
public string CustomerEmail { get; set; }
|
||||
public List<AddressInvoiceData> AddressInvoices { get; set; }
|
||||
public bool Archived { get; set; }
|
||||
public List<PendingInvoiceData> PendingInvoices { get; set; }
|
||||
public List<InvoiceSearchData> InvoiceSearchData { get; set; }
|
||||
public List<RefundData> Refunds { get; set; }
|
||||
|
||||
public static string GetOrderId(string blob) => throw new NotSupportedException();
|
||||
public static string GetItemCode(string blob) => throw new NotSupportedException();
|
||||
public static bool IsPending(string status) => throw new NotSupportedException();
|
||||
|
||||
[Timestamp]
|
||||
// With this, update of InvoiceData will fail if the row was modified by another process
|
||||
public uint XMin { get; set; }
|
||||
@ -42,6 +41,7 @@ namespace BTCPayServer.Data
|
||||
.HasOne(o => o.StoreData)
|
||||
.WithMany(a => a.Invoices).OnDelete(DeleteBehavior.Cascade);
|
||||
builder.Entity<InvoiceData>().HasIndex(o => o.StoreDataId);
|
||||
builder.Entity<InvoiceData>().HasIndex(o => o.OrderId);
|
||||
builder.Entity<InvoiceData>().HasIndex(o => o.Created);
|
||||
builder.Entity<InvoiceData>()
|
||||
.Property(o => o.Blob2)
|
||||
@ -49,9 +49,6 @@ namespace BTCPayServer.Data
|
||||
builder.Entity<InvoiceData>()
|
||||
.Property(o => o.Amount)
|
||||
.HasColumnType("NUMERIC");
|
||||
builder.HasDbFunction(typeof(InvoiceData).GetMethod(nameof(GetOrderId), new[] { typeof(string) }), b => b.HasName("get_orderid"));
|
||||
builder.HasDbFunction(typeof(InvoiceData).GetMethod(nameof(GetItemCode), new[] { typeof(string) }), b => b.HasName("get_itemcode"));
|
||||
builder.HasDbFunction(typeof(InvoiceData).GetMethod(nameof(IsPending), new[] { typeof(string) }), b => b.HasName("is_pending"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -137,10 +137,9 @@ namespace BTCPayServer.Data
|
||||
{
|
||||
return paymentType switch
|
||||
{
|
||||
"BTCLike" or "MoneroLike" or "ZcashLike" => $"{cryptoCode}-CHAIN",
|
||||
"BTCLike" => $"{cryptoCode}-CHAIN",
|
||||
"LightningLike" or "LightningNetwork" => $"{cryptoCode}-LN",
|
||||
"LNURLPAY" => $"{cryptoCode}-LNURL",
|
||||
|
||||
_ => throw new NotSupportedException("Unknown payment type " + paymentType)
|
||||
};
|
||||
}
|
||||
@ -148,25 +147,5 @@ namespace BTCPayServer.Data
|
||||
return $"{splitted[0]}-CHAIN";
|
||||
throw new NotSupportedException("Unknown payment id " + paymentMethodId);
|
||||
}
|
||||
public static string TryMigratePaymentMethodId(string paymentMethodId)
|
||||
{
|
||||
var splitted = paymentMethodId.Split(new[] { '_', '-' });
|
||||
if (splitted is [var cryptoCode, var paymentType])
|
||||
{
|
||||
return paymentType switch
|
||||
{
|
||||
"BTCLike" or "MoneroLike" or "ZcashLike" => $"{cryptoCode}-CHAIN",
|
||||
"LightningLike" or "LightningNetwork" => $"{cryptoCode}-LN",
|
||||
"LNURLPAY" => $"{cryptoCode}-LNURL",
|
||||
_ => paymentMethodId
|
||||
};
|
||||
}
|
||||
if (splitted.Length == 1)
|
||||
return $"{splitted[0]}-CHAIN";
|
||||
return paymentMethodId;
|
||||
}
|
||||
|
||||
// Make postgres happy
|
||||
public static string SanitizeJSON(string json) => json.Replace("\\u0000", string.Empty, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
}
|
||||
|
@ -1,45 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.EntityFrameworkCore.Diagnostics;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace BTCPayServer.Data
|
||||
{
|
||||
/// <summary>
|
||||
/// We have a migration running in the background that will migrate the data from the old blob to the new blob
|
||||
/// Meanwhile, we need to make sure that invoices which haven't been migrated yet are migrated on the fly.
|
||||
/// </summary>
|
||||
public class MigrationInterceptor : IMaterializationInterceptor, ISaveChangesInterceptor
|
||||
{
|
||||
public interface IHasMigration
|
||||
{
|
||||
bool TryMigrate();
|
||||
bool Migrated { get; set; }
|
||||
}
|
||||
public static readonly MigrationInterceptor Instance = new MigrationInterceptor();
|
||||
public object InitializedInstance(MaterializationInterceptionData materializationData, object entity)
|
||||
{
|
||||
if (entity is IHasMigration hasMigration && hasMigration.TryMigrate())
|
||||
{
|
||||
hasMigration.Migrated = true;
|
||||
}
|
||||
return entity;
|
||||
}
|
||||
|
||||
public ValueTask<InterceptionResult<int>> SavingChangesAsync(DbContextEventData eventData, InterceptionResult<int> result, CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
|
||||
foreach (var entry in eventData.Context.ChangeTracker.Entries())
|
||||
{
|
||||
if (entry is { Entity: IHasMigration { Migrated: true }, State: EntityState.Modified })
|
||||
// It seems doing nothing, but this actually set all properties as modified
|
||||
entry.State = EntityState.Modified;
|
||||
}
|
||||
return new ValueTask<InterceptionResult<int>>(result);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,13 +1,10 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.Linq;
|
||||
using System.Reflection.Metadata;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.ChangeTracking.Internal;
|
||||
using NBitcoin;
|
||||
using NBitcoin.Altcoins;
|
||||
using NBitcoin.DataEncoders;
|
||||
@ -16,17 +13,16 @@ using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace BTCPayServer.Data
|
||||
{
|
||||
public partial class PaymentData : MigrationInterceptor.IHasMigration
|
||||
public partial class PaymentData
|
||||
{
|
||||
public bool TryMigrate()
|
||||
public void Migrate()
|
||||
{
|
||||
#pragma warning disable CS0618 // Type or member is obsolete
|
||||
if (Currency is not null)
|
||||
return false;
|
||||
return;
|
||||
if (Blob is not (null or { Length: 0 }))
|
||||
{
|
||||
Blob2 = MigrationExtensions.Unzip(Blob);
|
||||
Blob2 = MigrationExtensions.SanitizeJSON(Blob2);
|
||||
Blob = null;
|
||||
}
|
||||
var blob = JObject.Parse(Blob2);
|
||||
@ -46,10 +42,9 @@ namespace BTCPayServer.Data
|
||||
}
|
||||
|
||||
var cryptoCode = blob["cryptoCode"].Value<string>();
|
||||
MigratedPaymentMethodId = PaymentMethodId;
|
||||
PaymentMethodId = cryptoCode + "_" + blob["cryptoPaymentDataType"].Value<string>();
|
||||
PaymentMethodId = MigrationExtensions.MigratePaymentMethodId(PaymentMethodId);
|
||||
var divisibility = MigrationExtensions.GetDivisibility(PaymentMethodId);
|
||||
Type = cryptoCode + "_" + blob["cryptoPaymentDataType"].Value<string>();
|
||||
Type = MigrationExtensions.MigratePaymentMethodId(Type);
|
||||
var divisibility = MigrationExtensions.GetDivisibility(Type);
|
||||
Currency = blob["cryptoCode"].Value<string>();
|
||||
blob.Remove("cryptoCode");
|
||||
blob.Remove("cryptoPaymentDataType");
|
||||
@ -92,7 +87,7 @@ namespace BTCPayServer.Data
|
||||
blob.Remove("output");
|
||||
blob.Remove("outpoint");
|
||||
// Convert from sats to btc
|
||||
if (cryptoData["value"] is not (null or { Type: JTokenType.Null } or { Type: JTokenType.Object }))
|
||||
if (cryptoData["value"] is not (null or { Type: JTokenType.Null }))
|
||||
{
|
||||
var v = cryptoData["value"].Value<long>();
|
||||
Amount = (decimal)v / (decimal)Money.COIN;
|
||||
@ -103,22 +98,7 @@ namespace BTCPayServer.Data
|
||||
blob.ConvertNumberToString("paymentMethodFee");
|
||||
blob.Remove("networkFee");
|
||||
blob.RemoveIfNull("paymentMethodFee");
|
||||
}
|
||||
// Liquid
|
||||
else if (cryptoData["value"] is { Type: JTokenType.Object })
|
||||
{
|
||||
var v = cryptoData["value"]["value"].Value<long>();
|
||||
var assetId = cryptoData["value"]["assetId"].Value<string>();
|
||||
divisibility = GetDivisibility(assetId) ?? 8;
|
||||
Amount = (decimal)v / (decimal)Math.Pow(10.0, divisibility);
|
||||
cryptoData.Remove("value");
|
||||
cryptoData["assetId"] = assetId;
|
||||
blob["paymentMethodFee"] = blob["networkFee"];
|
||||
blob.RemoveIfValue<decimal>("paymentMethodFee", 0.0m);
|
||||
blob.ConvertNumberToString("paymentMethodFee");
|
||||
blob.Remove("networkFee");
|
||||
blob.RemoveIfNull("paymentMethodFee");
|
||||
}
|
||||
}
|
||||
// Convert from millisats to btc
|
||||
else if (cryptoData["amount"] is not (null or { Type: JTokenType.Null }))
|
||||
{
|
||||
@ -177,25 +157,8 @@ namespace BTCPayServer.Data
|
||||
Blob2 = blob.ToString(Formatting.None);
|
||||
Accounted = null;
|
||||
#pragma warning restore CS0618 // Type or member is obsolete
|
||||
return true;
|
||||
}
|
||||
|
||||
private int? GetDivisibility(string assetId) =>
|
||||
assetId switch
|
||||
{
|
||||
"ce091c998b83c78bb71a632313ba3760f1763d9cfcffae02258ffa9865a37bd2" => 8,
|
||||
"aa775044c32a7df391902b3659f46dfe004ccb2644ce2ddc7dba31e889391caf" => 2,
|
||||
"0e99c1a6da379d1f4151fb9df90449d40d0608f6cb33a5bcbfc8c265f42bab0a" => 8,
|
||||
"6f0279e9ed041c3d710a9f57d0c02928416460c4b722ae3457a11eec381c526d" => 8,
|
||||
_ => null,
|
||||
};
|
||||
|
||||
[NotMapped]
|
||||
public bool Migrated { get; set; }
|
||||
[NotMapped]
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public string MigratedPaymentMethodId { get; set; }
|
||||
|
||||
static readonly DateTimeOffset unixRef = new DateTimeOffset(1970, 1, 1, 0, 0, 0, TimeSpan.Zero);
|
||||
public static long DateTimeToMilliUnixTime(in DateTime time)
|
||||
{
|
||||
|
@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
|
||||
@ -27,15 +26,13 @@ namespace BTCPayServer.Data
|
||||
[Obsolete("Use Blob2 instead")]
|
||||
public byte[] Blob { get; set; }
|
||||
public string Blob2 { get; set; }
|
||||
public string PaymentMethodId { get; set; }
|
||||
public string Type { get; set; }
|
||||
[Obsolete("Use Status instead")]
|
||||
public bool? Accounted { get; set; }
|
||||
public PaymentStatus? Status { get; set; }
|
||||
public static bool IsPending(PaymentStatus? status) => throw new NotSupportedException();
|
||||
internal static void OnModelCreating(ModelBuilder builder)
|
||||
|
||||
internal static void OnModelCreating(ModelBuilder builder, DatabaseFacade databaseFacade)
|
||||
{
|
||||
builder.Entity<PaymentData>()
|
||||
.HasKey(o => new { o.Id, o.PaymentMethodId });
|
||||
builder.Entity<PaymentData>()
|
||||
.HasOne(o => o.InvoiceData)
|
||||
.WithMany(i => i.Payments).OnDelete(DeleteBehavior.Cascade);
|
||||
@ -50,7 +47,6 @@ namespace BTCPayServer.Data
|
||||
builder.Entity<PaymentData>()
|
||||
.Property(o => o.Amount)
|
||||
.HasColumnType("NUMERIC");
|
||||
builder.HasDbFunction(typeof(PaymentData).GetMethod(nameof(IsPending), new[] { typeof(PaymentStatus?) }), b => b.HasName("is_pending"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,39 +0,0 @@
|
||||
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
|
||||
{
|
||||
public partial class PaymentRequestData : IHasBlobUntyped
|
||||
public class PaymentRequestData : IHasBlobUntyped
|
||||
{
|
||||
public string Id { get; set; }
|
||||
public DateTimeOffset Created { get; set; }
|
||||
|
18
BTCPayServer.Data/Data/PayoutData.Migration.cs
Normal file
18
BTCPayServer.Data/Data/PayoutData.Migration.cs
Normal file
@ -0,0 +1,18 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BTCPayServer.Data
|
||||
{
|
||||
public partial class PayoutData
|
||||
{
|
||||
public void Migrate()
|
||||
{
|
||||
PayoutMethodId = MigrationExtensions.MigratePaymentMethodId(PayoutMethodId);
|
||||
// Could only be BTC-LN or BTC-CHAIN, so we extract the crypto currency
|
||||
Currency = PayoutMethodId.Split('-')[0];
|
||||
}
|
||||
}
|
||||
}
|
@ -1,9 +1,11 @@
|
||||
using System;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.Text;
|
||||
using BTCPayServer.Client.Models;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
using NBitcoin;
|
||||
|
||||
namespace BTCPayServer.Data
|
||||
@ -16,23 +18,7 @@ namespace BTCPayServer.Data
|
||||
public DateTimeOffset Date { get; set; }
|
||||
public string PullPaymentDataId { get; set; }
|
||||
public string StoreDataId { get; set; }
|
||||
/// <summary>
|
||||
/// The currency of the payout (eg. BTC)
|
||||
/// </summary>
|
||||
public string Currency { get; set; }
|
||||
/// <summary>
|
||||
/// The amount of the payout in Currency.
|
||||
/// The Amount only get set when the payout is actually approved.
|
||||
/// </summary>
|
||||
public decimal? Amount { get; set; }
|
||||
/// <summary>
|
||||
/// The original currency of the payout (eg. USD)
|
||||
/// </summary>
|
||||
public string OriginalCurrency { get; set; }
|
||||
/// <summary>
|
||||
/// The amount of the payout in OriginalCurrency
|
||||
/// </summary>
|
||||
public decimal OriginalAmount { get; set; }
|
||||
public PullPaymentData PullPaymentData { get; set; }
|
||||
[MaxLength(20)]
|
||||
public PayoutState State { get; set; }
|
||||
@ -42,14 +28,7 @@ namespace BTCPayServer.Data
|
||||
public string Blob { get; set; }
|
||||
public string Proof { get; set; }
|
||||
#nullable enable
|
||||
/// <summary>
|
||||
/// For example, BTC-CHAIN needs to ensure that only a single address is tied to an active payout.
|
||||
/// If `PayoutBlob.Destination` is `bitcoin://1BvBMSeYstWetqTFn5Au4m4GFg7xJaNVN2?amount=0.1`
|
||||
/// Then `DedupId` is `1BvBMSeYstWetqTFn5Au4m4GFg7xJaNVN2`
|
||||
/// For Lightning, Destination could be the lightning address, BOLT11 or LNURL
|
||||
/// But the `DedupId` would be the `PaymentHash`.
|
||||
/// </summary>
|
||||
public string? DedupId { get; set; }
|
||||
public string? Destination { get; set; }
|
||||
#nullable restore
|
||||
public StoreData StoreData { get; set; }
|
||||
|
||||
@ -67,11 +46,11 @@ namespace BTCPayServer.Data
|
||||
builder.Entity<PayoutData>()
|
||||
.HasIndex(o => o.State);
|
||||
builder.Entity<PayoutData>()
|
||||
.HasIndex(x => new { DestinationId = x.DedupId, x.State });
|
||||
.HasIndex(x => new { DestinationId = x.Destination, x.State });
|
||||
|
||||
builder.Entity<PayoutData>()
|
||||
.Property(o => o.Blob)
|
||||
.HasColumnType("jsonb");
|
||||
.HasColumnType("JSONB");
|
||||
builder.Entity<PayoutData>()
|
||||
.Property(o => o.Proof)
|
||||
.HasColumnType("JSONB");
|
||||
|
@ -16,7 +16,7 @@ public class PayoutProcessorData : IHasBlobUntyped
|
||||
public string Id { get; set; }
|
||||
public string StoreId { get; set; }
|
||||
public StoreData Store { get; set; }
|
||||
public string PayoutMethodId { get; set; }
|
||||
public string PaymentMethod { get; set; }
|
||||
public string Processor { get; set; }
|
||||
|
||||
[Obsolete("Use Blob2 instead")]
|
||||
@ -36,6 +36,6 @@ public class PayoutProcessorData : IHasBlobUntyped
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"{Processor} {PayoutMethodId} {StoreId}";
|
||||
return $"{Processor} {PaymentMethod} {StoreId}";
|
||||
}
|
||||
}
|
||||
|
18
BTCPayServer.Data/Data/PendingInvoiceData.cs
Normal file
18
BTCPayServer.Data/Data/PendingInvoiceData.cs
Normal file
@ -0,0 +1,18 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace BTCPayServer.Data
|
||||
{
|
||||
public class PendingInvoiceData
|
||||
{
|
||||
public string Id { get; set; }
|
||||
public InvoiceData InvoiceData { get; set; }
|
||||
|
||||
internal static void OnModelCreating(ModelBuilder builder)
|
||||
{
|
||||
builder.Entity<PendingInvoiceData>()
|
||||
.HasOne(o => o.InvoiceData)
|
||||
.WithMany(o => o.PendingInvoices)
|
||||
.HasForeignKey(o => o.Id).OnDelete(DeleteBehavior.Cascade);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,63 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
|
||||
namespace BTCPayServer.Data;
|
||||
|
||||
public class PendingTransaction: IHasBlob<PendingTransactionBlob>
|
||||
{
|
||||
public string TransactionId { get; set; }
|
||||
public string CryptoCode { get; set; }
|
||||
public string StoreId { get; set; }
|
||||
public StoreData Store { get; set; }
|
||||
public DateTimeOffset? Expiry { get; set; }
|
||||
public PendingTransactionState State { get; set; }
|
||||
public string[] OutpointsUsed { get; set; }
|
||||
|
||||
[NotMapped][Obsolete("Use Blob2 instead")]
|
||||
public byte[] Blob { get; set; }
|
||||
|
||||
public string Blob2 { get; set; }
|
||||
|
||||
|
||||
internal static void OnModelCreating(ModelBuilder builder, DatabaseFacade databaseFacade)
|
||||
{
|
||||
builder.Entity<PendingTransaction>()
|
||||
.HasOne(o => o.Store)
|
||||
.WithMany(i => i.PendingTransactions)
|
||||
.HasForeignKey(i => i.StoreId)
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
builder.Entity<PendingTransaction>().HasKey(transaction => new {transaction.CryptoCode, transaction.TransactionId});
|
||||
|
||||
builder.Entity<PendingTransaction>()
|
||||
.Property(o => o.Blob2)
|
||||
.HasColumnType("JSONB");
|
||||
builder.Entity<PendingTransaction>()
|
||||
.Property(o => o.OutpointsUsed)
|
||||
.HasColumnType("text[]");
|
||||
}
|
||||
}
|
||||
public enum PendingTransactionState
|
||||
{
|
||||
Pending,
|
||||
Cancelled,
|
||||
Expired,
|
||||
Invalidated,
|
||||
Signed,
|
||||
Broadcast
|
||||
}
|
||||
|
||||
public class PendingTransactionBlob
|
||||
{
|
||||
public string PSBT { get; set; }
|
||||
public List<CollectedSignature> CollectedSignatures { get; set; } = new();
|
||||
}
|
||||
|
||||
public class CollectedSignature
|
||||
{
|
||||
public DateTimeOffset Timestamp { get; set; }
|
||||
public string ReceivedPSBT { get; set; }
|
||||
}
|
@ -24,8 +24,6 @@ namespace BTCPayServer.Data
|
||||
public StoreData StoreData { get; set; }
|
||||
[MaxLength(50)]
|
||||
public string StoreId { get; set; }
|
||||
public string Currency { get; set; }
|
||||
public decimal Limit { get; set; }
|
||||
public DateTimeOffset StartDate { get; set; }
|
||||
public DateTimeOffset? EndDate { get; set; }
|
||||
public bool Archived { get; set; }
|
||||
|
@ -49,7 +49,6 @@ namespace BTCPayServer.Data
|
||||
public IEnumerable<FormData> Forms { get; set; }
|
||||
public IEnumerable<StoreRole> StoreRoles { get; set; }
|
||||
public bool Archived { get; set; }
|
||||
public IEnumerable<PendingTransaction> PendingTransactions { get; set; }
|
||||
|
||||
internal static void OnModelCreating(ModelBuilder builder, DatabaseFacade databaseFacade)
|
||||
{
|
||||
|
@ -0,0 +1,30 @@
|
||||
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("20240405052858_cleanup_address_invoices")]
|
||||
public partial class cleanup_address_invoices : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.Sql(@"
|
||||
DELETE FROM ""AddressInvoices"" WHERE ""Address"" LIKE '%_LightningLike';
|
||||
ALTER TABLE ""AddressInvoices"" DROP COLUMN IF EXISTS ""CreatedTime"";
|
||||
");
|
||||
migrationBuilder.Sql(@"VACUUM (FULL, ANALYZE) ""AddressInvoices"";", true);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
using BTCPayServer.Data;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace BTCPayServer.Migrations
|
||||
{
|
||||
[DbContext(typeof(ApplicationDbContext))]
|
||||
[Migration("20240520042729_payoutsmigration")]
|
||||
public partial class payoutsmigration : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "Currency",
|
||||
table: "Payouts",
|
||||
type: "text",
|
||||
nullable: true);
|
||||
migrationBuilder.RenameColumn("PaymentMethodId", "Payouts", "PayoutMethodId");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
1679
BTCPayServer.Data/Migrations/20240726113051_AppStuff.Designer.cs
generated
Normal file
1679
BTCPayServer.Data/Migrations/20240726113051_AppStuff.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
56
BTCPayServer.Data/Migrations/20240726113051_AppStuff.cs
Normal file
56
BTCPayServer.Data/Migrations/20240726113051_AppStuff.cs
Normal file
@ -0,0 +1,56 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace BTCPayServer.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class AppStuff : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.CreateTable(
|
||||
name: "AppStorageItems",
|
||||
columns: table => new
|
||||
{
|
||||
Key = table.Column<string>(type: "text", nullable: false),
|
||||
Version = table.Column<long>(type: "bigint", nullable: false),
|
||||
UserId = table.Column<string>(type: "text", nullable: false),
|
||||
Value = table.Column<byte[]>(type: "bytea", nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_AppStorageItems", x => new { x.Key, x.Version, x.UserId });
|
||||
table.ForeignKey(
|
||||
name: "FK_AppStorageItems_AspNetUsers_UserId",
|
||||
column: x => x.UserId,
|
||||
principalTable: "AspNetUsers",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_AppStorageItems_Key_UserId",
|
||||
table: "AppStorageItems",
|
||||
columns: new[] { "Key", "UserId" },
|
||||
unique: true);
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_AppStorageItems_UserId",
|
||||
table: "AppStorageItems",
|
||||
column: "UserId");
|
||||
|
||||
migrationBuilder.Sql("CREATE FUNCTION \"LC_TRIGGER_BEFORE_INSERT_APPSTORAGEITEMDATA\"() RETURNS trigger as $LC_TRIGGER_BEFORE_INSERT_APPSTORAGEITEMDATA$\r\nBEGIN\r\n DELETE FROM \"AppStorageItems\"\r\n WHERE NEW.\"UserId\" = \"AppStorageItems\".\"UserId\" AND NEW.\"Key\" = \"AppStorageItems\".\"Key\" AND NEW.\"Version\" > \"AppStorageItems\".\"Version\";\r\nRETURN NEW;\r\nEND;\r\n$LC_TRIGGER_BEFORE_INSERT_APPSTORAGEITEMDATA$ LANGUAGE plpgsql;\r\nCREATE TRIGGER LC_TRIGGER_BEFORE_INSERT_APPSTORAGEITEMDATA BEFORE INSERT\r\nON \"AppStorageItems\"\r\nFOR EACH ROW EXECUTE PROCEDURE \"LC_TRIGGER_BEFORE_INSERT_APPSTORAGEITEMDATA\"();");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.Sql("DROP FUNCTION \"LC_TRIGGER_BEFORE_INSERT_APPSTORAGEITEMDATA\"() CASCADE;");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "AppStorageItems");
|
||||
}
|
||||
}
|
||||
}
|
@ -1,35 +0,0 @@
|
||||
using BTCPayServer.Data;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace BTCPayServer.Migrations
|
||||
{
|
||||
[DbContext(typeof(ApplicationDbContext))]
|
||||
[Migration("20240826065950_removeinvoicecols")]
|
||||
[DBScript("001.InvoiceFunctions.sql")]
|
||||
public partial class removeinvoicecols : DBScriptsMigration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropIndex(
|
||||
name: "IX_Invoices_OrderId",
|
||||
table: "Invoices");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "ItemCode",
|
||||
table: "Invoices");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "OrderId",
|
||||
table: "Invoices");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "CustomerEmail",
|
||||
table: "Invoices");
|
||||
base.Up(migrationBuilder);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,40 +0,0 @@
|
||||
using BTCPayServer.Data;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace BTCPayServer.Migrations
|
||||
{
|
||||
[DbContext(typeof(ApplicationDbContext))]
|
||||
[Migration("20240827034505_migratepayouts")]
|
||||
[DBScript("002.RefactorPayouts.sql")]
|
||||
public partial class migratepayouts : DBScriptsMigration
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
base.Up(migrationBuilder);
|
||||
migrationBuilder.RenameColumn(
|
||||
name: "Destination",
|
||||
table: "Payouts",
|
||||
newName: "DedupId");
|
||||
migrationBuilder.RenameIndex(
|
||||
name: "IX_Payouts_Destination_State",
|
||||
table: "Payouts",
|
||||
newName: "IX_Payouts_DedupId_State");
|
||||
migrationBuilder.RenameColumn(
|
||||
name: "PaymentMethod",
|
||||
table: "PayoutProcessors",
|
||||
newName: "PayoutMethodId");
|
||||
|
||||
migrationBuilder.Sql("""
|
||||
UPDATE "PayoutProcessors"
|
||||
SET
|
||||
"PayoutMethodId" = CASE WHEN STRPOS("PayoutMethodId", '_') = 0 THEN "PayoutMethodId" || '-CHAIN'
|
||||
WHEN STRPOS("PayoutMethodId", '_LightningLike') > 0 THEN split_part("PayoutMethodId", '_LightningLike', 1) || '-LN'
|
||||
WHEN STRPOS("PayoutMethodId", '_LNURLPAY') > 0 THEN split_part("PayoutMethodId",'_LNURLPAY', 1) || '-LN'
|
||||
ELSE "PayoutMethodId" END
|
||||
""");
|
||||
}
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user