initial commit

This commit is contained in:
Kukks
2023-01-16 10:31:48 +01:00
parent 136273406c
commit 25ccd99558
171 changed files with 10592 additions and 0 deletions

View File

@@ -0,0 +1,40 @@
<Project Sdk="Microsoft.NET.Sdk.Razor">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<LangVersion>10</LangVersion>
</PropertyGroup>
<!-- Plugin specific properties -->
<PropertyGroup>
<Title>FixedFloat</Title>
<Description>Allows you to embed a FixedFloat conversion screen to allow customers to pay with altcoins.</Description>
<Authors>Kukks</Authors>
<Version>1.0.6</Version>
</PropertyGroup>
<!-- Plugin development properties -->
<PropertyGroup>
<AddRazorSupportForMvc>true</AddRazorSupportForMvc>
<PreserveCompilationContext>false</PreserveCompilationContext>
<GenerateEmbeddedFilesManifest>true</GenerateEmbeddedFilesManifest>
</PropertyGroup>
<!-- This will make sure that referencing BTCPayServer doesn't put any artifact in the published directory -->
<ItemDefinitionGroup>
<ProjectReference>
<Properties>StaticWebAssetsEnabled=false</Properties>
<Private>false</Private>
<ExcludeAssets>runtime;native;build;buildTransitive;contentFiles</ExcludeAssets>
</ProjectReference>
</ItemDefinitionGroup>
<ItemGroup>
<FrameworkReference Include="Microsoft.AspNetCore.App" />
<ProjectReference Include="..\..\submodules\btcpayserver\BTCPayServer\BTCPayServer.csproj" />
<EmbeddedResource Include="Resources\**" />
</ItemGroup>
<ItemGroup>
<Folder Include="Views\Shared" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,81 @@
using System;
using System.Threading.Tasks;
using BTCPayServer.Abstractions.Constants;
using BTCPayServer.Client;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
namespace BTCPayServer.Plugins.FixedFloat
{
[Authorize(AuthenticationSchemes = AuthenticationSchemes.Cookie)]
[Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Cookie)]
[Route("plugins/{storeId}/FixedFloat")]
public class FixedFloatController : Controller
{
private readonly BTCPayServerClient _btcPayServerClient;
private readonly FixedFloatService _FixedFloatService;
public FixedFloatController(BTCPayServerClient btcPayServerClient, FixedFloatService FixedFloatService)
{
_btcPayServerClient = btcPayServerClient;
_FixedFloatService = FixedFloatService;
}
[HttpGet("")]
public async Task<IActionResult> UpdateFixedFloatSettings(string storeId)
{
var store = await _btcPayServerClient.GetStore(storeId);
UpdateFixedFloatSettingsViewModel vm = new UpdateFixedFloatSettingsViewModel();
vm.StoreName = store.Name;
FixedFloatSettings FixedFloat = null;
try
{
FixedFloat = await _FixedFloatService.GetFixedFloatForStore(storeId);
}
catch (Exception)
{
// ignored
}
SetExistingValues(FixedFloat, vm);
return View(vm);
}
private void SetExistingValues(FixedFloatSettings existing, UpdateFixedFloatSettingsViewModel vm)
{
if (existing == null)
return;
vm.Enabled = existing.Enabled;
}
[HttpPost("")]
public async Task<IActionResult> UpdateFixedFloatSettings(string storeId, UpdateFixedFloatSettingsViewModel vm,
string command)
{
if (vm.Enabled)
{
if (!ModelState.IsValid)
{
return View(vm);
}
}
var FixedFloatSettings = new FixedFloatSettings()
{
Enabled = vm.Enabled,
};
switch (command)
{
case "save":
await _FixedFloatService.SetFixedFloatForStore(storeId, FixedFloatSettings);
TempData["SuccessMessage"] = "FixedFloat settings modified";
return RedirectToAction(nameof(UpdateFixedFloatSettings), new {storeId});
default:
return View(vm);
}
}
}
}

View File

@@ -0,0 +1,48 @@
using BTCPayServer.Abstractions.Contracts;
using BTCPayServer.Abstractions.Models;
using BTCPayServer.Abstractions.Services;
using Microsoft.Extensions.DependencyInjection;
namespace BTCPayServer.Plugins.FixedFloat
{
public class FixedFloatPlugin : BaseBTCPayServerPlugin
{
public override string Identifier => "BTCPayServer.Plugins.FixedFloat";
public override string Name => "FixedFloat";
public override IBTCPayServerPlugin.PluginDependency[] Dependencies { get; } =
{
new() { Identifier = nameof(BTCPayServer), Condition = ">=1.7.0.0" }
};
public override string Description =>
"Allows you to embed a FixedFloat conversion screen to allow customers to pay with altcoins.";
public override void Execute(IServiceCollection applicationBuilder)
{
applicationBuilder.AddSingleton<FixedFloatService>();
applicationBuilder.AddSingleton<IUIExtension>(new UIExtension("FixedFloat/FixedFloatNav",
"store-integrations-nav"));
applicationBuilder.AddSingleton<IUIExtension>(new UIExtension("FixedFloat/StoreIntegrationFixedFloatOption",
"store-integrations-list"));
// Checkout v2
applicationBuilder.AddSingleton<IUIExtension>(new UIExtension("FixedFloat/CheckoutPaymentMethodExtension",
"checkout-payment-method"));
applicationBuilder.AddSingleton<IUIExtension>(new UIExtension("FixedFloat/CheckoutPaymentExtension",
"checkout-payment"));
// Checkout Classic
applicationBuilder.AddSingleton<IUIExtension>(new UIExtension("FixedFloat/CheckoutContentExtension",
"checkout-bitcoin-post-content"));
applicationBuilder.AddSingleton<IUIExtension>(new UIExtension("FixedFloat/CheckoutContentExtension",
"checkout-lightning-post-content"));
applicationBuilder.AddSingleton<IUIExtension>(new UIExtension("FixedFloat/CheckoutTabExtension",
"checkout-bitcoin-post-tabs"));
applicationBuilder.AddSingleton<IUIExtension>(new UIExtension("FixedFloat/CheckoutTabExtension",
"checkout-lightning-post-tabs"));
applicationBuilder.AddSingleton<IUIExtension>(new UIExtension("FixedFloat/CheckoutEnd",
"checkout-end"));
base.Execute(applicationBuilder);
}
}
}

View File

@@ -0,0 +1,46 @@
using System.Threading.Tasks;
using BTCPayServer.Abstractions.Contracts;
using Microsoft.Extensions.Caching.Memory;
namespace BTCPayServer.Plugins.FixedFloat
{
public class FixedFloatService
{
private readonly ISettingsRepository _settingsRepository;
private readonly IStoreRepository _storeRepository;
private readonly IMemoryCache _memoryCache;
public FixedFloatService(ISettingsRepository settingsRepository, IStoreRepository storeRepository, IMemoryCache memoryCache)
{
_settingsRepository = settingsRepository;
_storeRepository = storeRepository;
_memoryCache = memoryCache;
}
public async Task<FixedFloatSettings> GetFixedFloatForStore(string storeId)
{
var k = $"{nameof(FixedFloatSettings)}_{storeId}";
return await _memoryCache.GetOrCreateAsync(k, async _ =>
{
var res = await _storeRepository.GetSettingAsync<FixedFloatSettings>(storeId,
nameof(FixedFloatSettings));
if (res is not null) return res;
res = await _settingsRepository.GetSettingAsync<FixedFloatSettings>(k);
if (res is not null)
{
await SetFixedFloatForStore(storeId, res);
}
await _settingsRepository.UpdateSetting<FixedFloatSettings>(null, k);
return res;
});
}
public async Task SetFixedFloatForStore(string storeId, FixedFloatSettings fixedFloatSettings)
{
var k = $"{nameof(FixedFloatSettings)}_{storeId}";
await _storeRepository.UpdateSetting(storeId, nameof(FixedFloatSettings), fixedFloatSettings);
_memoryCache.Set(k, fixedFloatSettings);
}
}
}

View File

@@ -0,0 +1,8 @@
namespace BTCPayServer.Plugins.FixedFloat
{
public class FixedFloatSettings
{
public bool Enabled { get; set; }
public decimal AmountMarkupPercentage { get; set; } = 0;
}
}

View File

@@ -0,0 +1,2 @@
dotnet publish -c Altcoins-Release -o bin/publish/BTCPayServer.Plugins.FixedFloat
dotnet run -p ../../BTCPayServer.PluginPacker bin/publish/BTCPayServer.Plugins.FixedFloat BTCPayServer.Plugins.FixedFloat ../packed

Binary file not shown.

After

Width:  |  Height:  |  Size: 747 B

View File

@@ -0,0 +1,35 @@
Vue.component("fixed-float", {
props: ["toCurrency", "toCurrencyDue", "toCurrencyAddress"],
data() {
return {
shown: false,
};
},
computed: {
url() {
let settleMethodId = "";
if (
this.toCurrency.endsWith("LightningLike") ||
this.toCurrency.endsWith("LNURLPay")
) {
settleMethodId = "BTCLN";
} else {
settleMethodId = this.toCurrency
.replace("_BTCLike", "")
.replace("_MoneroLike", "")
.replace("_ZcashLike", "")
.toUpperCase();
}
const topup = this.$parent.srvModel.isUnsetTopUp;
return (
"https://widget.fixedfloat.com/?" +
`to=${settleMethodId}` +
"&lockReceive=true&ref=fkbyt39c" +
`&address=${this.toCurrencyAddress}` +
(topup
? ""
: `&lockType=true&hideType=true&lockAmount=true&toAmount=${this.toCurrencyDue}`)
);
},
},
});

View File

@@ -0,0 +1,8 @@
namespace BTCPayServer.Plugins.FixedFloat
{
public class UpdateFixedFloatSettingsViewModel
{
public bool Enabled { get; set; }
public string StoreName { get; set; }
}
}

View File

@@ -0,0 +1,28 @@
@using BTCPayServer.Abstractions.Extensions
@using Microsoft.AspNetCore.Mvc.TagHelpers
@model BTCPayServer.Plugins.FixedFloat.UpdateFixedFloatSettingsViewModel
@{
ViewData.SetActivePage("FixedFloat", "FixedFloat", "FixedFloat");
}
<partial name="_StatusMessage" />
<h2 class="mb-4">@ViewData["Title"]</h2>
<div class="alert alert-warning mb-4" role="alert">
If you are enabling FixedFloat support, we advise that you configure the invoice expiration to a minimum of 30 minutes as it may take longer than the default 15 minutes to convert the funds.
</div>
<div class="row">
<div class="col-md-10">
<form method="post">
<div class="form-group">
<div class="d-flex align-items-center">
<input asp-for="Enabled" type="checkbox" class="btcpay-toggle me-2"/>
<label asp-for="Enabled" class="form-label mb-0 me-1"></label>
</div>
</div>
<button name="command" type="submit" value="save" class="btn btn-primary">Submit</button>
</form>
</div>
</div>

View File

@@ -0,0 +1,19 @@
@using BTCPayServer.Plugins.FixedFloat
@using Newtonsoft.Json
@using Newtonsoft.Json.Linq
@inject FixedFloatService FixedFloatService
@{
var storeId = ((JObject)JObject.Parse(JsonConvert.SerializeObject(Model)))["StoreId"].Value<string>();
var settings = await FixedFloatService.GetFixedFloatForStore(storeId);
if (settings?.Enabled is true)
{
<div id="FixedFloat" class="bp-view payment manual-flow" style="padding:0" :class="{ active: currentTab == 'undefined' || currentTab == 'FixedFloat' }">
<fixed-float inline-template
:to-currency="srvModel.paymentMethodId"
:to-currency-due="srvModel.btcDue * (1 + (@settings.AmountMarkupPercentage / 100)) "
:to-currency-address="srvModel.btcAddress">
<iframe :src="url" style="min-height:600px;width:100%;border:none" allowtransparency="true"></iframe>
</fixed-float>
</div>
}
}

View File

@@ -0,0 +1,12 @@
@using BTCPayServer.Plugins.FixedFloat
@using Newtonsoft.Json
@using Newtonsoft.Json.Linq
@inject FixedFloatService FixedFloatService
@{
var storeId = ((JObject)JObject.Parse(JsonConvert.SerializeObject(Model)))["StoreId"].Value<string>();
var settings = await FixedFloatService.GetFixedFloatForStore(storeId);
if (settings?.Enabled is true)
{
<script src="~/Resources/js/fixedFloatComponent.js"></script>
}
}

View File

@@ -0,0 +1,46 @@
@using BTCPayServer.Plugins.FixedFloat
@using Newtonsoft.Json
@using Newtonsoft.Json.Linq
@inject FixedFloatService FixedFloatService
@{
var storeId = ((JObject)JObject.Parse(JsonConvert.SerializeObject(Model)))["StoreId"].Value<string>();
var settings = await FixedFloatService.GetFixedFloatForStore(storeId);
}
@if (settings?.Enabled is true)
{
<template id="fixed-float-checkout-template">
<iframe :src="url" style="min-height:600px;width:100%;border:none" allowtransparency="true"></iframe>
</template>
<script>
const markupPercentage = @settings.AmountMarkupPercentage;
Vue.component("FixedFloatCheckout", {
template: "#fixed-float-checkout-template",
props: ["model"],
computed: {
url () {
return "https://widget.fixedfloat.com/?" +
`to=${this.settleMethodId}` +
"&lockReceive=true&ref=fkbyt39c" +
`&address=${this.model.btcAddress}` +
this.amountQuery;
},
currency () {
return this.model.paymentMethodId;
},
settleMethodId () {
return this.currency.endsWith('LightningLike') || this.currency.endsWith('LNURLPay')
? 'BTCLN'
: this.currency.replace('_BTCLike', '').replace('_MoneroLike', '').replace('_ZcashLike', '').toUpperCase();
},
amountQuery () {
return this.model.isUnsetTopUp
? ''
: `&lockType=true&hideType=true&lockAmount=true&toAmount=${this.amountDue}`;
},
amountDue () {
return this.model.btcDue * (1 + (markupPercentage / 100));
}
}
});
</script>
}

View File

@@ -0,0 +1,16 @@
@using BTCPayServer.Plugins.FixedFloat
@using Newtonsoft.Json
@using Newtonsoft.Json.Linq
@inject FixedFloatService FixedFloatService
@{
const string id = "FixedFloat";
var storeId = ((JObject)JObject.Parse(JsonConvert.SerializeObject(Model)))["StoreId"].Value<string>();
var settings = await FixedFloatService.GetFixedFloatForStore(storeId);
if (settings?.Enabled is true)
{
<a href="#@id" class="btcpay-pill m-0 payment-method" :class="{ active: pmId === '@id' }" v-on:click.prevent="changePaymentMethod('@id')">
@id
</a>
}
}

View File

@@ -0,0 +1,14 @@
@using BTCPayServer.Plugins.FixedFloat
@using Newtonsoft.Json
@using Newtonsoft.Json.Linq
@inject FixedFloatService FixedFloatService
@{
var storeId = ((JObject)JObject.Parse(JsonConvert.SerializeObject(Model)))["StoreId"].Value<string>();
var settings = await FixedFloatService.GetFixedFloatForStore(storeId);
if (settings?.Enabled is true)
{
<div class="payment-tabs__tab py-0" id="FixedFloat-tab" v-on:click="switchTab('FixedFloat')" v-bind:class="{ 'active': currentTab == 'FixedFloat'}" v-if="!srvModel.paymentMethodId.endsWith('LNURLPAY')">
<span>{{$t("Altcoins (FixedFloat)")}}</span>
</div>
}
}

View File

@@ -0,0 +1,16 @@
@using BTCPayServer.Abstractions.Contracts
@using BTCPayServer.Abstractions.Extensions
@using Microsoft.AspNetCore.Mvc.TagHelpers
@inject IScopeProvider ScopeProvider
@{
var storeId = ScopeProvider.GetCurrentStoreId();
}
@if (!string.IsNullOrEmpty(storeId))
{
<li class="nav-item">
<a asp-area="" asp-controller="FixedFloat" asp-action="UpdateFixedFloatSettings" asp-route-storeId="@storeId" class="nav-link @ViewData.IsActivePage("FixedFloat")" id="Nav-FixedFloat">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 160 160" alt="FixedFloat" class="icon"><g transform="translate(-20,-20)"><path fill="currentColor" d="m111.6 96.1-9.6-9.6-9.5-9.5a4.7 4.7 0 0 0-3.3-1.4c-1.2 0-2.4.5-3.3 1.4L73.6 89.3l-12.3 12.3-3.9-3.9-3.9-3.9c-.7-.7-1.6-.8-2.3-.5-.7.3-1.3 1-1.3 1.9V138a2.04 2.04 0 0 0 2.1 2.1h42.6c.9 0 1.6-.6 1.9-1.3.3-.7.2-1.6-.5-2.3l-4.6-4.6-4.6-4.6L99.3 115l12.3-12.3c.9-.9 1.4-2.1 1.4-3.3 0-1.2-.5-2.4-1.4-3.3z"/><path fill="currentColor" d="M107.1 133.4c-1.2 0-2.3-.4-3.2-1.3a4.47 4.47 0 0 1 0-6.4l27.6-27.6c1.8-1.8 4.6-1.8 6.4 0l3 3V68.9h-32.3l3.1 3.1c1.8 1.8 1.8 4.6 0 6.4a4.47 4.47 0 0 1-6.4 0L94.6 67.6a4.47 4.47 0 0 1-1-4.9c.7-1.7 2.3-2.8 4.2-2.8h47.7c2.5 0 4.5 2 4.5 4.5v47.7c0 1.8-1.1 3.5-2.8 4.2-1.7.7-3.6.3-4.9-1l-7.6-7.6-24.4 24.4c-.8.9-2 1.3-3.2 1.3z"/></g></svg>
<span>FixedFloat</span>
</a>
</li>
}

View File

@@ -0,0 +1,58 @@
@using BTCPayServer.Abstractions.Contracts
@using BTCPayServer.Plugins.FixedFloat
@using Microsoft.AspNetCore.Routing
@inject FixedFloatService FixedFloatService
@inject IScopeProvider ScopeProvider
@{
var storeId = ScopeProvider.GetCurrentStoreId();
FixedFloatSettings settings = null;
if (!string.IsNullOrEmpty(storeId))
{
try
{
settings = await FixedFloatService.GetFixedFloatForStore(storeId);
}
catch (Exception)
{
}
}
}
@if (!string.IsNullOrEmpty(storeId))
{
<li class="list-group-item bg-tile ">
<div class="d-flex align-items-center">
<span class="d-flex flex-wrap flex-fill flex-column flex-sm-row">
<strong class="me-3">
FixedFloat
</strong>
<span title="" class="d-flex me-3">
<span class="text-secondary">Allows your customers to pay with altcoins that are not supported by BTCPay Server.</span>
</span>
</span>
<span class="d-flex align-items-center fw-semibold">
@if (settings?.Enabled is true)
{
<span class="d-flex align-items-center text-success">
<span class="me-2 btcpay-status btcpay-status--enabled"></span>
Enabled
</span>
<span class="text-light ms-3 me-2">|</span>
<a lass="btn btn-link px-1 py-1 fw-semibold" asp-controller="FixedFloat" asp-action="UpdateFixedFloatSettings" asp-route-storeId="@storeId">
Modify
</a>
}
else
{
<span class="d-flex align-items-center text-danger">
<span class="me-2 btcpay-status btcpay-status--disabled"></span>
Disabled
</span>
<a class="btn btn-primary btn-sm ms-4 px-3 py-1 fw-semibold" asp-controller="FixedFloat" asp-action="UpdateFixedFloatSettings" asp-route-storeId="@storeId">
Setup
</a>
}
</span>
</div>
</li>
}

View File

@@ -0,0 +1,2 @@
@addTagHelper *, BTCPayServer.Abstractions
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers