Compare commits

..

1 Commits

Author SHA1 Message Date
85a3dc4848 Plugins: Recommended plugins and github Remote config options
This allows external integrations ( btcpay docker fragments) to highlight specific plugins as recommended to be installed. Also moved the remote option to  a config option instead of a url query param to avoid messy situations where users could get deceived with a generated url. The dockerfiles also have an additional csproj to build and the plugin dir was renamed correctly from extensions to plugins
2020-11-04 08:17:39 +01:00
368 changed files with 4277 additions and 12575 deletions

View File

@ -1,63 +1,38 @@
---
name: "\U0001F41B Bug report"
about: Report a bug or a technical issue
name: Bug report
about: File a bug report
title: ''
labels: ''
assignees: ''
---
<!--
Thank you for reporting a technical issue.
This issue tracker is only for bug reports and problems.
For general questions please read our documentation docs.btcpayserver.org. You can ask technical questions in discussions https://github.com/btcpayserver/btcpayserver/discussions and general support on our community chat chat.btcpayserver.org
Please fill in as much of the template below as you're able.
-->
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce the bug**
Steps to reproduce the reported bug:
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Expected behavior**
<!--
A clear and concise description of what you expected to happen.
-->
**Screenshots**
<!--
If applicable, add screenshots to help explain your problem.
-->
**Your BTCPay Environment (please complete the following information):**
- BTCPay Server Version: <!--[available in the right bottom corner of footer] -->
- Deployment Method: <!--[e.g. Docker, Manual, Third-Party-host]-->
- Browser: <!--[e.g. Chrome, Safari]-->
- BTCPay Server Version: [available in the right bottom corner of footer]
- Deployment Method: [e.g. Docker, Manual, Third-Party-host]
- Browser: [e.g. Chrome, Safari]
**Logs (if applicable)**
<!--
Basic logs can be found in Server Settings > Logs.
More logs https://docs.btcpayserver.org/Troubleshooting/#2-looking-through-the-logs
-->
Basic logs can be found in Server Settings > Logs. More logs https://docs.btcpayserver.org/Troubleshooting/#2-looking-through-the-logs
**Setup Parameters**
<!--
If you're reporting a deployment issue run `. btcpay-setup.sh -i` and paste the setup parameters here with your private information removed or obscured.
-->
**Additional context**
<!--
Add any other context about the problem here.
-->

View File

@ -1,11 +1,5 @@
blank_issues_enabled: false
contact_links:
- name: 🚀 Discussions
url: https://github.com/btcpayserver/btcpayserver/discussions
about: Technical discussions, questions and feature requests
- name: 📝 Official Documentation
url: https://docs.btcpayserver.org
about: Check our documentation for answers to common questions
- name: 💬 Community Support Chat
contact_links:
- name: Community Support Chat
url: https://chat.btcpayserver.org/
about: Ask general questions and get community support in real-time
about: Ask general questions and get community support in real-time.

View File

@ -0,0 +1,23 @@
---
name: Feature request
about: Suggest a new feature or enhancement
title: ''
labels: ''
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Sketch/Image/Wireframe/Mockup**
If applicable provide examples, wireframes, sketches or images to better explain your idea.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.

View File

@ -0,0 +1,6 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Build and pack plugins" type="CompoundRunConfigurationType">
<toRun name="Pack Test Plugin" type="DotNetProject" />
<method v="2" />
</configuration>
</component>

View File

@ -30,10 +30,4 @@
<ItemGroup>
<None Include="icon.png" Pack="true" PackagePath="\" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="3.1.4" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="3.1.4" />
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="3.1.4" />
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="3.1.1" />
</ItemGroup>
</Project>

View File

@ -1,12 +0,0 @@
namespace BTCPayServer.Configuration
{
public class DataDirectories
{
public string DataDir { get; set; }
public string PluginDir { get; set; }
public string TempStorageDir { get; set; }
public string StorageDir { get; set; }
}
}

View File

@ -1,4 +1,4 @@
namespace BTCPayServer.Abstractions.Constants
namespace BTCPayServer.Security
{
public class AuthenticationSchemes
{

View File

@ -1,109 +0,0 @@
using System;
using BTCPayServer.Abstractions.Models;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.Extensions.Options;
using Npgsql.EntityFrameworkCore.PostgreSQL.Migrations;
using Npgsql.EntityFrameworkCore.PostgreSQL.Migrations.Operations;
namespace BTCPayServer.Abstractions.Contracts
{
public abstract class BaseDbContextFactory<T> where T: DbContext
{
private readonly IOptions<DatabaseOptions> _options;
private readonly string _schemaPrefix;
public BaseDbContextFactory(IOptions<DatabaseOptions> options, string schemaPrefix)
{
_options = options;
_schemaPrefix = schemaPrefix;
}
public abstract T CreateContext();
class CustomNpgsqlMigrationsSqlGenerator : NpgsqlMigrationsSqlGenerator
{
public CustomNpgsqlMigrationsSqlGenerator(MigrationsSqlGeneratorDependencies dependencies, IMigrationsAnnotationProvider annotations, Npgsql.EntityFrameworkCore.PostgreSQL.Infrastructure.Internal.INpgsqlOptions opts) : base(dependencies, annotations, opts)
{
}
protected override void Generate(NpgsqlCreateDatabaseOperation operation, IModel model, MigrationCommandListBuilder builder)
{
builder
.Append("CREATE DATABASE ")
.Append(Dependencies.SqlGenerationHelper.DelimitIdentifier(operation.Name));
// POSTGRES gotcha: Indexed Text column (even if PK) are not used if we are not using C locale
builder
.Append(" TEMPLATE ")
.Append(Dependencies.SqlGenerationHelper.DelimitIdentifier("template0"));
builder
.Append(" LC_CTYPE ")
.Append(Dependencies.SqlGenerationHelper.DelimitIdentifier("C"));
builder
.Append(" LC_COLLATE ")
.Append(Dependencies.SqlGenerationHelper.DelimitIdentifier("C"));
builder
.Append(" ENCODING ")
.Append(Dependencies.SqlGenerationHelper.DelimitIdentifier("UTF8"));
if (operation.Tablespace != null)
{
builder
.Append(" TABLESPACE ")
.Append(Dependencies.SqlGenerationHelper.DelimitIdentifier(operation.Tablespace));
}
builder.AppendLine(Dependencies.SqlGenerationHelper.StatementTerminator);
EndStatement(builder, suppressTransaction: true);
}
}
public void ConfigureBuilder(DbContextOptionsBuilder builder)
{
switch (_options.Value.DatabaseType)
{
case DatabaseType.Sqlite:
builder.UseSqlite(_options.Value.ConnectionString, o =>
{
if (!string.IsNullOrEmpty(_schemaPrefix))
{
o.MigrationsHistoryTable(_schemaPrefix);
}
});
break;
case DatabaseType.Postgres:
builder
.UseNpgsql(_options.Value.ConnectionString, o =>
{
o.EnableRetryOnFailure(10);
if (!string.IsNullOrEmpty(_schemaPrefix))
{
o.MigrationsHistoryTable(_schemaPrefix);
}
})
.ReplaceService<IMigrationsSqlGenerator, CustomNpgsqlMigrationsSqlGenerator>();
break;
case DatabaseType.MySQL:
builder.UseMySql(_options.Value.ConnectionString, o =>
{
o.EnableRetryOnFailure(10);
if (!string.IsNullOrEmpty(_schemaPrefix))
{
o.MigrationsHistoryTable(_schemaPrefix);
}
});
break;
default:
throw new ArgumentOutOfRangeException();
}
}
}
}

View File

@ -4,7 +4,7 @@ using BTCPayServer.Abstractions.Converters;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
namespace BTCPayServer.Abstractions.Contracts
namespace BTCPayServer.Contracts
{
public interface IBTCPayServerPlugin
{
@ -14,19 +14,8 @@ namespace BTCPayServer.Abstractions.Contracts
Version Version { get; }
string Description { get; }
bool SystemPlugin { get; set; }
PluginDependency[] Dependencies { get; }
string[] Dependencies { get; }
void Execute(IApplicationBuilder applicationBuilder, IServiceProvider applicationBuilderApplicationServices);
void Execute(IServiceCollection applicationBuilder);
public class PluginDependency
{
public string Identifier { get; set; }
public string Condition { get; set; }
public override string ToString()
{
return $"{Identifier}: {Condition}";
}
}
}
}

View File

@ -1,6 +1,6 @@
using System;
namespace BTCPayServer.Abstractions.Contracts
namespace BTCPayServer.Contracts
{
public abstract class BaseNotification
{

View File

@ -1,10 +0,0 @@
using System.Threading.Tasks;
namespace BTCPayServer.Abstractions.Contracts
{
public interface IPluginHookAction
{
public string Hook { get; }
Task Execute(object args);
}
}

View File

@ -1,11 +0,0 @@
using System.Threading.Tasks;
namespace BTCPayServer.Abstractions.Contracts
{
public interface IPluginHookFilter
{
public string Hook { get; }
Task<object> Execute(object args);
}
}

View File

@ -1,10 +0,0 @@
using System.Threading.Tasks;
namespace BTCPayServer.Abstractions.Contracts
{
public interface IPluginHookService
{
Task ApplyAction(string hook, object args);
Task<object> ApplyFilter(string hook, object args);
}
}

View File

@ -1,7 +1,7 @@
using System.Threading;
using System.Threading.Tasks;
namespace BTCPayServer.Abstractions.Contracts
namespace BTCPayServer.Services
{
public interface ISettingsRepository
{

View File

@ -1,7 +1,7 @@
using System.Threading;
using System.Threading.Tasks;
namespace BTCPayServer.Abstractions.Contracts
namespace BTCPayServer.Hosting
{
public interface IStartupTask
{

View File

@ -1,7 +1,12 @@
using BTCPayServer.Abstractions.Contracts;
namespace BTCPayServer.Abstractions.Services
namespace BTCPayServer.Contracts
{
public interface IUIExtension
{
string Partial { get; }
string Location { get; }
}
public class UIExtension: IUIExtension
{
public UIExtension(string partial, string location)

View File

@ -1,4 +1,4 @@
namespace BTCPayServer.Abstractions.Contracts
namespace BTCPayServer.Contracts
{
public interface ISyncSummaryProvider
{

View File

@ -1,9 +0,0 @@
namespace BTCPayServer.Abstractions.Contracts
{
public interface IUIExtension
{
string Partial { get; }
string Location { get; }
}
}

View File

@ -1,8 +1,8 @@
using System.Text.Json;
using BTCPayServer.Abstractions.Models;
using BTCPayServer.Models;
using Microsoft.AspNetCore.Mvc.ViewFeatures;
namespace BTCPayServer.Abstractions.Extensions
namespace BTCPayServer
{
public static class SetStatusMessageModelExtensions
{

View File

@ -1,7 +1,6 @@
using BTCPayServer.Abstractions.Contracts;
using Microsoft.Extensions.DependencyInjection;
using BTCPayServer.Hosting;
namespace BTCPayServer.Abstractions.Extensions
namespace Microsoft.Extensions.DependencyInjection
{
public static class ServiceCollectionExtensions
{

View File

@ -1,10 +1,10 @@
using System;
using System.Reflection;
using BTCPayServer.Abstractions.Contracts;
using BTCPayServer.Contracts;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
namespace BTCPayServer.Abstractions.Models
namespace BTCPayServer.Models
{
public abstract class BaseBTCPayServerPlugin : IBTCPayServerPlugin
{
@ -21,7 +21,8 @@ namespace BTCPayServer.Abstractions.Models
public abstract string Description { get; }
public bool SystemPlugin { get; set; }
public virtual IBTCPayServerPlugin.PluginDependency[] Dependencies { get; } = Array.Empty<IBTCPayServerPlugin.PluginDependency>();
public bool SystemExtension { get; set; }
public virtual string[] Dependencies { get; } = Array.Empty<string>();
public virtual void Execute(IApplicationBuilder applicationBuilder,
IServiceProvider applicationBuilderApplicationServices)

View File

@ -1,8 +0,0 @@
namespace BTCPayServer.Abstractions.Models
{
public class DatabaseOptions
{
public DatabaseType DatabaseType { get; set; }
public string ConnectionString { get; set; }
}
}

View File

@ -1,9 +0,0 @@
namespace BTCPayServer.Abstractions.Models
{
public enum DatabaseType
{
Sqlite,
Postgres,
MySQL,
}
}

View File

@ -1,6 +1,6 @@
using System;
namespace BTCPayServer.Abstractions.Models
namespace BTCPayServer.Models
{
public class StatusMessageModel
{

View File

@ -1,16 +0,0 @@
using System.Threading.Tasks;
using BTCPayServer.Abstractions.Contracts;
namespace BTCPayServer.Abstractions.Services
{
public abstract class PluginAction<T>:IPluginHookAction
{
public abstract string Hook { get; }
public Task Execute(object args)
{
return Execute(args is T args1 ? args1 : default);
}
public abstract Task Execute(T arg);
}
}

View File

@ -1,17 +0,0 @@
using System.Threading.Tasks;
using BTCPayServer.Abstractions.Contracts;
namespace BTCPayServer.Abstractions.Services
{
public abstract class PluginHookFilter<T>:IPluginHookFilter
{
public abstract string Hook { get; }
public Task<object> Execute(object args)
{
return Execute(args is T args1 ? args1 : default).ContinueWith(task => task.Result as object);
}
public abstract Task<T> Execute(T arg);
}
}

View File

@ -13,7 +13,7 @@
<RepositoryType>git</RepositoryType>
</PropertyGroup>
<PropertyGroup>
<Version Condition=" '$(Version)' == '' ">1.2.0</Version>
<Version Condition=" '$(Version)' == '' ">1.1.1</Version>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<PublishRepositoryUrl>true</PublishRepositoryUrl>
@ -27,7 +27,7 @@
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="All" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="NBitcoin" Version="5.0.68" />
<PackageReference Include="NBitcoin" Version="5.0.60" />
<PackageReference Include="BTCPayServer.Lightning.Common" Version="1.2.0" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
</ItemGroup>

View File

@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace BTCPayServer.Client
{

View File

@ -26,13 +26,6 @@ namespace BTCPayServer.Client
CreateHttpRequest($"api/v1/stores/{storeId}/invoices/{invoiceId}"), token);
return await HandleResponse<InvoiceData>(response);
}
public virtual async Task<InvoicePaymentMethodDataModel[]> GetInvoicePaymentMethods(string storeId, string invoiceId,
CancellationToken token = default)
{
var response = await _httpClient.SendAsync(
CreateHttpRequest($"api/v1/stores/{storeId}/invoices/{invoiceId}/payment-methods"), token);
return await HandleResponse<InvoicePaymentMethodDataModel[]>(response);
}
public virtual async Task ArchiveInvoice(string storeId, string invoiceId,
CancellationToken token = default)
@ -54,23 +47,12 @@ namespace BTCPayServer.Client
return await HandleResponse<InvoiceData>(response);
}
public virtual async Task<InvoiceData> UpdateInvoice(string storeId, string invoiceId,
UpdateInvoiceRequest request, CancellationToken token = default)
{
if (request == null)
throw new ArgumentNullException(nameof(request));
var response = await _httpClient.SendAsync(
CreateHttpRequest($"api/v1/stores/{storeId}/invoices/{invoiceId}", bodyPayload: request,
method: HttpMethod.Put), token);
return await HandleResponse<InvoiceData>(response);
}
public virtual async Task<InvoiceData> MarkInvoiceStatus(string storeId, string invoiceId,
MarkInvoiceStatusRequest request, CancellationToken token = default)
{
if (request == null)
throw new ArgumentNullException(nameof(request));
if (request.Status!= InvoiceStatus.Settled && request.Status!= InvoiceStatus.Invalid)
if (request.Status!= InvoiceStatus.Complete && request.Status!= InvoiceStatus.Invalid)
throw new ArgumentOutOfRangeException(nameof(request.Status), "Status can only be Invalid or Complete");
var response = await _httpClient.SendAsync(
CreateHttpRequest($"api/v1/stores/{storeId}/invoices/{invoiceId}/status", bodyPayload: request,

View File

@ -1,63 +0,0 @@
using System.Collections.Generic;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using BTCPayServer.Client.Models;
namespace BTCPayServer.Client
{
public partial class BTCPayServerClient
{
public virtual async Task<IEnumerable<LightningNetworkPaymentMethodData>>
GetStoreLightningNetworkPaymentMethods(string storeId,
CancellationToken token = default)
{
var response =
await _httpClient.SendAsync(
CreateHttpRequest($"api/v1/stores/{storeId}/payment-methods/LightningNetwork"), token);
return await HandleResponse<IEnumerable<LightningNetworkPaymentMethodData>>(response);
}
public virtual async Task<LightningNetworkPaymentMethodData> GetStoreLightningNetworkPaymentMethod(
string storeId,
string cryptoCode, CancellationToken token = default)
{
var response =
await _httpClient.SendAsync(
CreateHttpRequest($"api/v1/stores/{storeId}/payment-methods/LightningNetwork/{cryptoCode}"), token);
return await HandleResponse<LightningNetworkPaymentMethodData>(response);
}
public virtual async Task RemoveStoreLightningNetworkPaymentMethod(string storeId,
string cryptoCode, CancellationToken token = default)
{
var response =
await _httpClient.SendAsync(
CreateHttpRequest($"api/v1/stores/{storeId}/payment-methods/LightningNetwork/{cryptoCode}",
method: HttpMethod.Delete), token);
await HandleResponse(response);
}
public virtual async Task<LightningNetworkPaymentMethodData> UpdateStoreLightningNetworkPaymentMethod(
string storeId,
string cryptoCode, LightningNetworkPaymentMethodData paymentMethod,
CancellationToken token = default)
{
var response = await _httpClient.SendAsync(
CreateHttpRequest($"api/v1/stores/{storeId}/payment-methods/LightningNetwork/{cryptoCode}",
bodyPayload: paymentMethod, method: HttpMethod.Put), token);
return await HandleResponse<LightningNetworkPaymentMethodData>(response);
}
public virtual async Task<LightningNetworkPaymentMethodData>
UpdateStoreLightningNetworkPaymentMethodToInternalNode(string storeId,
string cryptoCode, LightningNetworkPaymentMethodData paymentMethod,
CancellationToken token = default)
{
var response = await _httpClient.SendAsync(
CreateHttpRequest($"api/v1/stores/{storeId}/payment-methods/LightningNetwork/{cryptoCode}/internal",
method: HttpMethod.Put), token);
return await HandleResponse<LightningNetworkPaymentMethodData>(response);
}
}
}

View File

@ -1,47 +0,0 @@
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using BTCPayServer.Client.Models;
namespace BTCPayServer.Client
{
public partial class BTCPayServerClient
{
public virtual async Task<IEnumerable<NotificationData>> GetNotifications(bool? seen = null,
CancellationToken token = default)
{
var response =
await _httpClient.SendAsync(
CreateHttpRequest($"api/v1/users/me/notifications",
seen != null ? new Dictionary<string, object>() {{nameof(seen), seen}} : null), token);
return await HandleResponse<IEnumerable<NotificationData>>(response);
}
public virtual async Task<NotificationData> GetNotification(string notificationId,
CancellationToken token = default)
{
var response = await _httpClient.SendAsync(
CreateHttpRequest($"api/v1/users/me/notifications/{notificationId}"), token);
return await HandleResponse<NotificationData>(response);
}
public virtual async Task<NotificationData> UpdateNotification(string notificationId, bool? seen,
CancellationToken token = default)
{
var response = await _httpClient.SendAsync(
CreateHttpRequest($"api/v1/users/me/notifications/{notificationId}",
method: HttpMethod.Put, bodyPayload: new UpdateNotification() {Seen = seen}), token);
return await HandleResponse<NotificationData>(response);
}
public virtual async Task RemoveNotification(string notificationId, CancellationToken token = default)
{
var response = await _httpClient.SendAsync(
CreateHttpRequest($"api/v1/users/me/notifications/{notificationId}",
method: HttpMethod.Delete), token);
await HandleResponse(response);
}
}
}

View File

@ -1,74 +0,0 @@
using System.Collections.Generic;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using BTCPayServer.Client.Models;
namespace BTCPayServer.Client
{
public partial class BTCPayServerClient
{
public virtual async Task<IEnumerable<OnChainPaymentMethodData>> GetStoreOnChainPaymentMethods(string storeId,
CancellationToken token = default)
{
var response =
await _httpClient.SendAsync(
CreateHttpRequest($"api/v1/stores/{storeId}/payment-methods/Onchain"), token);
return await HandleResponse<IEnumerable<OnChainPaymentMethodData>>(response);
}
public virtual async Task<OnChainPaymentMethodData> GetStoreOnChainPaymentMethod(string storeId,
string cryptoCode, CancellationToken token = default)
{
var response =
await _httpClient.SendAsync(
CreateHttpRequest($"api/v1/stores/{storeId}/payment-methods/Onchain/{cryptoCode}"), token);
return await HandleResponse<OnChainPaymentMethodData>(response);
}
public virtual async Task RemoveStoreOnChainPaymentMethod(string storeId,
string cryptoCode, CancellationToken token = default)
{
var response =
await _httpClient.SendAsync(
CreateHttpRequest($"api/v1/stores/{storeId}/payment-methods/Onchain/{cryptoCode}",
method: HttpMethod.Delete), token);
await HandleResponse(response);
}
public virtual async Task<OnChainPaymentMethodData> UpdateStoreOnChainPaymentMethod(string storeId,
string cryptoCode, OnChainPaymentMethodData paymentMethod,
CancellationToken token = default)
{
var response = await _httpClient.SendAsync(
CreateHttpRequest($"api/v1/stores/{storeId}/payment-methods/Onchain/{cryptoCode}",
bodyPayload: paymentMethod, method: HttpMethod.Put), token);
return await HandleResponse<OnChainPaymentMethodData>(response);
}
public virtual async Task<OnChainPaymentMethodPreviewResultData>
PreviewProposedStoreOnChainPaymentMethodAddresses(
string storeId, string cryptoCode, OnChainPaymentMethodData paymentMethod, int offset = 0,
int amount = 10,
CancellationToken token = default)
{
var response = await _httpClient.SendAsync(
CreateHttpRequest($"api/v1/stores/{storeId}/payment-methods/Onchain/{cryptoCode}/preview",
bodyPayload: paymentMethod,
queryPayload: new Dictionary<string, object>() {{"offset", offset}, {"amount", amount}},
method: HttpMethod.Post), token);
return await HandleResponse<OnChainPaymentMethodPreviewResultData>(response);
}
public virtual async Task<OnChainPaymentMethodPreviewResultData> PreviewStoreOnChainPaymentMethodAddresses(
string storeId, string cryptoCode, int offset = 0, int amount = 10,
CancellationToken token = default)
{
var response = await _httpClient.SendAsync(
CreateHttpRequest($"api/v1/stores/{storeId}/payment-methods/Onchain/{cryptoCode}/preview",
queryPayload: new Dictionary<string, object>() {{"offset", offset}, {"amount", amount}},
method: HttpMethod.Get), token);
return await HandleResponse<OnChainPaymentMethodPreviewResultData>(response);
}
}
}

View File

@ -1,65 +0,0 @@
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
using BTCPayServer.Client.Models;
using Newtonsoft.Json.Linq;
namespace BTCPayServer.Client
{
public partial class BTCPayServerClient
{
public async Task<StoreWebhookData> CreateWebhook(string storeId, Client.Models.CreateStoreWebhookRequest create, CancellationToken token = default)
{
var response = await _httpClient.SendAsync(CreateHttpRequest($"api/v1/stores/{storeId}/webhooks", bodyPayload: create, method: HttpMethod.Post), token);
return await HandleResponse<StoreWebhookData>(response);
}
public async Task<StoreWebhookData> GetWebhook(string storeId, string webhookId, CancellationToken token = default)
{
var response = await _httpClient.SendAsync(CreateHttpRequest($"api/v1/stores/{storeId}/webhooks/{webhookId}"), token);
if (response.StatusCode == System.Net.HttpStatusCode.NotFound)
return null;
return await HandleResponse<StoreWebhookData>(response);
}
public async Task<StoreWebhookData> UpdateWebhook(string storeId, string webhookId, Models.UpdateStoreWebhookRequest update, CancellationToken token = default)
{
var response = await _httpClient.SendAsync(CreateHttpRequest($"api/v1/stores/{storeId}/webhooks/{webhookId}", bodyPayload: update, method: HttpMethod.Put), token);
return await HandleResponse<StoreWebhookData>(response);
}
public async Task<bool> DeleteWebhook(string storeId, string webhookId, CancellationToken token = default)
{
var response = await _httpClient.SendAsync(CreateHttpRequest($"api/v1/stores/{storeId}/webhooks/{webhookId}", method: HttpMethod.Delete), token);
return response.IsSuccessStatusCode;
}
public async Task<StoreWebhookData[]> GetWebhooks(string storeId, CancellationToken token = default)
{
var response = await _httpClient.SendAsync(CreateHttpRequest($"api/v1/stores/{storeId}/webhooks"), token);
return await HandleResponse<StoreWebhookData[]>(response);
}
public async Task<WebhookDeliveryData[]> GetWebhookDeliveries(string storeId, string webhookId, CancellationToken token = default)
{
var response = await _httpClient.SendAsync(CreateHttpRequest($"api/v1/stores/{storeId}/webhooks/{webhookId}/deliveries"), token);
return await HandleResponse<WebhookDeliveryData[]>(response);
}
public async Task<WebhookDeliveryData> GetWebhookDelivery(string storeId, string webhookId, string deliveryId, CancellationToken token = default)
{
var response = await _httpClient.SendAsync(CreateHttpRequest($"api/v1/stores/{storeId}/webhooks/{webhookId}/deliveries/{deliveryId}"), token);
return await HandleResponse<WebhookDeliveryData>(response);
}
public async Task<string> RedeliverWebhook(string storeId, string webhookId, string deliveryId, CancellationToken token = default)
{
var response = await _httpClient.SendAsync(CreateHttpRequest($"api/v1/stores/{storeId}/webhooks/{webhookId}/deliveries/{deliveryId}/redeliver", null, HttpMethod.Post), token);
return await HandleResponse<string>(response);
}
public async Task<WebhookEvent> GetWebhookDeliveryRequest(string storeId, string webhookId, string deliveryId, CancellationToken token = default)
{
var response = await _httpClient.SendAsync(CreateHttpRequest($"api/v1/stores/{storeId}/webhooks/{webhookId}/deliveries/{deliveryId}/request"), token);
if (response.StatusCode == System.Net.HttpStatusCode.NotFound)
return null;
return await HandleResponse<WebhookEvent>(response);
}
}
}

View File

@ -65,8 +65,7 @@ namespace BTCPayServer.Client
protected async Task<T> HandleResponse<T>(HttpResponseMessage message)
{
await HandleResponse(message);
var str = await message.Content.ReadAsStringAsync();
return JsonConvert.DeserializeObject<T>(str);
return JsonConvert.DeserializeObject<T>(await message.Content.ReadAsStringAsync());
}
protected virtual HttpRequestMessage CreateHttpRequest(string path,

View File

@ -17,7 +17,6 @@ namespace BTCPayServer.Client.Models
public class CheckoutOptions
{
[JsonConverter(typeof(StringEnumConverter))]
public SpeedPolicy? SpeedPolicy { get; set; }
@ -31,9 +30,6 @@ namespace BTCPayServer.Client.Models
public TimeSpan? Monitoring { get; set; }
public double? PaymentTolerance { get; set; }
[JsonProperty("redirectURL")]
public string RedirectURL { get; set; }
public string DefaultLanguage { get; set; }
}
}
}

View File

@ -10,7 +10,8 @@ namespace BTCPayServer.Client.Models
}
public GreenfieldAPIError(string code, string message)
{
code = code ?? "generic-error";
if (code == null)
throw new ArgumentNullException(nameof(code));
if (message == null)
throw new ArgumentNullException(nameof(message));
Code = code;

View File

@ -1,4 +1,6 @@
using System;
using System.Collections.Generic;
using BTCPayServer.JsonConverters;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
@ -7,7 +9,6 @@ namespace BTCPayServer.Client.Models
public class InvoiceData : CreateInvoiceRequest
{
public string Id { get; set; }
public string CheckoutLink { get; set; }
[JsonConverter(typeof(StringEnumConverter))]
public InvoiceStatus Status { get; set; }
[JsonConverter(typeof(StringEnumConverter))]
@ -19,12 +20,4 @@ namespace BTCPayServer.Client.Models
[JsonConverter(typeof(NBitcoin.JsonConverters.DateTimeToUnixTimeConverter))]
public DateTimeOffset CreatedTime { get; set; }
}
public enum InvoiceStatus
{
New,
Processing,
Expired,
Invalid,
Settled
}
}

View File

@ -1,61 +0,0 @@
using System;
using System.Collections.Generic;
using BTCPayServer.JsonConverters;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
namespace BTCPayServer.Client.Models
{
public class InvoicePaymentMethodDataModel
{
public string Destination { get; set; }
public string PaymentLink { get; set; }
[JsonConverter(typeof(NumericStringJsonConverter))]
public decimal Rate { get; set; }
[JsonConverter(typeof(NumericStringJsonConverter))]
public decimal PaymentMethodPaid { get; set; }
[JsonConverter(typeof(NumericStringJsonConverter))]
public decimal TotalPaid { get; set; }
[JsonConverter(typeof(NumericStringJsonConverter))]
public decimal Due { get; set; }
[JsonConverter(typeof(NumericStringJsonConverter))]
public decimal Amount { get; set; }
[JsonConverter(typeof(NumericStringJsonConverter))]
public decimal NetworkFee { get; set; }
public List<Payment> Payments { get; set; }
public string PaymentMethod { get; set; }
public class Payment
{
public string Id { get; set; }
[JsonConverter(typeof(NBitcoin.JsonConverters.DateTimeToUnixTimeConverter))]
public DateTime ReceivedDate { get; set; }
[JsonConverter(typeof(NumericStringJsonConverter))]
public decimal Value { get; set; }
[JsonConverter(typeof(NumericStringJsonConverter))]
public decimal Fee { get; set; }
[JsonConverter(typeof(StringEnumConverter))]
public PaymentStatus Status { get; set; }
public string Destination { get; set; }
public enum PaymentStatus
{
Invalid,
Processing,
Settled
}
}
}
}

View File

@ -0,0 +1,12 @@
namespace BTCPayServer.Client.Models
{
public enum InvoiceStatus
{
New,
Paid,
Expired,
Invalid,
Complete,
Confirmed
}
}

View File

@ -1,28 +0,0 @@
namespace BTCPayServer.Client.Models
{
public class LightningNetworkPaymentMethodData
{
/// <summary>
/// Whether the payment method is enabled
/// </summary>
public bool Enabled { get; set; }
/// <summary>
/// Crypto code of the payment method
/// </summary>
public string CryptoCode { get; set; }
public string ConnectionString { get; set; }
public LightningNetworkPaymentMethodData()
{
}
public LightningNetworkPaymentMethodData(string cryptoCode, string connectionString, bool enabled)
{
Enabled = enabled;
CryptoCode = cryptoCode;
ConnectionString = connectionString;
}
}
}

View File

@ -1,16 +0,0 @@
using System;
using Newtonsoft.Json;
namespace BTCPayServer.Client.Models
{
public class NotificationData
{
public string Id { get; set; }
public string Body { get; set; }
public bool Seen { get; set; }
public Uri Link { get; set; }
[JsonConverter(typeof(NBitcoin.JsonConverters.DateTimeToUnixTimeConverter))]
public DateTimeOffset CreatedTime { get; set; }
}
}

View File

@ -1,39 +0,0 @@
using NBitcoin;
using Newtonsoft.Json;
namespace BTCPayServer.Client.Models
{
public class OnChainPaymentMethodData
{
/// <summary>
/// Whether the payment method is enabled
/// </summary>
public bool Enabled { get; set; }
/// <summary>
/// Crypto code of the payment method
/// </summary>
public string CryptoCode { get; set; }
/// <summary>
/// The derivation scheme
/// </summary>
public string DerivationScheme { get; set; }
public string Label { get; set; }
[JsonConverter(typeof(NBitcoin.JsonConverters.KeyPathJsonConverter))]
public RootedKeyPath AccountKeyPath { get; set; }
public OnChainPaymentMethodData()
{
}
public OnChainPaymentMethodData(string cryptoCode, string derivationScheme, bool enabled)
{
Enabled = enabled;
CryptoCode = cryptoCode;
DerivationScheme = derivationScheme;
}
}
}

View File

@ -1,23 +0,0 @@
using System.Collections.Generic;
namespace BTCPayServer.Client.Models
{
public class OnChainPaymentMethodPreviewResultData
{
/// <summary>
/// a list of addresses generated by the derivation scheme
/// </summary>
public IList<OnChainPaymentMethodPreviewResultAddressItem> Addresses { get; set; } =
new List<OnChainPaymentMethodPreviewResultAddressItem>();
public class OnChainPaymentMethodPreviewResultAddressItem
{
/// <summary>
/// The key path relative to the account key path.
/// </summary>
public string KeyPath { get; set; }
//The address generated at the key path
public string Address { get; set; }
}
}
}

View File

@ -30,22 +30,14 @@ namespace BTCPayServer.Client.Models
public double PaymentTolerance { get; set; } = 0;
public bool AnyoneCanCreateInvoice { get; set; }
public bool RequiresRefundEmail { get; set; }
public bool LightningAmountInSatoshi { get; set; }
public bool LightningPrivateRouteHints { get; set; }
public bool OnChainWithLnInvoiceFallback { get; set; }
public bool RedirectAutomatically { get; set; }
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public bool ShowRecommendedFee { get; set; } = true;
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public int RecommendedFeeBlockTarget { get; set; } = 1;
public string DefaultPaymentMethod { get; set; }
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public string DefaultLang { get; set; } = "en";
public bool LightningAmountInSatoshi { get; set; }
public string CustomLogo { get; set; }
@ -53,13 +45,16 @@ namespace BTCPayServer.Client.Models
public string HtmlTitle { get; set; }
public bool RedirectAutomatically { get; set; }
public bool RequiresRefundEmail { get; set; }
[JsonConverter(typeof(StringEnumConverter))]
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public NetworkFeeMode NetworkFeeMode { get; set; } = NetworkFeeMode.Never;
public bool PayJoinEnabled { get; set; }
public bool LightningPrivateRouteHints { get; set; }
[JsonExtensionData]

View File

@ -1,35 +0,0 @@
using System;
using System.Collections.Generic;
using System.Text;
using Newtonsoft.Json;
namespace BTCPayServer.Client.Models
{
public class StoreWebhookBaseData
{
public class AuthorizedEventsData
{
public bool Everything { get; set; } = true;
[JsonProperty(ItemConverterType = typeof(Newtonsoft.Json.Converters.StringEnumConverter))]
public WebhookEventType[] SpecificEvents { get; set; } = Array.Empty<WebhookEventType>();
}
public bool Enabled { get; set; } = true;
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)]
public string Secret { get; set; }
public bool AutomaticRedelivery { get; set; } = true;
public string Url { get; set; }
public AuthorizedEventsData AuthorizedEvents { get; set; } = new AuthorizedEventsData();
}
public class UpdateStoreWebhookRequest : StoreWebhookBaseData
{
}
public class CreateStoreWebhookRequest : StoreWebhookBaseData
{
}
public class StoreWebhookData : StoreWebhookBaseData
{
public string Id { get; set; }
}
}

View File

@ -1,9 +0,0 @@
using Newtonsoft.Json.Linq;
namespace BTCPayServer.Client.Models
{
public class UpdateInvoiceRequest
{
public JObject Metadata { get; set; }
}
}

View File

@ -1,7 +0,0 @@
namespace BTCPayServer.Client.Models
{
public class UpdateNotification
{
public bool? Seen { get; set; }
}
}

View File

@ -1,18 +0,0 @@
using System;
using System.Collections.Generic;
using System.Text;
using Newtonsoft.Json;
namespace BTCPayServer.Client.Models
{
public class WebhookDeliveryData
{
public string Id { get; set; }
[JsonConverter(typeof(NBitcoin.JsonConverters.DateTimeToUnixTimeConverter))]
public DateTimeOffset Timestamp { get; set; }
public int? HttpCode { get; set; }
public string ErrorMessage { get; set; }
[JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))]
public WebhookDeliveryStatus Status { get; set; }
}
}

View File

@ -1,13 +0,0 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace BTCPayServer.Client.Models
{
public enum WebhookDeliveryStatus
{
Failed,
HttpError,
HttpSuccess
}
}

View File

@ -1,36 +0,0 @@
using System;
using System.Collections.Generic;
using System.Text;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Linq;
namespace BTCPayServer.Client.Models
{
public class WebhookEvent
{
public readonly static JsonSerializerSettings DefaultSerializerSettings;
static WebhookEvent()
{
DefaultSerializerSettings = new JsonSerializerSettings();
DefaultSerializerSettings.ContractResolver = new Newtonsoft.Json.Serialization.CamelCasePropertyNamesContractResolver();
NBitcoin.JsonConverters.Serializer.RegisterFrontConverters(DefaultSerializerSettings);
DefaultSerializerSettings.Formatting = Formatting.None;
}
public string DeliveryId { get; set; }
public string WebhookId { get; set; }
public string OrignalDeliveryId { get; set; }
public bool IsRedelivery { get; set; }
[JsonConverter(typeof(StringEnumConverter))]
public WebhookEventType Type { get; set; }
[JsonConverter(typeof(NBitcoin.JsonConverters.DateTimeToUnixTimeConverter))]
public DateTimeOffset Timestamp { get; set; }
[JsonExtensionData]
public IDictionary<string, JToken> AdditionalData { get; set; }
public T ReadAs<T>()
{
var str = JsonConvert.SerializeObject(this, DefaultSerializerSettings);
return JsonConvert.DeserializeObject<T>(str, DefaultSerializerSettings);
}
}
}

View File

@ -1,16 +0,0 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace BTCPayServer.Client.Models
{
public enum WebhookEventType
{
InvoiceCreated,
InvoiceReceivedPayment,
InvoiceProcessing,
InvoiceExpired,
InvoiceSettled,
InvoiceInvalid
}
}

View File

@ -1,85 +0,0 @@
using System;
using System.Collections.Generic;
using System.Text;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
namespace BTCPayServer.Client.Models
{
public class WebhookInvoiceEvent : WebhookEvent
{
public WebhookInvoiceEvent()
{
}
public WebhookInvoiceEvent(WebhookEventType evtType)
{
this.Type = evtType;
}
[JsonProperty(Order = 1)]
public string StoreId { get; set; }
[JsonProperty(Order = 2)]
public string InvoiceId { get; set; }
}
public class WebhookInvoiceSettledEvent : WebhookInvoiceEvent
{
public WebhookInvoiceSettledEvent()
{
}
public WebhookInvoiceSettledEvent(WebhookEventType evtType) : base(evtType)
{
}
public bool ManuallyMarked { get; set; }
}
public class WebhookInvoiceInvalidEvent : WebhookInvoiceEvent
{
public WebhookInvoiceInvalidEvent()
{
}
public WebhookInvoiceInvalidEvent(WebhookEventType evtType) : base(evtType)
{
}
public bool ManuallyMarked { get; set; }
}
public class WebhookInvoiceProcessingEvent : WebhookInvoiceEvent
{
public WebhookInvoiceProcessingEvent()
{
}
public WebhookInvoiceProcessingEvent(WebhookEventType evtType) : base(evtType)
{
}
public bool OverPaid { get; set; }
}
public class WebhookInvoiceReceivedPaymentEvent : WebhookInvoiceEvent
{
public WebhookInvoiceReceivedPaymentEvent()
{
}
public WebhookInvoiceReceivedPaymentEvent(WebhookEventType evtType) : base(evtType)
{
}
public bool AfterExpiration { get; set; }
}
public class WebhookInvoiceExpiredEvent : WebhookInvoiceEvent
{
public WebhookInvoiceExpiredEvent()
{
}
public WebhookInvoiceExpiredEvent(WebhookEventType evtType) : base(evtType)
{
}
public bool PartiallyPaid { get; set; }
}
}

View File

@ -12,7 +12,6 @@ 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 CanModifyStoreWebhooks = "btcpay.store.webhooks.canmodifywebhooks";
public const string CanModifyStoreSettingsUnscoped = "btcpay.store.canmodifystoresettings:";
public const string CanViewStoreSettings = "btcpay.store.canviewstoresettings";
public const string CanViewInvoices = "btcpay.store.canviewinvoices";
@ -21,8 +20,6 @@ namespace BTCPayServer.Client
public const string CanModifyPaymentRequests = "btcpay.store.canmodifypaymentrequests";
public const string CanModifyProfile = "btcpay.user.canmodifyprofile";
public const string CanViewProfile = "btcpay.user.canviewprofile";
public const string CanManageNotificationsForUser = "btcpay.user.canmanagenotificationsforuser";
public const string CanViewNotificationsForUser = "btcpay.user.canviewnotificationsforuser";
public const string CanCreateUser = "btcpay.server.cancreateuser";
public const string CanManagePullPayments = "btcpay.store.canmanagepullpayments";
public const string Unrestricted = "unrestricted";
@ -32,7 +29,6 @@ namespace BTCPayServer.Client
{
yield return CanViewInvoices;
yield return CanCreateInvoice;
yield return CanModifyStoreWebhooks;
yield return CanModifyServerSettings;
yield return CanModifyStoreSettings;
yield return CanViewStoreSettings;
@ -41,8 +37,6 @@ namespace BTCPayServer.Client
yield return CanModifyProfile;
yield return CanViewProfile;
yield return CanCreateUser;
yield return CanManageNotificationsForUser;
yield return CanViewNotificationsForUser;
yield return Unrestricted;
yield return CanUseInternalLightningNode;
yield return CanCreateLightningInvoiceInternalNode;
@ -162,7 +156,6 @@ namespace BTCPayServer.Client
switch (subpolicy)
{
case Policies.CanViewInvoices when this.Policy == Policies.CanModifyStoreSettings:
case Policies.CanModifyStoreWebhooks when this.Policy == Policies.CanModifyStoreSettings:
case Policies.CanViewInvoices when this.Policy == Policies.CanViewStoreSettings:
case Policies.CanViewStoreSettings when this.Policy == Policies.CanModifyStoreSettings:
case Policies.CanCreateInvoice when this.Policy == Policies.CanModifyStoreSettings:
@ -172,7 +165,6 @@ namespace BTCPayServer.Client
case Policies.CanViewPaymentRequests when this.Policy == Policies.CanViewStoreSettings:
case Policies.CanCreateLightningInvoiceInternalNode when this.Policy == Policies.CanUseInternalLightningNode:
case Policies.CanCreateLightningInvoiceInStore when this.Policy == Policies.CanUseLightningNodeInStore:
case Policies.CanViewNotificationsForUser when this.Policy == Policies.CanManageNotificationsForUser:
return true;
default:
return false;

View File

@ -4,14 +4,14 @@ namespace BTCPayServer
{
public partial class BTCPayNetworkProvider
{
public void InitBGold()
public void InitBitcoinGold()
{
var nbxplorerNetwork = NBXplorerNetworkProvider.GetFromCryptoCode("BTG");
Add(new BTCPayNetwork()
{
CryptoCode = nbxplorerNetwork.CryptoCode,
DisplayName = "BGold",
BlockExplorerLink = NetworkType == NetworkType.Mainnet ? "https://btgexplorer.com/tx/{0}" : "https://testnet.btgexplorer.com/tx/{0}",
BlockExplorerLink = NetworkType == NetworkType.Mainnet ? "https://explorer.bitcoingold.org/insight/tx/{0}/" : "https://test-explorer.bitcoingold.org/insight/tx/{0}",
NBXplorerNetwork = nbxplorerNetwork,
UriScheme = "bitcoingold",
DefaultRateRules = new[]

View File

@ -5,22 +5,22 @@ namespace BTCPayServer
{
public partial class BTCPayNetworkProvider
{
public void InitBPlus()
public void InitBitcoinplus()
{
var nbxplorerNetwork = NBXplorerNetworkProvider.GetFromCryptoCode("XBC");
Add(new BTCPayNetwork()
{
CryptoCode = nbxplorerNetwork.CryptoCode,
DisplayName = "BPlus",
DisplayName = "Bitcoinplus",
BlockExplorerLink = NetworkType == NetworkType.Mainnet ? "https://chainz.cryptoid.info/xbc/tx.dws?{0}" : "https://chainz.cryptoid.info/xbc/tx.dws?{0}",
NBXplorerNetwork = nbxplorerNetwork,
UriScheme = "bplus-fix-it",
UriScheme = "bitcoinplus",
DefaultRateRules = new[]
{
"XBC_X = XBC_BTC * BTC_X",
"XBC_BTC = cryptopia(XBC_BTC)"
"XBC_X = XBC_BTC * BTC_X",
"XBC_BTC = cryptopia(XBC_BTC)"
},
CryptoImagePath = "imlegacy/xbc.png",
CryptoImagePath = "imlegacy/bitcoinplus.png",
DefaultSettings = BTCPayDefaultSettings.GetDefaultSettings(NetworkType),
CoinType = NetworkType == NetworkType.Mainnet ? new KeyPath("65'") : new KeyPath("1'")
});

View File

@ -53,7 +53,7 @@ namespace BTCPayServer
public bool SupportRBF { get; internal set; }
public string LightningImagePath { get; set; }
public BTCPayDefaultSettings DefaultSettings { get; set; }
public KeyPath CoinType { get; set; }
public KeyPath CoinType { get; internal set; }
public Dictionary<uint, DerivationType> ElectrumMapping = new Dictionary<uint, DerivationType>();
@ -132,7 +132,7 @@ namespace BTCPayServer
{
private string _blockExplorerLink;
public bool ShowSyncSummary { get; set; } = true;
public string CryptoCode { get; set; }
public string CryptoCode { get; internal set; }
public string BlockExplorerLink
{
@ -161,7 +161,7 @@ namespace BTCPayServer
}
public string CryptoImagePath { get; set; }
public string[] DefaultRateRules { get; set; } = Array.Empty<string>();
public string[] DefaultRateRules { get; internal set; } = Array.Empty<string>();
public override string ToString()
{
return CryptoCode;

View File

@ -8,7 +8,8 @@ namespace BTCPayServer
{
public partial class BTCPayNetworkProvider
{
protected readonly Dictionary<string, BTCPayNetworkBase> _Networks = new Dictionary<string, BTCPayNetworkBase>();
readonly Dictionary<string, BTCPayNetworkBase> _Networks = new Dictionary<string, BTCPayNetworkBase>();
private readonly NBXplorerNetworkProvider _NBXplorerNetworkProvider;
public NBXplorerNetworkProvider NBXplorerNetworkProvider
@ -47,7 +48,7 @@ namespace BTCPayServer
InitLitecoin();
InitBitcore();
InitDogecoin();
InitBGold();
InitBitcoinGold();
InitMonacoin();
InitDash();
InitFeathercoin();
@ -78,7 +79,7 @@ namespace BTCPayServer
}
// Disabled because of https://twitter.com/Cryptopia_NZ/status/1085084168852291586
//InitBPlus();
//InitBitcoinplus();
//InitUfo();
#endif
}
@ -132,4 +133,4 @@ namespace BTCPayServer
return network as T;
}
}
}
}

View File

@ -1,21 +0,0 @@
using BTCPayServer.Abstractions.Contracts;
using BTCPayServer.Abstractions.Models;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Options;
namespace BTCPayServer.Data
{
public class ApplicationDbContextFactory : BaseDbContextFactory<ApplicationDbContext>
{
public ApplicationDbContextFactory(IOptions<DatabaseOptions> options) : base(options, "")
{
}
public override ApplicationDbContext CreateContext()
{
var builder = new DbContextOptionsBuilder<ApplicationDbContext>();
ConfigureBuilder(builder);
return new ApplicationDbContext(builder.Options);
}
}
}

View File

@ -7,10 +7,12 @@
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="3.1.4" />
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="3.1.4" />
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="3.1.1" />
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="3.1.4" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\BTCPayServer.Abstractions\BTCPayServer.Abstractions.csproj" />
<ProjectReference Include="..\BTCPayServer.Client\BTCPayServer.Client.csproj" />
</ItemGroup>
</Project>

View File

@ -6,13 +6,15 @@ namespace BTCPayServer.Data
public class APIKeyData
{
[MaxLength(50)]
public string Id { get; set; }
public string Id
{
get;
set;
}
[MaxLength(50)]
public string StoreId { get; set; }
[MaxLength(50)] public string StoreId { get; set; }
[MaxLength(50)]
public string UserId { get; set; }
[MaxLength(50)] public string UserId { get; set; }
public APIKeyType Type { get; set; } = APIKeyType.Legacy;
@ -21,7 +23,6 @@ namespace BTCPayServer.Data
public ApplicationUser User { get; set; }
public string Label { get; set; }
internal static void OnModelCreating(ModelBuilder builder)
{
builder.Entity<APIKeyData>()

View File

@ -10,11 +10,25 @@ namespace BTCPayServer.Data
/// For not having exceptions thrown by two address on different network, we suffix by "#CRYPTOCODE"
/// </summary>
[Obsolete("Use GetHash instead")]
public string Address { get; set; }
public InvoiceData InvoiceData { get; set; }
public string InvoiceDataId { get; set; }
public DateTimeOffset? CreatedTime { get; set; }
public string Address
{
get; set;
}
public InvoiceData InvoiceData
{
get; set;
}
public string InvoiceDataId
{
get; set;
}
public DateTimeOffset? CreatedTime
{
get; set;
}
internal static void OnModelCreating(ModelBuilder builder)
{

View File

@ -8,24 +8,22 @@ namespace BTCPayServer.Data
{
public string Id { get; set; }
public string Name { get; set; }
public string StoreDataId { get; set; }
public string StoreDataId
{
get; set;
}
public string AppType { get; set; }
public StoreData StoreData { get; set; }
public DateTimeOffset Created { get; set; }
public StoreData StoreData
{
get; set;
}
public DateTimeOffset Created
{
get; set;
}
public bool TagAllInvoices { get; set; }
public string Settings { get; set; }
internal static void OnModelCreating(ModelBuilder builder)
{
builder.Entity<AppData>()
.HasOne(o => o.StoreData)
.WithMany(i => i.Apps).OnDelete(DeleteBehavior.Cascade);
builder.Entity<AppData>()
.HasOne(a => a.StoreData);
}
// utility methods
public T GetSettings<T>() where T : class, new()
{
if (String.IsNullOrEmpty(Settings))
@ -37,5 +35,14 @@ namespace BTCPayServer.Data
{
Settings = value == null ? null : JsonConvert.SerializeObject(value);
}
internal static void OnModelCreating(ModelBuilder builder)
{
builder.Entity<AppData>()
.HasOne(o => o.StoreData)
.WithMany(i => i.Apps).OnDelete(DeleteBehavior.Cascade);
builder.Entity<AppData>()
.HasOne(a => a.StoreData);
}
}
}

View File

@ -30,36 +30,38 @@ namespace BTCPayServer.Data
_designTime = designTime;
}
public DbSet<AddressInvoiceData> AddressInvoices { get; set; }
public DbSet<APIKeyData> ApiKeys { get; set; }
public DbSet<AppData> Apps { get; set; }
public DbSet<StoredFile> Files { get; set; }
public DbSet<HistoricalAddressInvoiceData> HistoricalAddressInvoices { get; set; }
public DbSet<InvoiceEventData> InvoiceEvents { get; set; }
public DbSet<InvoiceSearchData> InvoiceSearches { get; set; }
public DbSet<InvoiceWebhookDeliveryData> InvoiceWebhookDeliveries { get; set; }
public DbSet<InvoiceData> Invoices { get; set; }
public DbSet<NotificationData> Notifications { get; set; }
public DbSet<OffchainTransactionData> OffchainTransactions { get; set; }
public DbSet<PairedSINData> PairedSINData { get; set; }
public DbSet<PairingCodeData> PairingCodes { get; set; }
public DbSet<PayjoinLock> PayjoinLocks { get; set; }
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<InvoiceData> Invoices
{
get; set;
}
public DbSet<RefundData> Refunds
{
get; set;
}
public DbSet<PlannedTransaction> PlannedTransactions { get; set; }
public DbSet<PayjoinLock> PayjoinLocks { get; set; }
public DbSet<AppData> Apps { get; set; }
public DbSet<InvoiceEventData> InvoiceEvents { get; set; }
public DbSet<OffchainTransactionData> OffchainTransactions { get; set; }
public DbSet<HistoricalAddressInvoiceData> HistoricalAddressInvoices { get; set; }
public DbSet<PendingInvoiceData> PendingInvoices { get; set; }
public DbSet<PaymentData> Payments { get; set; }
public DbSet<PaymentRequestData> PaymentRequests { get; set; }
public DbSet<PullPaymentData> PullPayments { get; set; }
public DbSet<RefundData> Refunds { get; set; }
public DbSet<SettingData> Settings { get; set; }
public DbSet<StoreWebhookData> StoreWebhooks { get; set; }
public DbSet<StoreData> Stores { get; set; }
public DbSet<U2FDevice> U2FDevices { get; set; }
public DbSet<UserStore> UserStore { get; set; }
public DbSet<PayoutData> Payouts { get; set; }
public DbSet<WalletData> Wallets { get; set; }
public DbSet<WalletTransactionData> WalletTransactions { get; set; }
public DbSet<WebhookDeliveryData> WebhookDeliveries { get; set; }
public DbSet<WebhookData> Webhooks { get; set; }
public DbSet<StoreData> Stores { get; set; }
public DbSet<UserStore> UserStore { get; set; }
public DbSet<AddressInvoiceData> AddressInvoices { get; set; }
public DbSet<SettingData> Settings { get; set; }
public DbSet<PairingCodeData> PairingCodes { get; set; }
public DbSet<PairedSINData> PairedSINData { get; set; }
public DbSet<APIKeyData> ApiKeys { get; set; }
public DbSet<StoredFile> Files { get; set; }
public DbSet<U2FDevice> U2FDevices { get; set; }
public DbSet<NotificationData> Notifications { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
@ -71,41 +73,25 @@ namespace BTCPayServer.Data
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
// some of the data models don't have OnModelCreating for now, commenting them
AddressInvoiceData.OnModelCreating(builder);
NotificationData.OnModelCreating(builder);
InvoiceData.OnModelCreating(builder);
PaymentData.OnModelCreating(builder);
Data.UserStore.OnModelCreating(builder);
APIKeyData.OnModelCreating(builder);
AppData.OnModelCreating(builder);
//StoredFile.OnModelCreating(builder);
AddressInvoiceData.OnModelCreating(builder);
PairingCodeData.OnModelCreating(builder);
PendingInvoiceData.OnModelCreating(builder);
Data.PairedSINData.OnModelCreating(builder);
HistoricalAddressInvoiceData.OnModelCreating(builder);
InvoiceEventData.OnModelCreating(builder);
InvoiceSearchData.OnModelCreating(builder);
InvoiceWebhookDeliveryData.OnModelCreating(builder);
InvoiceData.OnModelCreating(builder);
NotificationData.OnModelCreating(builder);
//OffchainTransactionData.OnModelCreating(builder);
Data.PairedSINData.OnModelCreating(builder);
PairingCodeData.OnModelCreating(builder);
//PayjoinLock.OnModelCreating(builder);
PaymentRequestData.OnModelCreating(builder);
PaymentData.OnModelCreating(builder);
PayoutData.OnModelCreating(builder);
PendingInvoiceData.OnModelCreating(builder);
//PlannedTransaction.OnModelCreating(builder);
PullPaymentData.OnModelCreating(builder);
RefundData.OnModelCreating(builder);
//SettingData.OnModelCreating(builder);
StoreWebhookData.OnModelCreating(builder);
//StoreData.OnModelCreating(builder);
U2FDevice.OnModelCreating(builder);
Data.UserStore.OnModelCreating(builder);
//WalletData.OnModelCreating(builder);
WalletTransactionData.OnModelCreating(builder);
WebhookDeliveryData.OnModelCreating(builder);
//WebhookData.OnModelCreating(builder);
PullPaymentData.OnModelCreating(builder);
PayoutData.OnModelCreating(builder);
RefundData.OnModelCreating(builder);
U2FDevice.OnModelCreating(builder);
if (Database.IsSqlite() && !_designTime)
{
// SQLite does not have proper support for DateTimeOffset via Entity Framework Core, see the limitations

View File

@ -0,0 +1,96 @@
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Migrations;
using Npgsql.EntityFrameworkCore.PostgreSQL.Migrations;
using Npgsql.EntityFrameworkCore.PostgreSQL.Migrations.Operations;
namespace BTCPayServer.Data
{
public enum DatabaseType
{
Sqlite,
Postgres,
MySQL,
}
public class ApplicationDbContextFactory
{
readonly string _ConnectionString;
readonly DatabaseType _Type;
public ApplicationDbContextFactory(DatabaseType type, string connectionString)
{
_ConnectionString = connectionString ?? throw new ArgumentNullException(nameof(connectionString));
_Type = type;
}
public DatabaseType Type
{
get
{
return _Type;
}
}
public ApplicationDbContext CreateContext()
{
var builder = new DbContextOptionsBuilder<ApplicationDbContext>();
ConfigureBuilder(builder);
return new ApplicationDbContext(builder.Options);
}
class CustomNpgsqlMigrationsSqlGenerator : NpgsqlMigrationsSqlGenerator
{
public CustomNpgsqlMigrationsSqlGenerator(MigrationsSqlGeneratorDependencies dependencies, IMigrationsAnnotationProvider annotations, Npgsql.EntityFrameworkCore.PostgreSQL.Infrastructure.Internal.INpgsqlOptions opts) : base(dependencies, annotations, opts)
{
}
protected override void Generate(NpgsqlCreateDatabaseOperation operation, IModel model, MigrationCommandListBuilder builder)
{
builder
.Append("CREATE DATABASE ")
.Append(Dependencies.SqlGenerationHelper.DelimitIdentifier(operation.Name));
// POSTGRES gotcha: Indexed Text column (even if PK) are not used if we are not using C locale
builder
.Append(" TEMPLATE ")
.Append(Dependencies.SqlGenerationHelper.DelimitIdentifier("template0"));
builder
.Append(" LC_CTYPE ")
.Append(Dependencies.SqlGenerationHelper.DelimitIdentifier("C"));
builder
.Append(" LC_COLLATE ")
.Append(Dependencies.SqlGenerationHelper.DelimitIdentifier("C"));
builder
.Append(" ENCODING ")
.Append(Dependencies.SqlGenerationHelper.DelimitIdentifier("UTF8"));
if (operation.Tablespace != null)
{
builder
.Append(" TABLESPACE ")
.Append(Dependencies.SqlGenerationHelper.DelimitIdentifier(operation.Tablespace));
}
builder.AppendLine(Dependencies.SqlGenerationHelper.StatementTerminator);
EndStatement(builder, suppressTransaction: true);
}
}
public void ConfigureBuilder(DbContextOptionsBuilder builder)
{
if (_Type == DatabaseType.Sqlite)
builder.UseSqlite(_ConnectionString, o => o.MigrationsAssembly("BTCPayServer.Data"));
else if (_Type == DatabaseType.Postgres)
builder
.UseNpgsql(_ConnectionString, o => o.MigrationsAssembly("BTCPayServer.Data").EnableRetryOnFailure(10))
.ReplaceService<IMigrationsSqlGenerator, CustomNpgsqlMigrationsSqlGenerator>();
else if (_Type == DatabaseType.MySQL)
builder.UseMySql(_ConnectionString, o => o.MigrationsAssembly("BTCPayServer.Data").EnableRetryOnFailure(10));
}
}
}

View File

@ -7,14 +7,27 @@ namespace BTCPayServer.Data
// Add profile data for application users by adding properties to the ApplicationUser class
public class ApplicationUser : IdentityUser
{
public bool RequiresEmailConfirmation { get; set; }
public List<StoredFile> StoredFiles { get; set; }
public List<NotificationData> Notifications { get; set; }
public List<UserStore> UserStores
{
get;
set;
}
public bool RequiresEmailConfirmation
{
get; set;
}
public List<StoredFile> StoredFiles
{
get;
set;
}
public List<U2FDevice> U2FDevices { get; set; }
public List<APIKeyData> APIKeys { get; set; }
public DateTimeOffset? Created { get; set; }
public string DisabledNotifications { get; set; }
public List<NotificationData> Notifications { get; set; }
public List<UserStore> UserStores { get; set; }
}
}

View File

@ -5,23 +5,39 @@ namespace BTCPayServer.Data
{
public class HistoricalAddressInvoiceData
{
public string InvoiceDataId { get; set; }
public InvoiceData InvoiceData { get; set; }
public string InvoiceDataId
{
get; set;
}
public InvoiceData InvoiceData
{
get; set;
}
/// <summary>
/// Some crypto currencies share same address prefix
/// For not having exceptions thrown by two address on different network, we suffix by "#CRYPTOCODE"
/// </summary>
[Obsolete("Use GetCryptoCode instead")]
public string Address { get; set; }
public string Address
{
get; set;
}
[Obsolete("Use GetCryptoCode instead")]
public string CryptoCode { get; set; }
public DateTimeOffset Assigned { get; set; }
public DateTimeOffset? UnAssigned { get; set; }
public DateTimeOffset Assigned
{
get; set;
}
public DateTimeOffset? UnAssigned
{
get; set;
}
internal static void OnModelCreating(ModelBuilder builder)
{

View File

@ -7,40 +7,84 @@ namespace BTCPayServer.Data
{
public class InvoiceData
{
public string Id { get; set; }
public string StoreDataId
{
get; set;
}
public StoreData StoreData
{
get; set;
}
public string StoreDataId { get; set; }
public StoreData StoreData { get; set; }
public string Id
{
get; set;
}
public DateTimeOffset Created { get; set; }
public List<PaymentData> Payments { get; set; }
public List<InvoiceEventData> Events { get; set; }
public DateTimeOffset Created
{
get; set;
}
public List<PaymentData> Payments
{
get; set;
}
public List<HistoricalAddressInvoiceData> HistoricalAddressInvoices { get; set; }
public List<InvoiceEventData> Events
{
get; set;
}
public byte[] Blob { get; set; }
public string ItemCode { get; set; }
public string OrderId { get; set; }
public string Status { get; set; }
public string ExceptionStatus { get; set; }
public string CustomerEmail { get; set; }
public List<AddressInvoiceData> AddressInvoices { get; set; }
public List<HistoricalAddressInvoiceData> HistoricalAddressInvoices
{
get; set;
}
public byte[] Blob
{
get; set;
}
public string ItemCode
{
get;
set;
}
public string OrderId
{
get;
set;
}
public string Status
{
get;
set;
}
public string ExceptionStatus
{
get;
set;
}
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 string CurrentRefundId { get; set; }
[ForeignKey("Id,CurrentRefundId")]
public RefundData CurrentRefund { get; set; }
internal static void OnModelCreating(ModelBuilder builder)
{
builder.Entity<InvoiceData>()
.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>()
.HasOne(o => o.CurrentRefund);
}

View File

@ -5,14 +5,23 @@ namespace BTCPayServer.Data
{
public class InvoiceEventData
{
public string InvoiceDataId { get; set; }
public InvoiceData InvoiceData { get; set; }
public string InvoiceDataId
{
get; set;
}
public InvoiceData InvoiceData
{
get; set;
}
public string UniqueId { get; set; }
public DateTimeOffset Timestamp { get; set; }
public DateTimeOffset Timestamp
{
get; set;
}
public string Message { get; set; }
public EventSeverity Severity { get; set; } = EventSeverity.Info;
internal static void OnModelCreating(ModelBuilder builder)
{
builder.Entity<InvoiceEventData>()
@ -27,7 +36,7 @@ namespace BTCPayServer.Data
#pragma warning restore CS0618
});
}
public enum EventSeverity
{
Info,
@ -35,7 +44,7 @@ namespace BTCPayServer.Data
Success,
Warning
}
public string GetCssClass()
{
return Severity switch

View File

@ -1,37 +0,0 @@
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using Microsoft.EntityFrameworkCore;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
namespace BTCPayServer.Data
{
public class InvoiceSearchData
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Key]
public int Id { get; set; }
[ForeignKey(nameof(InvoiceData))]
public string InvoiceDataId { get; set; }
public InvoiceData InvoiceData { get; set; }
public string Value { get; set; }
internal static void OnModelCreating(ModelBuilder builder)
{
builder.Entity<InvoiceSearchData>()
.HasOne(o => o.InvoiceData)
.WithMany(a => a.InvoiceSearchData)
.OnDelete(DeleteBehavior.Cascade);
builder.Entity<InvoiceSearchData>()
.HasIndex(data => data.Value);
builder.Entity<InvoiceSearchData>()
.Property(a => a.Id)
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.SerialColumn)
.HasAnnotation("MySql:ValueGeneratedOnAdd", true)
.HasAnnotation("Sqlite:Autoincrement", true);
}
}
}

View File

@ -1,25 +0,0 @@
using Microsoft.EntityFrameworkCore;
namespace BTCPayServer.Data
{
public class InvoiceWebhookDeliveryData
{
public string InvoiceId { get; set; }
public InvoiceData Invoice { get; set; }
public string DeliveryId { get; set; }
public WebhookDeliveryData Delivery { get; set; }
internal static void OnModelCreating(ModelBuilder builder)
{
builder.Entity<InvoiceWebhookDeliveryData>()
.HasKey(p => new { p.InvoiceId, p.DeliveryId });
builder.Entity<InvoiceWebhookDeliveryData>()
.HasOne(o => o.Invoice)
.WithOne().OnDelete(DeleteBehavior.Cascade);
builder.Entity<InvoiceWebhookDeliveryData>()
.HasOne(o => o.Delivery)
.WithOne().OnDelete(DeleteBehavior.Cascade);
}
}
}

View File

@ -19,7 +19,6 @@ namespace BTCPayServer.Data
public bool Seen { get; set; }
public byte[] Blob { get; set; }
internal static void OnModelCreating(ModelBuilder builder)
{
builder.Entity<NotificationData>()

View File

@ -5,16 +5,32 @@ namespace BTCPayServer.Data
{
public class PairedSINData
{
public string Id { get; set; }
public string Id
{
get; set;
}
public string StoreDataId { get; set; }
public string StoreDataId
{
get; set;
}
public StoreData StoreData { get; set; }
public string Label { get; set; }
public DateTimeOffset PairingTime { get; set; }
public string SIN { get; set; }
public string Label
{
get;
set;
}
public DateTimeOffset PairingTime
{
get;
set;
}
public string SIN
{
get; set;
}
internal static void OnModelCreating(ModelBuilder builder)
{

View File

@ -5,17 +5,45 @@ namespace BTCPayServer.Data
{
public class PairingCodeData
{
public string Id { get; set; }
public string Id
{
get; set;
}
[Obsolete("Unused")]
public string Facade { get; set; }
public string StoreDataId { get; set; }
public DateTimeOffset Expiration { get; set; }
public string Label { get; set; }
public string SIN { get; set; }
public DateTime DateCreated { get; set; }
public string TokenValue { get; set; }
public string Facade
{
get; set;
}
public string StoreDataId
{
get; set;
}
public DateTimeOffset Expiration
{
get;
set;
}
public string Label
{
get;
set;
}
public string SIN
{
get;
set;
}
public DateTime DateCreated
{
get;
set;
}
public string TokenValue
{
get;
set;
}
internal static void OnModelCreating(ModelBuilder builder)
{

View File

@ -4,13 +4,28 @@ namespace BTCPayServer.Data
{
public class PaymentData
{
public string Id { get; set; }
public string InvoiceDataId { get; set; }
public InvoiceData InvoiceData { get; set; }
public string Id
{
get; set;
}
public byte[] Blob { get; set; }
public bool Accounted { get; set; }
public string InvoiceDataId
{
get; set;
}
public InvoiceData InvoiceData
{
get; set;
}
public byte[] Blob
{
get; set;
}
public bool Accounted
{
get; set;
}
internal static void OnModelCreating(ModelBuilder builder)
{

View File

@ -6,7 +6,10 @@ namespace BTCPayServer.Data
public class PaymentRequestData
{
public string Id { get; set; }
public DateTimeOffset Created { get; set; }
public DateTimeOffset Created
{
get; set;
}
public string StoreDataId { get; set; }
public bool Archived { get; set; }
@ -16,7 +19,6 @@ namespace BTCPayServer.Data
public byte[] Blob { get; set; }
internal static void OnModelCreating(ModelBuilder builder)
{
builder.Entity<PaymentRequestData>()

View File

@ -21,7 +21,18 @@ namespace BTCPayServer.Data
public string Destination { get; set; }
public byte[] Blob { get; set; }
public byte[] Proof { get; set; }
public bool IsInPeriod(PullPaymentData pp, DateTimeOffset now)
{
var period = pp.GetPeriod(now);
if (period is { } p)
{
return p.Start <= Date && (p.End is DateTimeOffset end ? Date < end : true);
}
else
{
return false;
}
}
internal static void OnModelCreating(ModelBuilder builder)
{
@ -38,20 +49,6 @@ namespace BTCPayServer.Data
builder.Entity<PayoutData>()
.HasIndex(o => o.State);
}
// utility methods
public bool IsInPeriod(PullPaymentData pp, DateTimeOffset now)
{
var period = pp.GetPeriod(now);
if (period is { } p)
{
return p.Start <= Date && (p.End is DateTimeOffset end ? Date < end : true);
}
else
{
return false;
}
}
}
public enum PayoutState

View File

@ -4,7 +4,10 @@ namespace BTCPayServer.Data
{
public class PendingInvoiceData
{
public string Id { get; set; }
public string Id
{
get; set;
}
public InvoiceData InvoiceData { get; set; }
internal static void OnModelCreating(ModelBuilder builder)

View File

@ -7,7 +7,8 @@ namespace BTCPayServer.Data
{
[Key]
[MaxLength(100)]
public string Id { get; set; } // Id in the format [cryptocode]-[txid]
// Id in the format [cryptocode]-[txid]
public string Id { get; set; }
public DateTimeOffset BroadcastAt { get; set; }
public byte[] Blob { get; set; }
}

View File

@ -8,6 +8,53 @@ using NBitcoin;
namespace BTCPayServer.Data
{
public static class PayoutExtensions
{
public static IQueryable<PayoutData> GetPayoutInPeriod(this IQueryable<PayoutData> payouts, PullPaymentData pp)
{
return GetPayoutInPeriod(payouts, pp, DateTimeOffset.UtcNow);
}
public static IQueryable<PayoutData> GetPayoutInPeriod(this IQueryable<PayoutData> payouts, PullPaymentData pp, DateTimeOffset now)
{
var request = payouts.Where(p => p.PullPaymentDataId == pp.Id);
var period = pp.GetPeriod(now);
if (period is { } p)
{
var start = p.Start;
if (p.End is DateTimeOffset end)
{
return request.Where(p => p.Date >= start && p.Date < end);
}
else
{
return request.Where(p => p.Date >= start);
}
}
else
{
return request.Where(p => false);
}
}
public static string GetStateString(this PayoutState state)
{
switch (state)
{
case PayoutState.AwaitingApproval:
return "Awaiting Approval";
case PayoutState.AwaitingPayment:
return "Awaiting Payment";
case PayoutState.InProgress:
return "In Progress";
case PayoutState.Completed:
return "Completed";
case PayoutState.Cancelled:
return "Cancelled";
default:
throw new ArgumentOutOfRangeException(nameof(state), state, null);
}
}
}
public class PullPaymentData
{
[Key]
@ -24,16 +71,6 @@ namespace BTCPayServer.Data
public List<PayoutData> Payouts { get; set; }
public byte[] Blob { get; set; }
internal static void OnModelCreating(ModelBuilder builder)
{
builder.Entity<PullPaymentData>()
.HasIndex(o => o.StoreId);
builder.Entity<PullPaymentData>()
.HasOne(o => o.StoreData)
.WithMany(o => o.PullPayments).OnDelete(DeleteBehavior.Cascade);
}
public (DateTimeOffset Start, DateTimeOffset? End)? GetPeriod(DateTimeOffset now)
{
if (now < StartDate)
@ -84,54 +121,14 @@ namespace BTCPayServer.Data
{
return !Archived && !IsExpired(now) && HasStarted(now);
}
}
public static class PayoutExtensions
{
public static IQueryable<PayoutData> GetPayoutInPeriod(this IQueryable<PayoutData> payouts, PullPaymentData pp)
internal static void OnModelCreating(ModelBuilder builder)
{
return GetPayoutInPeriod(payouts, pp, DateTimeOffset.UtcNow);
}
public static IQueryable<PayoutData> GetPayoutInPeriod(this IQueryable<PayoutData> payouts, PullPaymentData pp, DateTimeOffset now)
{
var request = payouts.Where(p => p.PullPaymentDataId == pp.Id);
var period = pp.GetPeriod(now);
if (period is { } p)
{
var start = p.Start;
if (p.End is DateTimeOffset end)
{
return request.Where(p => p.Date >= start && p.Date < end);
}
else
{
return request.Where(p => p.Date >= start);
}
}
else
{
return request.Where(p => false);
}
}
public static string GetStateString(this PayoutState state)
{
switch (state)
{
case PayoutState.AwaitingApproval:
return "Awaiting Approval";
case PayoutState.AwaitingPayment:
return "Awaiting Payment";
case PayoutState.InProgress:
return "In Progress";
case PayoutState.Completed:
return "Completed";
case PayoutState.Cancelled:
return "Cancelled";
default:
throw new ArgumentOutOfRangeException(nameof(state), state, null);
}
builder.Entity<PullPaymentData>()
.HasIndex(o => o.StoreId);
builder.Entity<PullPaymentData>()
.HasOne(o => o.StoreData)
.WithMany(o => o.PullPayments).OnDelete(DeleteBehavior.Cascade);
}
}
}

View File

@ -13,7 +13,6 @@ namespace BTCPayServer.Data
public PullPaymentData PullPaymentData { get; set; }
public InvoiceData InvoiceData { get; set; }
internal static void OnModelCreating(ModelBuilder builder)
{
builder.Entity<RefundData>()

View File

@ -2,8 +2,14 @@ namespace BTCPayServer.Data
{
public class SettingData
{
public string Id { get; set; }
public string Id
{
get; set;
}
public string Value { get; set; }
public string Value
{
get; set;
}
}
}

View File

@ -5,6 +5,7 @@ using BTCPayServer.Client.Models;
namespace BTCPayServer.Data
{
public class StoreData
{
public string Id { get; set; }
@ -42,4 +43,6 @@ namespace BTCPayServer.Data
public List<PairedSINData> PairedSINs { get; set; }
public IEnumerable<APIKeyData> APIKeys { get; set; }
}
}

View File

@ -1,27 +0,0 @@
using Microsoft.EntityFrameworkCore;
namespace BTCPayServer.Data
{
public class StoreWebhookData
{
public string StoreId { get; set; }
public string WebhookId { get; set; }
public WebhookData Webhook { get; set; }
public StoreData Store { get; set; }
internal static void OnModelCreating(ModelBuilder builder)
{
builder.Entity<StoreWebhookData>()
.HasKey(p => new { p.StoreId, p.WebhookId });
builder.Entity<StoreWebhookData>()
.HasOne(o => o.Webhook)
.WithOne().OnDelete(DeleteBehavior.Cascade);
builder.Entity<StoreWebhookData>()
.HasOne(o => o.Store)
.WithOne().OnDelete(DeleteBehavior.Cascade);
}
}
}

View File

@ -12,6 +12,9 @@ namespace BTCPayServer.Data
public string StorageFileName { get; set; }
public DateTime Timestamp { get; set; }
public string ApplicationUserId { get; set; }
public ApplicationUser ApplicationUser { get; set; }
public ApplicationUser ApplicationUser
{
get; set;
}
}
}

View File

@ -4,13 +4,28 @@ namespace BTCPayServer.Data
{
public class UserStore
{
public string ApplicationUserId { get; set; }
public ApplicationUser ApplicationUser { get; set; }
public string StoreDataId { get; set; }
public StoreData StoreData { get; set; }
public string Role { get; set; }
public string ApplicationUserId
{
get; set;
}
public ApplicationUser ApplicationUser
{
get; set;
}
public string StoreDataId
{
get; set;
}
public StoreData StoreData
{
get; set;
}
public string Role
{
get;
set;
}
internal static void OnModelCreating(ModelBuilder builder)
{

View File

@ -1,4 +1,6 @@
using System.Collections.Generic;
using Microsoft.EntityFrameworkCore;
using Newtonsoft.Json;
namespace BTCPayServer.Data
{
@ -9,8 +11,6 @@ namespace BTCPayServer.Data
public string TransactionId { get; set; }
public string Labels { get; set; }
public byte[] Blob { get; set; }
internal static void OnModelCreating(ModelBuilder builder)
{
builder.Entity<WalletTransactionData>()
@ -26,4 +26,11 @@ namespace BTCPayServer.Data
.WithMany(w => w.WalletTransactions).OnDelete(DeleteBehavior.Cascade);
}
}
public class WalletTransactionInfo
{
public string Comment { get; set; } = string.Empty;
[JsonIgnore]
public HashSet<string> Labels { get; set; } = new HashSet<string>();
}
}

View File

@ -1,15 +0,0 @@
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
namespace BTCPayServer.Data
{
public class WebhookData
{
[Key]
[MaxLength(25)]
public string Id { get; set; }
[Required]
public byte[] Blob { get; set; }
public List<WebhookDeliveryData> Deliveries { get; set; }
}
}

View File

@ -1,32 +0,0 @@
using System;
using System.ComponentModel.DataAnnotations;
using Microsoft.EntityFrameworkCore;
namespace BTCPayServer.Data
{
public class WebhookDeliveryData
{
[Key]
[MaxLength(25)]
public string Id { get; set; }
[MaxLength(25)]
[Required]
public string WebhookId { get; set; }
public WebhookData Webhook { get; set; }
[Required]
public DateTimeOffset Timestamp { get; set; }
[Required]
public byte[] Blob { get; set; }
internal static void OnModelCreating(ModelBuilder builder)
{
builder.Entity<WebhookDeliveryData>()
.HasOne(o => o.Webhook)
.WithMany(a => a.Deliveries).OnDelete(DeleteBehavior.Cascade);
builder.Entity<WebhookDeliveryData>().HasIndex(o => o.WebhookId);
}
}
}

View File

@ -1,115 +0,0 @@
using System;
using BTCPayServer.Data;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
namespace BTCPayServer.Migrations
{
[DbContext(typeof(ApplicationDbContext))]
[Migration("20201108054749_webhooks")]
public partial class webhooks : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "Webhooks",
columns: table => new
{
Id = table.Column<string>(maxLength: 25, nullable: false),
Blob = table.Column<byte[]>(nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Webhooks", x => x.Id);
});
migrationBuilder.CreateTable(
name: "StoreWebhooks",
columns: table => new
{
StoreId = table.Column<string>(nullable: false),
WebhookId = table.Column<string>(nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_StoreWebhooks", x => new { x.StoreId, x.WebhookId });
table.ForeignKey(
name: "FK_StoreWebhooks_Stores_StoreId",
column: x => x.StoreId,
principalTable: "Stores",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_StoreWebhooks_Webhooks_WebhookId",
column: x => x.WebhookId,
principalTable: "Webhooks",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "WebhookDeliveries",
columns: table => new
{
Id = table.Column<string>(maxLength: 25, nullable: false),
WebhookId = table.Column<string>(maxLength: 25, nullable: false),
Timestamp = table.Column<DateTimeOffset>(nullable: false),
Blob = table.Column<byte[]>(nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_WebhookDeliveries", x => x.Id);
table.ForeignKey(
name: "FK_WebhookDeliveries_Webhooks_WebhookId",
column: x => x.WebhookId,
principalTable: "Webhooks",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "InvoiceWebhookDeliveries",
columns: table => new
{
InvoiceId = table.Column<string>(nullable: false),
DeliveryId = table.Column<string>(nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_InvoiceWebhookDeliveries", x => new { x.InvoiceId, x.DeliveryId });
table.ForeignKey(
name: "FK_InvoiceWebhookDeliveries_WebhookDeliveries_DeliveryId",
column: x => x.DeliveryId,
principalTable: "WebhookDeliveries",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_InvoiceWebhookDeliveries_Invoices_InvoiceId",
column: x => x.InvoiceId,
principalTable: "Invoices",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateIndex(
name: "IX_WebhookDeliveries_WebhookId",
table: "WebhookDeliveries",
column: "WebhookId");
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "InvoiceWebhookDeliveries");
migrationBuilder.DropTable(
name: "StoreWebhooks");
migrationBuilder.DropTable(
name: "WebhookDeliveries");
migrationBuilder.DropTable(
name: "Webhooks");
}
}
}

View File

@ -1,26 +0,0 @@
using BTCPayServer.Data;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
namespace BTCPayServer.Migrations
{
[DbContext(typeof(ApplicationDbContext))]
[Migration("20201208054211_invoicesorderindex")]
public partial class invoicesorderindex : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateIndex(
name: "IX_Invoices_OrderId",
table: "Invoices",
column: "OrderId");
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropIndex(
name: "IX_Invoices_OrderId",
table: "Invoices");
}
}
}

View File

@ -1,55 +0,0 @@
using BTCPayServer.Data;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
namespace BTCPayServer.Migrations
{
[DbContext(typeof(ApplicationDbContext))]
[Migration("20201228225040_AddingInvoiceSearchesTable")]
public partial class AddingInvoiceSearchesTable : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "InvoiceSearches",
columns: table => new
{
Id = table.Column<int>(nullable: false)
// manually added
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.SerialColumn)
.Annotation("MySql:ValueGeneratedOnAdd", true)
.Annotation("Sqlite:Autoincrement", true),
// eof manually added
InvoiceDataId = table.Column<string>(nullable: true),
Value = table.Column<string>(nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_InvoiceSearches", x => x.Id);
table.ForeignKey(
name: "FK_InvoiceSearches_Invoices_InvoiceDataId",
column: x => x.InvoiceDataId,
principalTable: "Invoices",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateIndex(
name: "IX_InvoiceSearches_InvoiceDataId",
table: "InvoiceSearches",
column: "InvoiceDataId");
migrationBuilder.CreateIndex(
name: "IX_InvoiceSearches_Value",
table: "InvoiceSearches",
column: "Value");
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "InvoiceSearches");
}
}
}

View File

@ -4,7 +4,6 @@ using BTCPayServer.Data;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
namespace BTCPayServer.Migrations
{
@ -229,8 +228,6 @@ namespace BTCPayServer.Migrations
b.HasKey("Id");
b.HasIndex("OrderId");
b.HasIndex("StoreDataId");
b.HasIndex("Id", "CurrentRefundId");
@ -260,49 +257,6 @@ namespace BTCPayServer.Migrations
b.ToTable("InvoiceEvents");
});
modelBuilder.Entity("BTCPayServer.Data.InvoiceSearchData", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER")
.HasAnnotation("MySql:ValueGeneratedOnAdd", true)
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.SerialColumn)
.HasAnnotation("Sqlite:Autoincrement", true);
b.Property<string>("InvoiceDataId")
.HasColumnType("TEXT");
b.Property<string>("Value")
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("InvoiceDataId");
b.HasIndex("Value");
b.ToTable("InvoiceSearches");
});
modelBuilder.Entity("BTCPayServer.Data.InvoiceWebhookDeliveryData", b =>
{
b.Property<string>("InvoiceId")
.HasColumnType("TEXT");
b.Property<string>("DeliveryId")
.HasColumnType("TEXT");
b.HasKey("InvoiceId", "DeliveryId");
b.HasIndex("DeliveryId")
.IsUnique();
b.HasIndex("InvoiceId")
.IsUnique();
b.ToTable("InvoiceWebhookDeliveries");
});
modelBuilder.Entity("BTCPayServer.Data.NotificationData", b =>
{
b.Property<string>("Id")
@ -634,25 +588,6 @@ namespace BTCPayServer.Migrations
b.ToTable("Stores");
});
modelBuilder.Entity("BTCPayServer.Data.StoreWebhookData", b =>
{
b.Property<string>("StoreId")
.HasColumnType("TEXT");
b.Property<string>("WebhookId")
.HasColumnType("TEXT");
b.HasKey("StoreId", "WebhookId");
b.HasIndex("StoreId")
.IsUnique();
b.HasIndex("WebhookId")
.IsUnique();
b.ToTable("StoreWebhooks");
});
modelBuilder.Entity("BTCPayServer.Data.StoredFile", b =>
{
b.Property<string>("Id")
@ -761,46 +696,6 @@ namespace BTCPayServer.Migrations
b.ToTable("WalletTransactions");
});
modelBuilder.Entity("BTCPayServer.Data.WebhookData", b =>
{
b.Property<string>("Id")
.HasColumnType("TEXT")
.HasMaxLength(25);
b.Property<byte[]>("Blob")
.IsRequired()
.HasColumnType("BLOB");
b.HasKey("Id");
b.ToTable("Webhooks");
});
modelBuilder.Entity("BTCPayServer.Data.WebhookDeliveryData", b =>
{
b.Property<string>("Id")
.HasColumnType("TEXT")
.HasMaxLength(25);
b.Property<byte[]>("Blob")
.IsRequired()
.HasColumnType("BLOB");
b.Property<DateTimeOffset>("Timestamp")
.HasColumnType("TEXT");
b.Property<string>("WebhookId")
.IsRequired()
.HasColumnType("TEXT")
.HasMaxLength(25);
b.HasKey("Id");
b.HasIndex("WebhookId");
b.ToTable("WebhookDeliveries");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b =>
{
b.Property<string>("Id")
@ -988,29 +883,6 @@ namespace BTCPayServer.Migrations
.IsRequired();
});
modelBuilder.Entity("BTCPayServer.Data.InvoiceSearchData", b =>
{
b.HasOne("BTCPayServer.Data.InvoiceData", "InvoiceData")
.WithMany("InvoiceSearchData")
.HasForeignKey("InvoiceDataId")
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity("BTCPayServer.Data.InvoiceWebhookDeliveryData", b =>
{
b.HasOne("BTCPayServer.Data.WebhookDeliveryData", "Delivery")
.WithOne()
.HasForeignKey("BTCPayServer.Data.InvoiceWebhookDeliveryData", "DeliveryId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("BTCPayServer.Data.InvoiceData", "Invoice")
.WithOne()
.HasForeignKey("BTCPayServer.Data.InvoiceWebhookDeliveryData", "InvoiceId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("BTCPayServer.Data.NotificationData", b =>
{
b.HasOne("BTCPayServer.Data.ApplicationUser", "ApplicationUser")
@ -1084,21 +956,6 @@ namespace BTCPayServer.Migrations
.IsRequired();
});
modelBuilder.Entity("BTCPayServer.Data.StoreWebhookData", b =>
{
b.HasOne("BTCPayServer.Data.StoreData", "Store")
.WithOne()
.HasForeignKey("BTCPayServer.Data.StoreWebhookData", "StoreId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("BTCPayServer.Data.WebhookData", "Webhook")
.WithOne()
.HasForeignKey("BTCPayServer.Data.StoreWebhookData", "WebhookId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("BTCPayServer.Data.StoredFile", b =>
{
b.HasOne("BTCPayServer.Data.ApplicationUser", "ApplicationUser")
@ -1138,15 +995,6 @@ namespace BTCPayServer.Migrations
.IsRequired();
});
modelBuilder.Entity("BTCPayServer.Data.WebhookDeliveryData", b =>
{
b.HasOne("BTCPayServer.Data.WebhookData", "Webhook")
.WithMany("Deliveries")
.HasForeignKey("WebhookId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null)

View File

@ -4,7 +4,7 @@ using System.IO.Compression;
using System.Linq;
using System.Reflection;
using System.Text.Json;
using BTCPayServer.Abstractions.Contracts;
using BTCPayServer.Contracts;
namespace BTCPayServer.PluginPacker
{
@ -43,7 +43,6 @@ namespace BTCPayServer.PluginPacker
}
ZipFile.CreateFromDirectory(directory, outputFile + ".btcpay", CompressionLevel.Optimal, false);
File.WriteAllText(outputFile + ".btcpay.json", json);
Console.WriteLine($"Created {outputFile}.btcpay at {directory}");
}
private static Type[] GetAllExtensionTypesFromAssembly(Assembly assembly)

View File

@ -12,8 +12,4 @@
<ProjectReference Include="..\BTCPayServer.Abstractions\BTCPayServer.Abstractions.csproj" />
<EmbeddedResource Include="Resources\**" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="3.1.4">
</PackageReference>
</ItemGroup>
</Project>

View File

@ -1,35 +0,0 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using BTCPayServer.Plugins.Test.Data;
using BTCPayServer.Plugins.Test.Services;
using Microsoft.AspNetCore.Mvc;
namespace BTCPayServer.Plugins.Test
{
[Route("extensions/test")]
public class TestExtensionController : Controller
{
private readonly TestPluginService _testPluginService;
public TestExtensionController(TestPluginService testPluginService)
{
_testPluginService = testPluginService;
}
// GET
public async Task<IActionResult> Index()
{
return View(new TestPluginPageViewModel()
{
Data = await _testPluginService.Get()
});
}
}
public class TestPluginPageViewModel
{
public List<TestPluginData> Data { get; set; }
}
}

View File

@ -1,14 +0,0 @@
using System;
using System.ComponentModel.DataAnnotations.Schema;
namespace BTCPayServer.Plugins.Test.Data
{
public class TestPluginData
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public string Id { get; set; }
public DateTimeOffset Timestamp { get; set; }
}
}

View File

@ -1,46 +0,0 @@
using System;
using System.Linq;
using BTCPayServer.Plugins.Test.Data;
using Microsoft.EntityFrameworkCore;
namespace BTCPayServer.Plugins.Test
{
public class TestPluginDbContext : DbContext
{
private readonly bool _designTime;
public DbSet<TestPluginData> TestPluginRecords { get; set; }
public TestPluginDbContext(DbContextOptions<TestPluginDbContext> options, bool designTime = false)
: base(options)
{
_designTime = designTime;
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.HasDefaultSchema("BTCPayServer.Plugins.Test");
if (Database.IsSqlite() && !_designTime)
{
// SQLite does not have proper support for DateTimeOffset via Entity Framework Core, see the limitations
// here: https://docs.microsoft.com/en-us/ef/core/providers/sqlite/limitations#query-limitations
// To work around this, when the Sqlite database provider is used, all model properties of type DateTimeOffset
// use the DateTimeOffsetToBinaryConverter
// Based on: https://github.com/aspnet/EntityFrameworkCore/issues/10784#issuecomment-415769754
// This only supports millisecond precision, but should be sufficient for most use cases.
foreach (var entityType in modelBuilder.Model.GetEntityTypes())
{
var properties = entityType.ClrType.GetProperties().Where(p => p.PropertyType == typeof(DateTimeOffset));
foreach (var property in properties)
{
modelBuilder
.Entity(entityType.Name)
.Property(property.Name)
.HasConversion(new Microsoft.EntityFrameworkCore.Storage.ValueConversion.DateTimeOffsetToBinaryConverter());
}
}
}
}
}
}

View File

@ -1,37 +0,0 @@
using System;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
namespace BTCPayServer.Plugins.Test.Migrations
{
[DbContext(typeof(TestPluginDbContext))]
[Migration("20201117154419_Init")]
public partial class Init : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.EnsureSchema(
name: "BTCPayServer.Plugins.Test");
migrationBuilder.CreateTable(
name: "TestPluginRecords",
schema: "BTCPayServer.Plugins.Test",
columns: table => new
{
Id = table.Column<string>(nullable: false),
Timestamp = table.Column<DateTimeOffset>(nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_TestPluginRecords", x => x.Id);
});
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "TestPluginRecords",
schema: "BTCPayServer.Plugins.Test");
}
}
}

View File

@ -1,36 +0,0 @@
// <auto-generated />
using System;
using BTCPayServer.Plugins.Test;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
namespace BTCPayServer.Plugins.Test.Migrations
{
[DbContext(typeof(TestPluginDbContext))]
partial class TestPluginDbContextModelSnapshot : ModelSnapshot
{
protected override void BuildModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasDefaultSchema("BTCPayServer.Plugins.Test")
.HasAnnotation("ProductVersion", "3.1.10");
modelBuilder.Entity("BTCPayServer.Plugins.Test.Data.TestPluginData", b =>
{
b.Property<string>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("TEXT");
b.Property<DateTimeOffset>("Timestamp")
.HasColumnType("TEXT");
b.HasKey("Id");
b.ToTable("TestPluginRecords");
});
#pragma warning restore 612, 618
}
}
}

Some files were not shown because too many files have changed in this diff Show More