Compare commits

..

208 Commits

Author SHA1 Message Date
23aed49a79 support more ln methods 2024-08-05 11:01:24 +02:00
8ddb6d4b6f add grpc to btcpay 2024-08-05 10:22:56 +02:00
114479321e Try to fix MAUI build 2024-08-01 18:17:49 +02:00
1e5a783e7f notidy devices on master 2024-08-01 10:07:24 +02:00
035b91bec2 logs for vss 2024-08-01 09:31:23 +02:00
0993f788a1 Notify about user changes 2024-07-30 23:48:48 +02:00
b27afb9eed Add users to store group on store creation 2024-07-30 16:55:26 +02:00
7bdb136c27 switch to a long for device identifier 2024-07-30 15:56:45 +02:00
c0ad32eaf7 refactor locker 2024-07-30 14:53:59 +02:00
f61592cb35 Register first user as admin 2024-07-29 16:44:13 +02:00
0df173b415 add to group 2024-07-29 13:37:14 +02:00
a6c01f4658 fix protobuf 2024-07-26 15:42:34 +02:00
5ea1af44d3 update migration 2024-07-26 14:00:28 +02:00
3821795ec5 Merge remote-tracking branch 'origin/mobile-working-branch' into mobile-working-branch
# Conflicts:
#	BTCPayApp.CommonServer/IBTCPayAppHubClient.cs
#	BTCPayApp.CommonServer/Models/AppUserInfo.cs
#	BTCPayServer/App/BTCPayAppHub.cs
#	BTCPayServer/App/BTCPayAppState.cs
#	BTCPayServer/BTCPayServer.csproj
2024-07-26 08:47:06 +02:00
5b7dafe142 Simplify server events 2024-07-25 18:59:15 +02:00
e1888a038c Fix server event communication 2024-07-25 18:59:13 +02:00
e3afd3f933 Cleanups 2024-07-25 18:59:11 +02:00
055276ead9 Fix build and test 2024-07-25 18:59:09 +02:00
fbdeec84e3 Add store logo 2024-07-25 18:59:08 +02:00
04676de783 Try to add server events 2024-07-25 18:59:06 +02:00
766d3daf0d Updates after merges 2024-07-25 18:59:04 +02:00
9480eff096 Add user profile info 2024-07-25 18:59:02 +02:00
cb748e0897 btcpay to user app events 2024-07-25 18:59:00 +02:00
90feb1810f add usings 2024-07-25 18:58:58 +02:00
a05212923b add additional info 2024-07-25 18:58:56 +02:00
a6293d21c2 Immediate login on signup if possible 2024-07-25 18:58:54 +02:00
581307c334 Remove app tab on LN setup page 2024-07-25 18:58:53 +02:00
5b2e633589 Extract POSDataParser 2024-07-25 18:58:51 +02:00
f56dc8c6ae Support invite link in app 2024-07-25 18:58:49 +02:00
dd99a7b32d POS fix 2024-07-25 18:58:47 +02:00
6bc5c12051 Add login code support for the app 2024-07-25 18:58:45 +02:00
048d0c445f Add default currency to store data 2024-07-25 18:58:43 +02:00
0a50f7dba7 start ln listener immediately to app nodes 2024-07-25 18:58:41 +02:00
3218db5815 return lock 2024-07-25 18:58:40 +02:00
5ca19879b6 Add user profile info 2024-07-25 18:58:38 +02:00
13a7e9be0a add logs 2024-07-25 18:58:36 +02:00
c95a2552d0 Associate keypad POS with store 2024-07-25 18:58:34 +02:00
78a31b74c7 mak e regtest send a hacked but correct node info to app 2024-07-25 18:58:32 +02:00
8450d882f9 Add create store data 2024-07-25 18:58:30 +02:00
19f33f830c Move app models 2024-07-25 18:58:28 +02:00
e6fc7f1307 Split API controller 2024-07-25 18:58:26 +02:00
b0e3abe61f impl pay invoice 2024-07-25 18:58:25 +02:00
e1b2bc1a05 get onchain txs 2024-07-25 18:58:23 +02:00
8c0d1fde45 fix tx resp format 2024-07-25 18:58:21 +02:00
6516ed3586 Parse permissions from claims 2024-07-25 18:58:18 +02:00
4e8975a539 Use original IP and port mappings 2024-07-25 18:58:12 +02:00
66e8b1211b Move Bearer to Greenfield 2024-07-25 18:58:07 +02:00
e42b59bec6 fix compose 2024-07-25 18:58:00 +02:00
452f2be6c8 tell apps the internal node to connect to 2024-07-25 18:57:55 +02:00
a38553da29 expose local ip through nodes 2024-07-25 18:57:52 +02:00
1a28f790fc use clas 2024-07-25 18:57:50 +02:00
afa3c46ce3 Resolve logo and CSS URLs 2024-07-25 18:57:48 +02:00
8224c84556 Fix after update 2024-07-25 18:57:46 +02:00
b619688d80 expand tx update notif 2024-07-25 18:57:45 +02:00
106b4442a0 expose cln nodes to localhost for ldk peer connections 2024-07-25 18:57:43 +02:00
fc98457add update and have working invoice gen 2024-07-25 18:57:41 +02:00
1ec5917518 start connecting LN to btcpay 2024-07-25 18:57:39 +02:00
ab0b067916 btcpay ln conn string 2024-07-25 18:57:37 +02:00
35645278a2 fix bh 2024-07-25 18:57:35 +02:00
cc20a0ee95 wip 2024-07-25 18:57:33 +02:00
0c0c2be67b Unset default server name 2024-07-25 18:57:32 +02:00
c6b69babc2 Add nullable indicators 2024-07-25 18:57:30 +02:00
696d6a823d Support registration 2024-07-25 18:57:28 +02:00
cf47e2a1b3 Refactor AppUserInfo 2024-07-25 18:57:26 +02:00
d5faa2c8b7 add common classes 2024-07-25 18:57:24 +02:00
e9f785e2b0 Update after update 2024-07-25 18:57:22 +02:00
c881c3b7f2 Add Bearer authentication 2024-07-25 18:57:21 +02:00
bdb213dca6 fix event data from block 2024-07-25 18:57:19 +02:00
0291766588 fix hub contract 2024-07-25 18:57:17 +02:00
dabf1d4159 start adding notifications in hub for onchain related acitvity 2024-07-25 18:57:15 +02:00
71f9cb27b6 wip 2024-07-25 18:57:13 +02:00
cdc0a7fb09 fix btcpay app plugin loader 2024-07-25 18:57:11 +02:00
f4cf4a7e4a wip 2024-07-25 18:57:09 +02:00
d8c519d008 add common proj 2024-07-25 18:57:07 +02:00
ed4dea214d seed not xpriv 2024-07-25 18:57:06 +02:00
af95d472fa wip 2024-07-25 18:57:04 +02:00
20c80810f1 wip 2024-07-25 18:57:02 +02:00
ce9d2dc3d2 Merge remote-tracking branch 'origin/master' into mobile-working-branch 2024-07-25 14:51:28 +02:00
fcd365b8f6 backup store 2024-07-25 14:51:15 +02:00
deb9c1e1e1 Merge remote-tracking branch 'origin/master' into mobile-working-branch 2024-07-23 10:24:35 +02:00
2b349bfc8a fixes 2024-07-23 10:24:12 +02:00
49aae758a9 Merge remote-tracking branch 'origin/mobile-working-branch' into mobile-working-branch
# Conflicts:
#	BTCPayApp.CommonServer/IBTCPayAppHubClient.cs
#	BTCPayApp.CommonServer/Models/AppUserInfo.cs
#	BTCPayServer/App/BTCPayAppHub.cs
#	BTCPayServer/App/BTCPayAppState.cs
#	BTCPayServer/App/LN.cs
#	BTCPayServer/Services/Stores/StoreRepository.cs
2024-07-22 12:03:11 +02:00
308882234c wip 2024-07-22 11:56:26 +02:00
0fdaffc677 Simplify server events 2024-07-12 07:56:50 +02:00
8017493ff5 Fix server event communication 2024-07-11 15:58:59 +02:00
d18e8d2eaf Cleanups 2024-07-11 15:58:57 +02:00
49fbadbd29 Fix build and test 2024-07-11 15:58:55 +02:00
64505f65f9 Add store logo 2024-07-11 15:58:53 +02:00
9327b08219 Try to add server events 2024-07-11 15:58:51 +02:00
f893d8b8e2 Updates after merges 2024-07-11 15:58:49 +02:00
dfc70e7482 Add user profile info 2024-07-11 15:58:47 +02:00
e54f0831b8 btcpay to user app events 2024-07-11 15:58:45 +02:00
c3d77c1de0 add usings 2024-07-11 15:58:43 +02:00
59c61e2e3d add additional info 2024-07-11 15:58:41 +02:00
82f78d0cc4 Immediate login on signup if possible 2024-07-11 15:58:39 +02:00
d9290eae8e Remove app tab on LN setup page 2024-07-11 15:58:37 +02:00
7175052a00 Extract POSDataParser 2024-07-11 15:58:35 +02:00
9008e84c98 Support invite link in app 2024-07-11 15:58:33 +02:00
67c70db758 POS fix 2024-07-11 15:58:31 +02:00
d8a244b648 Add login code support for the app 2024-07-11 15:58:29 +02:00
2602846b2f Add default currency to store data 2024-07-11 15:58:27 +02:00
e19bf3a376 start ln listener immediately to app nodes 2024-07-11 15:58:25 +02:00
2a09cbbd07 return lock 2024-07-11 15:58:23 +02:00
60428ddb87 Add user profile info 2024-07-11 15:58:21 +02:00
a2590af4f8 add logs 2024-07-11 15:58:19 +02:00
4641123f08 Associate keypad POS with store 2024-07-11 15:58:17 +02:00
8d9460e1ce mak e regtest send a hacked but correct node info to app 2024-07-11 15:58:15 +02:00
4cc52ee578 Add create store data 2024-07-11 15:58:14 +02:00
a93d794b11 Move app models 2024-07-11 15:58:11 +02:00
90ae127cdb Split API controller 2024-07-11 15:58:09 +02:00
2ffae18d8b impl pay invoice 2024-07-11 15:58:07 +02:00
87d4038fc6 get onchain txs 2024-07-11 15:58:05 +02:00
3838b2abe7 fix tx resp format 2024-07-11 15:58:03 +02:00
a7fa00be9a Parse permissions from claims 2024-07-11 15:58:01 +02:00
bb9143d493 Use original IP and port mappings 2024-07-11 15:58:00 +02:00
aafedd7ccb Move Bearer to Greenfield 2024-07-11 15:57:58 +02:00
f2b62bce8e fix compose 2024-07-11 15:57:56 +02:00
db9f717656 tell apps the internal node to connect to 2024-07-11 15:57:54 +02:00
e1cfd82254 expose local ip through nodes 2024-07-11 15:57:52 +02:00
3ddcf457df use clas 2024-07-11 15:57:50 +02:00
8066d356b0 Resolve logo and CSS URLs 2024-07-11 15:57:48 +02:00
365423e598 Fix after update 2024-07-11 15:57:46 +02:00
5b20aca1f2 expand tx update notif 2024-07-11 15:57:44 +02:00
20c30cf0d1 expose cln nodes to localhost for ldk peer connections 2024-07-11 15:57:42 +02:00
9ed6cb8cf4 update and have working invoice gen 2024-07-11 15:57:40 +02:00
3bb383f0f1 start connecting LN to btcpay 2024-07-11 15:57:38 +02:00
6de334e50a btcpay ln conn string 2024-07-11 15:57:36 +02:00
16159c6a29 fix bh 2024-07-11 15:57:34 +02:00
2acea1ed99 wip 2024-07-11 15:57:32 +02:00
3454bfd213 Unset default server name 2024-07-11 15:57:30 +02:00
b0c25bcbb6 Add nullable indicators 2024-07-11 15:57:28 +02:00
553e560b75 Support registration 2024-07-11 15:57:26 +02:00
1e33229daa Refactor AppUserInfo 2024-07-11 15:57:24 +02:00
16c9c14f6c add common classes 2024-07-11 15:57:22 +02:00
ba56947ca5 Update after update 2024-07-11 15:57:20 +02:00
f5858f3338 Add Bearer authentication 2024-07-11 15:57:18 +02:00
d804fb132c fix event data from block 2024-07-11 15:57:16 +02:00
f276e4ccab fix hub contract 2024-07-11 15:57:14 +02:00
9287cc3732 start adding notifications in hub for onchain related acitvity 2024-07-11 15:57:12 +02:00
5b498416ef wip 2024-07-11 15:57:10 +02:00
7e41166390 fix btcpay app plugin loader 2024-07-11 15:57:08 +02:00
8ae9a8d5d6 wip 2024-07-11 15:57:06 +02:00
6e46651de2 add common proj 2024-07-11 15:57:04 +02:00
df9d6b9a40 seed not xpriv 2024-07-11 15:57:02 +02:00
52770ec758 wip 2024-07-11 15:57:00 +02:00
9087d7b91b wip 2024-07-11 15:56:58 +02:00
63cd54d6fc Fix server event communication 2024-07-10 18:08:37 +02:00
7fc51b1ee0 Cleanups 2024-07-10 18:08:35 +02:00
7622aba453 Fix build and test 2024-07-10 18:08:32 +02:00
61722fa099 Add store logo 2024-07-10 18:08:30 +02:00
61f37368f4 Try to add server events 2024-07-10 18:08:28 +02:00
5196bc4548 Updates after merges 2024-07-10 18:08:26 +02:00
3adb4b3c58 Add user profile info 2024-07-10 18:08:24 +02:00
f37282112c btcpay to user app events 2024-07-10 18:08:22 +02:00
2096b1dbd5 add usings 2024-07-10 18:08:19 +02:00
c5d86f6018 add additional info 2024-07-10 18:08:17 +02:00
d3806a8337 Immediate login on signup if possible 2024-07-10 18:08:15 +02:00
d35429b356 Remove app tab on LN setup page 2024-07-10 18:08:13 +02:00
17dc821c79 Extract POSDataParser 2024-07-10 18:08:11 +02:00
3e86ba91d6 Support invite link in app 2024-07-10 18:08:09 +02:00
b10db9e370 POS fix 2024-07-10 18:08:06 +02:00
955be1f20d Add login code support for the app 2024-07-10 18:08:04 +02:00
c965b27ca0 Add default currency to store data 2024-07-10 18:08:02 +02:00
c3bd4490dd start ln listener immediately to app nodes 2024-07-10 18:08:00 +02:00
7c69bd249d return lock 2024-07-10 18:07:58 +02:00
0ccfdb16eb Add user profile info 2024-07-10 18:07:56 +02:00
6479772571 add logs 2024-07-10 18:07:54 +02:00
6711688734 Associate keypad POS with store 2024-07-10 18:07:52 +02:00
0458ba9373 mak e regtest send a hacked but correct node info to app 2024-07-10 18:07:49 +02:00
e3c973fb61 Add create store data 2024-07-10 18:07:47 +02:00
28f26004c4 Move app models 2024-07-10 18:07:44 +02:00
516132c32b Split API controller 2024-07-10 18:07:42 +02:00
46f0649343 impl pay invoice 2024-07-10 18:07:40 +02:00
2d4c30522d get onchain txs 2024-07-10 18:07:38 +02:00
f207525ba3 fix tx resp format 2024-07-10 18:07:35 +02:00
13bb6eb6d7 Parse permissions from claims 2024-07-10 18:07:33 +02:00
796cd88ccf Use original IP and port mappings 2024-07-10 18:07:30 +02:00
6b14d87d27 Move Bearer to Greenfield 2024-07-10 18:07:28 +02:00
def9c3ce5b fix compose 2024-07-10 18:07:25 +02:00
0ac8e0c517 tell apps the internal node to connect to 2024-07-10 18:07:23 +02:00
eb3a37bd2b expose local ip through nodes 2024-07-10 18:07:21 +02:00
bd559f7bf5 use clas 2024-07-10 18:07:19 +02:00
bcce78c37b Resolve logo and CSS URLs 2024-07-10 18:07:17 +02:00
667bea4589 Fix after update 2024-07-10 18:07:15 +02:00
b9838204b2 expand tx update notif 2024-07-10 18:07:13 +02:00
6a29022335 expose cln nodes to localhost for ldk peer connections 2024-07-10 18:07:10 +02:00
5af47aa3f3 update and have working invoice gen 2024-07-10 18:07:08 +02:00
dc18f97d88 start connecting LN to btcpay 2024-07-10 18:07:06 +02:00
ec38da3c45 btcpay ln conn string 2024-07-10 18:07:04 +02:00
29905ba071 fix bh 2024-07-10 18:07:01 +02:00
e0c57b1691 wip 2024-07-10 18:06:59 +02:00
a9dd25e045 Unset default server name 2024-07-10 18:06:57 +02:00
cd9d9b8f20 Add nullable indicators 2024-07-10 18:06:55 +02:00
5d1413f733 Support registration 2024-07-10 18:06:53 +02:00
395abe0e5c Refactor AppUserInfo 2024-07-10 18:06:51 +02:00
03b68b12e5 add common classes 2024-07-10 18:06:48 +02:00
1a9a742dbe Update after update 2024-07-10 18:06:46 +02:00
ed0938346d Add Bearer authentication 2024-07-10 18:06:44 +02:00
643739514e fix event data from block 2024-07-10 18:06:42 +02:00
63720baa73 fix hub contract 2024-07-10 18:06:40 +02:00
dc8aa1fc13 start adding notifications in hub for onchain related acitvity 2024-07-10 18:06:38 +02:00
a1c86e011a wip 2024-07-10 18:06:35 +02:00
2cbbf4af7e fix btcpay app plugin loader 2024-07-10 18:06:33 +02:00
62d0409b57 wip 2024-07-10 18:06:31 +02:00
f8325ad5a8 add common proj 2024-07-10 18:06:29 +02:00
35371ee0a4 seed not xpriv 2024-07-10 18:06:26 +02:00
998032c6c8 wip 2024-07-10 18:06:24 +02:00
a34bdd8557 wip 2024-07-10 18:06:22 +02:00
868 changed files with 15589 additions and 24865 deletions

View File

@ -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: |

View File

@ -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
View File

@ -266,7 +266,6 @@ paket-files/
# JetBrains Rider
.idea/
*.sln.iml
.run
# CodeRush
.cr/

View File

@ -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";
}
}

View 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>

View 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();
}

View 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; }
}

View File

@ -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; }

View 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;
}

View File

@ -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; }

View File

@ -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; }

View File

@ -1,7 +1,6 @@
#nullable enable
using System.Collections.Generic;
namespace BTCPayServer.Client.App.Models;
namespace BTCPayApp.CommonServer.Models;
public class CreateStoreData
{

View 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; }
}

View 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; }
}

View File

@ -1,7 +1,7 @@
using System;
using Microsoft.AspNetCore.Authorization;
namespace BTCPayServer.Security
namespace BTCPayApp.CommonServer
{
public class PolicyRequirement : IAuthorizationRequirement
{

View File

@ -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
{

View File

@ -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);
}
}

View File

@ -1,7 +1,7 @@
using BTCPayServer.Client;
using Microsoft.AspNetCore.Authorization;
namespace BTCPayServer.Security
namespace BTCPayApp.CommonServer
{
public static class ServerPolicies
{

View File

@ -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>

View File

@ -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);
}

View File

@ -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; }
}
}

View File

@ -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>();
}

View File

@ -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")

View File

@ -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)

View File

@ -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; }
}

View File

@ -1,3 +1,4 @@
using BTCPayApp.CommonServer;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;

View File

@ -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;

View File

@ -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();
}

View File

@ -1,8 +0,0 @@
#nullable enable
namespace BTCPayServer.Client.App.Models;
public class AcceptInviteRequest
{
public string? UserId { get; set; }
public string? Code { get; set; }
}

View File

@ -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; }
}

View File

@ -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>

View File

@ -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);
}
}

View File

@ -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,

View File

@ -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)
{

View File

@ -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)
{

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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)

View File

@ -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);
}
}

View File

@ -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);

View File

@ -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; }
}

View File

@ -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; }
}

View File

@ -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; }
}

View File

@ -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; }
}

View File

@ -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; }
}
}

View File

@ -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; }
}

View File

@ -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; }
}
}

View File

@ -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

View File

@ -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; }

View File

@ -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; }
}

View File

@ -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; }

View File

@ -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; }

View File

@ -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; }

View File

@ -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; }

View File

@ -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; }

View File

@ -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; }
}
}

View File

@ -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);
}
}

View File

@ -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

View File

@ -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))]

View File

@ -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; }
}

View File

@ -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; }

View File

@ -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

View File

@ -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);

View File

@ -131,7 +131,7 @@ namespace BTCPayServer
public string GetTrackedDestination(Script scriptPubKey)
{
return scriptPubKey.Hash.ToString();
return scriptPubKey.Hash.ToString() + "#" + CryptoCode.ToUpperInvariant();
}
}

View File

@ -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)

View File

@ -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>

View 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();
}
}
}

View File

@ -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;

View 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; }
}

View File

@ -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);
}
}
}

View File

@ -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);
}
}
}

View File

@ -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>

View File

@ -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;

View File

@ -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;

View File

@ -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";

View File

@ -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;

View File

@ -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
}
}

View File

@ -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; }
}
}

View File

@ -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",

View File

@ -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"));
}
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}
}

View File

@ -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)
{

View File

@ -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"));
}
}
}

View File

@ -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;
}
}
}

View File

@ -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; }

View 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];
}
}
}

View File

@ -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");

View File

@ -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}";
}
}

View 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);
}
}
}

View File

@ -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; }
}

View File

@ -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; }

View File

@ -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)
{

View File

@ -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)
{
}
}
}

View File

@ -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)
{
}
}
}

File diff suppressed because it is too large Load Diff

View 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");
}
}
}

View File

@ -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);
}
}
}

View File

@ -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