Compare commits
24 Commits
role-prote
...
changlog
Author | SHA1 | Date | |
---|---|---|---|
6d0f9120b8 | |||
aafb4a7f2a | |||
ae432ff237 | |||
cdc318c71a | |||
94d1cec8a9 | |||
c0bc19ea59 | |||
6f07714cd9 | |||
a9d2cac23c | |||
693b46126b | |||
bbff9710bf | |||
358e122775 | |||
3818468932 | |||
3d2554fbe1 | |||
4309603317 | |||
f733c9ea77 | |||
775ee01171 | |||
33ec790137 | |||
0c575c888c | |||
24f7e51e3a | |||
0a0cf97c55 | |||
16b988d097 | |||
5edc0ff6ef | |||
375b96e508 | |||
1e72b12074 |
@ -12,6 +12,8 @@
|
||||
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
||||
<RepositoryUrl>https://github.com/btcpayserver/btcpayserver</RepositoryUrl>
|
||||
<RepositoryType>git</RepositoryType>
|
||||
<Configurations>Debug;Release;Altcoins-Debug;Altcoins-Release</Configurations>
|
||||
<Platforms>AnyCPU</Platforms>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<Version Condition=" '$(Version)' == '' ">1.7.2</Version>
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
<ItemGroup>
|
||||
<FrameworkReference Include="Microsoft.AspNetCore.App" />
|
||||
<PackageReference Include="NBXplorer.Client" Version="4.2.3" />
|
||||
<PackageReference Include="NBXplorer.Client" Version="4.2.5" />
|
||||
<PackageReference Include="NicolasDorier.StandardConfiguration" Version="2.0.1" />
|
||||
</ItemGroup>
|
||||
<ItemGroup Condition="'$(Altcoins)' != 'true'">
|
||||
|
@ -306,6 +306,8 @@ retry:
|
||||
foreach ((CurrencyPair key, Task<RateResult> value) in result)
|
||||
{
|
||||
var rateResult = value.GetAwaiter().GetResult();
|
||||
if (key.ToString() == "BTG_USD")
|
||||
continue; // shitcoin not supported by bitfinex anymore
|
||||
TestLogs.LogInformation($"Testing {key}");
|
||||
if (brokenShitcoins.Contains(key.ToString()))
|
||||
continue;
|
||||
|
@ -73,7 +73,7 @@ services:
|
||||
- "sshd_datadir:/root/.ssh"
|
||||
|
||||
devlnd:
|
||||
image: btcpayserver/bitcoin:24.1-1
|
||||
image: btcpayserver/bitcoin:25.0
|
||||
environment:
|
||||
BITCOIN_NETWORK: regtest
|
||||
BITCOIN_WALLETDIR: "/data/wallets"
|
||||
@ -135,7 +135,7 @@ services:
|
||||
|
||||
bitcoind:
|
||||
restart: unless-stopped
|
||||
image: btcpayserver/bitcoin:24.1-1
|
||||
image: btcpayserver/bitcoin:25.0
|
||||
environment:
|
||||
BITCOIN_NETWORK: regtest
|
||||
BITCOIN_WALLETDIR: "/data/wallets"
|
||||
|
@ -70,7 +70,7 @@ services:
|
||||
- "sshd_datadir:/root/.ssh"
|
||||
|
||||
devlnd:
|
||||
image: btcpayserver/bitcoin:24.1-1
|
||||
image: btcpayserver/bitcoin:25.0
|
||||
environment:
|
||||
BITCOIN_NETWORK: regtest
|
||||
BITCOIN_WALLETDIR: "/data/wallets"
|
||||
@ -121,7 +121,7 @@ services:
|
||||
|
||||
bitcoind:
|
||||
restart: unless-stopped
|
||||
image: btcpayserver/bitcoin:24.1-1
|
||||
image: btcpayserver/bitcoin:25.0
|
||||
environment:
|
||||
BITCOIN_NETWORK: regtest
|
||||
BITCOIN_WALLETDIR: "/data/wallets"
|
||||
|
@ -23,15 +23,17 @@
|
||||
@if (Model.Balance.OffchainBalance != null)
|
||||
{
|
||||
<div class="balance">
|
||||
<h3 class="d-inline-block me-1" data-balance="@Model.TotalOffchain" data-sensitive>@Model.TotalOffchain</h3>
|
||||
<span class="text-secondary fw-semibold text-nowrap">
|
||||
<span class="currency">@Model.CryptoCode</span> in channels
|
||||
</span>
|
||||
<div class="d-flex align-items-baseline gap-1">
|
||||
<h3 class="d-inline-block me-1" data-balance="@Model.TotalOffchain" data-sensitive>@Model.TotalOffchain</h3>
|
||||
<span class="text-secondary fw-semibold text-nowrap">
|
||||
<span class="currency">@Model.CryptoCode</span> in channels
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="balance-details collapse" id="balanceDetailsOffchain">
|
||||
@if (Model.Balance.OffchainBalance.Opening != null)
|
||||
{
|
||||
<div class="mt-2">
|
||||
<div class="mt-2 d-flex align-items-baseline gap-1">
|
||||
<span class="fw-semibold" data-balance="@Model.Balance.OffchainBalance.Opening" data-sensitive>
|
||||
@Model.Balance.OffchainBalance.Opening
|
||||
</span>
|
||||
@ -42,7 +44,7 @@
|
||||
}
|
||||
@if (Model.Balance.OffchainBalance.Local != null)
|
||||
{
|
||||
<div class="mt-2">
|
||||
<div class="mt-2 d-flex align-items-baseline gap-1">
|
||||
<span class="fw-semibold" data-balance="@Model.Balance.OffchainBalance.Local" data-sensitive>
|
||||
@Model.Balance.OffchainBalance.Local
|
||||
</span>
|
||||
@ -53,7 +55,7 @@
|
||||
}
|
||||
@if (Model.Balance.OffchainBalance.Remote != null)
|
||||
{
|
||||
<div class="mt-2">
|
||||
<div class="mt-2 d-flex align-items-baseline gap-1">
|
||||
<span class="fw-semibold" data-balance="@Model.Balance.OffchainBalance.Remote" data-sensitive>
|
||||
@Model.Balance.OffchainBalance.Remote
|
||||
</span>
|
||||
@ -64,7 +66,7 @@
|
||||
}
|
||||
@if (Model.Balance.OffchainBalance.Closing != null)
|
||||
{
|
||||
<div class="mt-2">
|
||||
<div class="mt-2 d-flex align-items-baseline gap-1">
|
||||
<span class="fw-semibold" data-balance="@Model.Balance.OffchainBalance.Closing" data-sensitive>
|
||||
@Model.Balance.OffchainBalance.Closing
|
||||
</span>
|
||||
@ -79,14 +81,16 @@
|
||||
@if (Model.Balance.OnchainBalance != null)
|
||||
{
|
||||
<div class="balance">
|
||||
<h3 class="d-inline-block me-1" data-balance="@Model.TotalOnchain" data-sensitive>@Model.TotalOnchain</h3>
|
||||
<span class="text-secondary fw-semibold text-nowrap">
|
||||
<span class="currency">@Model.CryptoCode</span> on-chain
|
||||
</span>
|
||||
<div class="d-flex align-items-baseline gap-1">
|
||||
<h3 class="d-inline-block me-1" data-balance="@Model.TotalOnchain" data-sensitive>@Model.TotalOnchain</h3>
|
||||
<span class="text-secondary fw-semibold text-nowrap">
|
||||
<span class="currency">@Model.CryptoCode</span> on-chain
|
||||
</span>
|
||||
</div>
|
||||
<div class="balance-details collapse" id="balanceDetailsOnchain">
|
||||
@if (Model.Balance.OnchainBalance.Confirmed != null)
|
||||
{
|
||||
<div class="mt-2">
|
||||
<div class="mt-2 d-flex align-items-baseline gap-1">
|
||||
<span class="fw-semibold" data-balance="@Model.Balance.OnchainBalance.Confirmed" data-sensitive>
|
||||
@Model.Balance.OnchainBalance.Confirmed
|
||||
</span>
|
||||
@ -97,7 +101,7 @@
|
||||
}
|
||||
@if (Model.Balance.OnchainBalance.Unconfirmed != null)
|
||||
{
|
||||
<div class="mt-2">
|
||||
<div class="mt-2 d-flex align-items-baseline gap-1">
|
||||
<span class="fw-semibold" data-balance="@Model.Balance.OnchainBalance.Unconfirmed" data-sensitive>
|
||||
@Model.Balance.OnchainBalance.Unconfirmed
|
||||
</span>
|
||||
@ -108,7 +112,7 @@
|
||||
}
|
||||
@if (Model.Balance.OnchainBalance.Reserved != null)
|
||||
{
|
||||
<div class="mt-2">
|
||||
<div class="mt-2 d-flex align-items-baseline gap-1">
|
||||
<span class="fw-semibold" data-balance="@Model.Balance.OnchainBalance.Reserved" data-sensitive>
|
||||
@Model.Balance.OnchainBalance.Reserved
|
||||
</span>
|
||||
|
@ -3,7 +3,6 @@
|
||||
@using BTCPayServer.Abstractions.Contracts
|
||||
@using BTCPayServer.Client
|
||||
@using BTCPayServer.Services
|
||||
@inject SignInManager<ApplicationUser> SignInManager
|
||||
@inject BTCPayServerEnvironment Env
|
||||
@inject IFileService FileService
|
||||
@model BTCPayServer.Components.StoreSelector.StoreSelectorViewModel
|
||||
@ -33,8 +32,7 @@
|
||||
else
|
||||
{
|
||||
<a asp-controller="UIStores" asp-action="Dashboard" permission="@Policies.CanModifyStoreSettings" asp-route-storeId="@Model.CurrentStoreId" id="StoreSelectorHome" class="navbar-brand py-2">@{await LogoContent();}</a>
|
||||
|
||||
<a asp-controller="UIInvoice" asp-action="ListInvoices" not-permission="@Policies.CanModifyStoreSettings" asp-route-storeId="@Model.CurrentStoreId" id="StoreSelectorHome" class="navbar-brand py-2">@{await LogoContent();}</a>
|
||||
<a asp-controller="UIInvoice" asp-action="ListInvoices" not-permission="@Policies.CanModifyStoreSettings" asp-route-storeId="@Model.CurrentStoreId" id="StoreSelectorHome" class="navbar-brand py-2">@{await LogoContent();}</a>
|
||||
}
|
||||
@if (Model.Options.Any())
|
||||
{
|
||||
|
@ -1,5 +1,6 @@
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Client;
|
||||
using BTCPayServer.Data;
|
||||
using BTCPayServer.Services.Stores;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
@ -38,12 +39,14 @@ namespace BTCPayServer.Components.StoreSelector
|
||||
.FirstOrDefault()?
|
||||
.Network.CryptoCode;
|
||||
var walletId = cryptoCode != null ? new WalletId(store.Id, cryptoCode) : null;
|
||||
var role = store.GetStoreRoleOfUser(userId);
|
||||
return new StoreSelectorOption
|
||||
{
|
||||
Text = store.StoreName,
|
||||
Value = store.Id,
|
||||
Selected = store.Id == currentStore?.Id,
|
||||
WalletId = walletId
|
||||
WalletId = walletId,
|
||||
IsOwner = role != null && role.Permissions.Contains(Policies.CanModifyStoreSettings)
|
||||
};
|
||||
})
|
||||
.OrderBy(s => s.Text)
|
||||
|
@ -17,7 +17,7 @@
|
||||
<header class="mb-3">
|
||||
@if (Model.Balance != null)
|
||||
{
|
||||
<div class="balance">
|
||||
<div class="balance d-flex align-items-baseline gap-1">
|
||||
<h3 class="d-inline-block me-1" data-balance="@Model.Balance" data-sensitive>@Model.Balance</h3>
|
||||
<span class="text-secondary fw-semibold currency">@Model.CryptoCode</span>
|
||||
</div>
|
||||
|
@ -3,7 +3,6 @@ using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Amazon.S3.Transfer;
|
||||
using BTCPayServer.Abstractions.Constants;
|
||||
using BTCPayServer.Abstractions.Extensions;
|
||||
using BTCPayServer.Abstractions.Models;
|
||||
@ -167,9 +166,17 @@ namespace BTCPayServer.Controllers
|
||||
[FromServices] StoreRepository storeRepository,
|
||||
string role)
|
||||
{
|
||||
await storeRepository.SetDefaultRole(role);
|
||||
|
||||
TempData[WellKnownTempData.SuccessMessage] = "Role set default";
|
||||
var resolved = await storeRepository.ResolveStoreRoleId(null, role);
|
||||
if (resolved is null)
|
||||
{
|
||||
TempData[WellKnownTempData.ErrorMessage] = "Role could not be set as default";
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
await storeRepository.SetDefaultRole(role);
|
||||
TempData[WellKnownTempData.SuccessMessage] = "Role set default";
|
||||
}
|
||||
|
||||
return RedirectToAction(nameof(ListRoles));
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
@ -250,7 +251,7 @@ namespace BTCPayServer.Controllers
|
||||
CryptoCode = cryptoCode,
|
||||
Method = method,
|
||||
SetupRequest = request,
|
||||
Confirmation = string.IsNullOrEmpty(request.ExistingMnemonic),
|
||||
Confirmation = !isImport,
|
||||
Network = network,
|
||||
Source = isImport ? "SeedImported" : "NBXplorerGenerated",
|
||||
IsHotWallet = isImport ? request.SavePrivateKeys : method == WalletSetupMethod.HotWallet,
|
||||
@ -311,7 +312,7 @@ namespace BTCPayServer.Controllers
|
||||
|
||||
var result = await UpdateWallet(vm);
|
||||
|
||||
if (!ModelState.IsValid || !(result is RedirectToActionResult))
|
||||
if (!ModelState.IsValid || result is not RedirectToActionResult)
|
||||
return result;
|
||||
|
||||
if (!isImport)
|
||||
|
@ -141,7 +141,7 @@ namespace BTCPayServer.Controllers
|
||||
"Delete"));
|
||||
}
|
||||
|
||||
[HttpPost("{storeId}/roles/{roleId}/delete")]
|
||||
[HttpPost("{storeId}/roles/{role}/delete")]
|
||||
public async Task<IActionResult> DeleteRolePost(
|
||||
string storeId,
|
||||
[FromServices] StoreRepository storeRepository,
|
||||
|
@ -111,12 +111,6 @@ namespace BTCPayServer.Hosting
|
||||
settings.DeprecatedLightningConnectionStringCheck = true;
|
||||
await _Settings.UpdateSetting(settings);
|
||||
}
|
||||
if (!settings.UnreachableStoreCheck)
|
||||
{
|
||||
await UnreachableStoreCheck();
|
||||
settings.UnreachableStoreCheck = true;
|
||||
await _Settings.UpdateSetting(settings);
|
||||
}
|
||||
if (!settings.ConvertMultiplierToSpread)
|
||||
{
|
||||
await ConvertMultiplierToSpread();
|
||||
@ -657,13 +651,6 @@ WHERE cte.""Id""=p.""Id""
|
||||
settings1.TargetCurrency = app.StoreData.GetStoreBlob().DefaultCurrency;
|
||||
app.SetSettings(settings1);
|
||||
}
|
||||
items = AppService.Parse(settings1.PerksTemplate);
|
||||
newTemplate = AppService.SerializeTemplate(items);
|
||||
if (settings1.PerksTemplate != newTemplate)
|
||||
{
|
||||
settings1.PerksTemplate = newTemplate;
|
||||
app.SetSettings(settings1);
|
||||
};
|
||||
break;
|
||||
|
||||
case PointOfSaleAppType.AppType:
|
||||
@ -674,13 +661,6 @@ WHERE cte.""Id""=p.""Id""
|
||||
settings2.Currency = app.StoreData.GetStoreBlob().DefaultCurrency;
|
||||
app.SetSettings(settings2);
|
||||
}
|
||||
items = AppService.Parse(settings2.Template);
|
||||
newTemplate = AppService.SerializeTemplate(items);
|
||||
if (settings2.Template != newTemplate)
|
||||
{
|
||||
settings2.Template = newTemplate;
|
||||
app.SetSettings(settings2);
|
||||
};
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -1068,11 +1048,6 @@ retry:
|
||||
}
|
||||
}
|
||||
|
||||
private Task UnreachableStoreCheck()
|
||||
{
|
||||
return _StoreRepository.CleanUnreachableStores();
|
||||
}
|
||||
|
||||
private async Task DeprecatedLightningConnectionStringCheck()
|
||||
{
|
||||
using var ctx = _DBContextFactory.CreateContext();
|
||||
|
@ -1,3 +1,4 @@
|
||||
using System.Collections.Generic;
|
||||
using NBXplorer.Models;
|
||||
|
||||
namespace BTCPayServer.Models.StoreViewModels
|
||||
|
@ -60,6 +60,11 @@ namespace BTCPayServer.Plugins.PayButton.Controllers
|
||||
}
|
||||
|
||||
var apps = await _appService.GetAllApps(_userManager.GetUserId(User), false, store.Id);
|
||||
// unset app store data, because we don't need it and inclusion leads to circular references when serializing to JSON
|
||||
foreach (var app in apps)
|
||||
{
|
||||
app.App.StoreData = null;
|
||||
}
|
||||
var appUrl = HttpContext.Request.GetAbsoluteRoot().WithTrailingSlash();
|
||||
var model = new PayButtonViewModel
|
||||
{
|
||||
|
@ -356,7 +356,7 @@ namespace BTCPayServer.Plugins.PointOfSale.Controllers
|
||||
meta.Merge(formResponseJObject);
|
||||
entity.Metadata = InvoiceMetadata.FromJObject(meta);
|
||||
});
|
||||
if (price is 0 && storeBlob.ReceiptOptions.Enabled is true)
|
||||
if (price is 0 && storeBlob.ReceiptOptions?.Enabled is true)
|
||||
{
|
||||
return RedirectToAction(nameof(UIInvoiceController.InvoiceReceipt), "UIInvoice", new { invoiceId = invoice.Data.Id });
|
||||
}
|
||||
|
@ -176,7 +176,7 @@ namespace BTCPayServer.Services.Apps
|
||||
res.Add(new InvoiceStatsItem
|
||||
{
|
||||
ItemCode = item.Id,
|
||||
FiatPrice = lineItem.Price.Value,
|
||||
FiatPrice = lineItem.Price,
|
||||
Date = e.InvoiceTime.Date
|
||||
});
|
||||
}
|
||||
|
@ -834,20 +834,13 @@ namespace BTCPayServer.Services.Invoices
|
||||
|
||||
public bool CanMarkComplete()
|
||||
{
|
||||
return (Status == InvoiceStatusLegacy.Paid) ||
|
||||
(Status == InvoiceStatusLegacy.New) ||
|
||||
((Status == InvoiceStatusLegacy.New || Status == InvoiceStatusLegacy.Expired) && ExceptionStatus == InvoiceExceptionStatus.PaidPartial) ||
|
||||
((Status == InvoiceStatusLegacy.New || Status == InvoiceStatusLegacy.Expired) && ExceptionStatus == InvoiceExceptionStatus.PaidLate) ||
|
||||
(Status != InvoiceStatusLegacy.Complete && ExceptionStatus == InvoiceExceptionStatus.Marked) ||
|
||||
(Status == InvoiceStatusLegacy.Invalid);
|
||||
return Status is InvoiceStatusLegacy.New or InvoiceStatusLegacy.Paid or InvoiceStatusLegacy.Expired or InvoiceStatusLegacy.Invalid ||
|
||||
(Status != InvoiceStatusLegacy.Complete && ExceptionStatus == InvoiceExceptionStatus.Marked);
|
||||
}
|
||||
|
||||
public bool CanMarkInvalid()
|
||||
{
|
||||
return (Status == InvoiceStatusLegacy.Paid) ||
|
||||
(Status == InvoiceStatusLegacy.New) ||
|
||||
((Status == InvoiceStatusLegacy.New || Status == InvoiceStatusLegacy.Expired) && ExceptionStatus == InvoiceExceptionStatus.PaidPartial) ||
|
||||
((Status == InvoiceStatusLegacy.New || Status == InvoiceStatusLegacy.Expired) && ExceptionStatus == InvoiceExceptionStatus.PaidLate) ||
|
||||
return Status is InvoiceStatusLegacy.New or InvoiceStatusLegacy.Paid or InvoiceStatusLegacy.Expired ||
|
||||
(Status != InvoiceStatusLegacy.Invalid && ExceptionStatus == InvoiceExceptionStatus.Marked);
|
||||
}
|
||||
|
||||
|
@ -521,8 +521,14 @@ namespace BTCPayServer.Services.Invoices
|
||||
|
||||
invoiceData.Status = legacyStatus.ToLowerInvariant();
|
||||
invoiceData.ExceptionStatus = InvoiceExceptionStatus.Marked.ToString().ToLowerInvariant();
|
||||
_eventAggregator.Publish(new InvoiceEvent(ToEntity(invoiceData), eventName));
|
||||
await context.SaveChangesAsync();
|
||||
try
|
||||
{
|
||||
await context.SaveChangesAsync();
|
||||
}
|
||||
finally
|
||||
{
|
||||
_eventAggregator.Publish(new InvoiceEvent(ToEntity(invoiceData), eventName));
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -34,7 +34,7 @@ public class PosAppCartItem
|
||||
public string Id { get; set; }
|
||||
|
||||
[JsonProperty(PropertyName = "price")]
|
||||
public PosAppCartItemPrice Price { get; set; }
|
||||
public decimal Price { get; set; }
|
||||
|
||||
[JsonProperty(PropertyName = "title")]
|
||||
public string Title { get; set; }
|
||||
@ -54,8 +54,6 @@ public class PosAppCartItemPrice
|
||||
[JsonProperty(PropertyName = "formatted")]
|
||||
public string Formatted { get; set; }
|
||||
|
||||
[JsonProperty(PropertyName = "value")]
|
||||
public decimal Value { get; set; }
|
||||
|
||||
[JsonProperty(PropertyName = "type")]
|
||||
public ViewPointOfSaleViewModel.ItemPriceType Type { get; set; }
|
||||
|
@ -7,7 +7,6 @@ namespace BTCPayServer.Services
|
||||
[JsonProperty("MigrateHotwalletProperty2")]
|
||||
public bool MigrateHotwalletProperty { get; set; }
|
||||
public bool MigrateU2FToFIDO2 { get; set; }
|
||||
public bool UnreachableStoreCheck { get; set; }
|
||||
public bool DeprecatedLightningConnectionStringCheck { get; set; }
|
||||
public bool ConvertMultiplierToSpread { get; set; }
|
||||
public bool ConvertNetworkFeeProperty { get; set; }
|
||||
|
@ -3,6 +3,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Amazon.S3;
|
||||
using BTCPayServer.Abstractions.Contracts;
|
||||
using BTCPayServer.Client;
|
||||
using BTCPayServer.Data;
|
||||
@ -229,18 +230,19 @@ namespace BTCPayServer.Services.Stores
|
||||
/// <param name="storeId"></param>
|
||||
/// <param name="role"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<StoreRoleId?> ResolveStoreRoleId(string storeId, string? role)
|
||||
public async Task<StoreRoleId?> ResolveStoreRoleId(string? storeId, string? role)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(role))
|
||||
return null;
|
||||
var isStoreRole = role.Contains("::", StringComparison.OrdinalIgnoreCase);
|
||||
if(isStoreRole && (string.IsNullOrEmpty(storeId) || !role.Contains(storeId, StringComparison.InvariantCultureIgnoreCase)))
|
||||
if (storeId?.Contains("::", StringComparison.OrdinalIgnoreCase) is true)
|
||||
return null;
|
||||
var roleId = StoreRoleId.Parse(role);
|
||||
if (roleId.StoreId != null && roleId.StoreId != storeId)
|
||||
return null;
|
||||
if ((await GetStoreRole(roleId)) != null)
|
||||
return roleId;
|
||||
if (string.IsNullOrEmpty(storeId))
|
||||
return null;
|
||||
if (roleId.IsServerRole)
|
||||
roleId = new StoreRoleId(storeId, role);
|
||||
if ((await GetStoreRole(roleId)) != null)
|
||||
|
@ -157,8 +157,6 @@ namespace BTCPayServer.Services
|
||||
{
|
||||
_logger.LogError($"Failed to delete user {user.Id}");
|
||||
}
|
||||
|
||||
await _storeRepository.CleanUnreachableStores();
|
||||
}
|
||||
|
||||
|
||||
|
@ -41,7 +41,8 @@
|
||||
}
|
||||
else
|
||||
{
|
||||
<input asp-for="Role" required="required" class="form-control" readonly />
|
||||
<input type="hidden" asp-for="Role"/>
|
||||
<input required="required" class="form-control" disabled value="@Model.Role" />
|
||||
}
|
||||
<span asp-validation-for="Role" class="text-danger"></span>
|
||||
</div>
|
||||
|
@ -5,6 +5,7 @@
|
||||
@inject ThemeSettings Theme
|
||||
@inject IFileService FileService
|
||||
|
||||
<script>if (window.localStorage.getItem('btcpay-hide-sensitive-info') === 'true') { document.documentElement.setAttribute('data-hide-sensitive-info', 'true')}</script>
|
||||
@if (Theme.CustomTheme && !string.IsNullOrEmpty(Theme.CssUri))
|
||||
{ // legacy customization with CSS URI - keep it for backwards-compatibility
|
||||
<link href="@Context.Request.GetRelativePathOrAbsolute(Theme.CssUri)" rel="stylesheet" asp-append-version="true" />
|
||||
@ -25,7 +26,6 @@ else
|
||||
{
|
||||
<link href="~/main/themes/default.css" asp-append-version="true" rel="stylesheet" />
|
||||
<link href="~/main/themes/default-dark.css" asp-append-version="true" rel="stylesheet" id="DarkThemeLinkTag" />
|
||||
<script>if (window.localStorage.getItem('btcpay-hide-sensitive-info') === 'true') { document.documentElement.setAttribute('data-hide-sensitive-info', 'true')}</script>
|
||||
<script src="~/js/theme-switch.js" asp-append-version="true"></script>
|
||||
<noscript><style>.btcpay-theme-switch { display: none !important; }</style></noscript>
|
||||
}
|
||||
|
@ -236,6 +236,10 @@
|
||||
@for (var index = 0; index < Model.Items.Length; index++)
|
||||
{
|
||||
var item = Model.Items[index];
|
||||
if (item.PriceType == ViewPointOfSaleViewModel.ItemPriceType.Topup)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
var image = item.Image;
|
||||
var description = item.Description;
|
||||
|
||||
|
@ -116,7 +116,7 @@
|
||||
</div>
|
||||
<button type="button" class="btn btn-link py-0 px-2 mt-2 mb-2 gap-1 add fw-semibold d-inline-flex align-items-center" v-on:click.stop="$emit('add-field', $event, path)">
|
||||
<vc:icon symbol="new" />
|
||||
Add Form Element
|
||||
Add Form Field
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -43,7 +43,7 @@
|
||||
Write them down on a piece of paper in the exact order:
|
||||
</p>
|
||||
</div>
|
||||
<ol id="RecoveryPhrase" data-mnemonic="@Model.Mnemonic" class="my-5 mx-auto">
|
||||
<ol id="RecoveryPhrase" data-mnemonic="@Model.Mnemonic" class="d-inline-block my-5 mx-auto ps-4">
|
||||
@foreach (var word in Model.Words)
|
||||
{
|
||||
<li class="text-start text-muted py-2">
|
||||
|
@ -23,13 +23,14 @@
|
||||
<meta name="robots" content="noindex,nofollow">
|
||||
@if (isProcessing)
|
||||
{
|
||||
<script type="text/javascript">
|
||||
setTimeout(() => { window.location.reload(); }, 10000);
|
||||
<script type="text/javascript">
|
||||
setTimeout(() => { window.location.reload(); }, 10000);
|
||||
</script>
|
||||
}else if (isFreeInvoice)
|
||||
}
|
||||
else if (isFreeInvoice)
|
||||
{
|
||||
<script type="text/javascript">
|
||||
setTimeout(() => { window.location.reload(); }, 2000);
|
||||
<script type="text/javascript">
|
||||
setTimeout(() => { window.location.reload(); }, 2000);
|
||||
</script>
|
||||
}
|
||||
<style>
|
||||
|
@ -62,27 +62,36 @@
|
||||
</div>
|
||||
<hr class="border" />
|
||||
}
|
||||
<div class="form-group">
|
||||
<div class="form-check">
|
||||
<input id="RateThenOption" asp-for="SelectedRefundOption" type="radio" value="RateThen" class="form-check-input"/>
|
||||
<label for="RateThenOption" class="form-check-label">@Model.RateThenText</label>
|
||||
<div class="form-text">The crypto currency price, at the rate the invoice got paid.</div>
|
||||
@if (Model.CryptoAmountThen > 0)
|
||||
{
|
||||
<div class="form-group">
|
||||
<div class="form-check">
|
||||
<input id="RateThenOption" asp-for="SelectedRefundOption" type="radio" value="RateThen" class="form-check-input" />
|
||||
<label for="RateThenOption" class="form-check-label">@Model.RateThenText</label>
|
||||
<div class="form-text">The crypto currency price, at the rate the invoice got paid.</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="form-check">
|
||||
<input id="CurrentRateOption" asp-for="SelectedRefundOption" type="radio" value="CurrentRate" class="form-check-input"/>
|
||||
<label for="CurrentRateOption" class="form-check-label">@Model.CurrentRateText</label>
|
||||
<div class="form-text">The crypto currency price, at the current rate.</div>
|
||||
}
|
||||
@if (Model.CryptoAmountNow > 0)
|
||||
{
|
||||
<div class="form-group">
|
||||
<div class="form-check">
|
||||
<input id="CurrentRateOption" asp-for="SelectedRefundOption" type="radio" value="CurrentRate" class="form-check-input" />
|
||||
<label for="CurrentRateOption" class="form-check-label">@Model.CurrentRateText</label>
|
||||
<div class="form-text">The crypto currency price, at the current rate.</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="form-check">
|
||||
<input id="FiatOption" asp-for="SelectedRefundOption" type="radio" value="Fiat" class="form-check-input"/>
|
||||
<label for="FiatOption" class="form-check-label">@Model.FiatText</label>
|
||||
<div class="form-text">The invoice currency, at the rate when the refund will be sent.</div>
|
||||
}
|
||||
@if (Model.FiatAmount > 0)
|
||||
{
|
||||
<div class="form-group">
|
||||
<div class="form-check">
|
||||
<input id="FiatOption" asp-for="SelectedRefundOption" type="radio" value="Fiat" class="form-check-input" />
|
||||
<label for="FiatOption" class="form-check-label">@Model.FiatText</label>
|
||||
<div class="form-text">The invoice currency, at the rate when the refund will be sent.</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
<div class="form-group">
|
||||
<div class="form-check">
|
||||
<input id="CustomOption" asp-for="SelectedRefundOption" type="radio" value="Custom" class="form-check-input"/>
|
||||
|
@ -140,7 +140,13 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@if (Model.AdditionalOptions is not null)
|
||||
{
|
||||
@foreach (var dictKeys in Model.AdditionalOptions)
|
||||
{
|
||||
<input type="hidden" asp-for="AdditionalOptions[dictKeys.Key]" />
|
||||
}
|
||||
}
|
||||
<button type="submit" class="btn btn-primary" id="Continue">@(isImport ? "Continue" : "Create")</button>
|
||||
</form>
|
||||
|
||||
|
@ -19,3 +19,5 @@
|
||||
}
|
||||
|
||||
@RenderBody()
|
||||
|
||||
<vc:ui-extension-point location="onchain-wallet-setup-post-body" model="@Model"/>
|
||||
|
@ -11,20 +11,20 @@
|
||||
"pay_in_wallet": "Πληρωμή στο πορτοφόλι",
|
||||
"pay_by_nfc": "Πληρωμή μέσω NFC",
|
||||
"pay_by_lnurl": "Πληρωμή με LNURL-Withdraw",
|
||||
"invoice_id": "ID Παραστατικού Πληρωμής",
|
||||
"order_id": "ID Παραγγελίας",
|
||||
"invoice_id": "ID παραστατικού πληρωμής",
|
||||
"order_id": "ID παραγγελίας",
|
||||
"total_price": "Συνολική τιμή",
|
||||
"total_fiat": "Συνολική τιμή σε νόμισμα",
|
||||
"exchange_rate": "Ισοτιμία",
|
||||
"amount_paid": "Πληρωθέν ποσό",
|
||||
"amount_due": "Οφειλόμενο ποσό",
|
||||
"recommended_fee": "Συνιστώμενη Αμοιβή",
|
||||
"recommended_fee": "Συνιστώμενη αμοιβή",
|
||||
"fee_rate": "{{feeRate}} sat/byte",
|
||||
"network_cost": "Κόστος Δικτύου",
|
||||
"network_cost": "Κόστος δικτύου",
|
||||
"tx_count": "{{count}} συναλλαγή",
|
||||
"qr_text": "Σαρώστε τον κωδικό QR ή πατήστε για να αντιγράψετε τη διεύθυνση.",
|
||||
"address": "Διεύθυνση",
|
||||
"lightning": "Αστραπή (Lightning)",
|
||||
"lightning": "Lightning",
|
||||
"payment_link": "Σύνδεσμος πληρωμής",
|
||||
"invoice_paid": "Εξοφλημένο τιμολόγιο",
|
||||
"invoice_expired": "Η τιμολόγηση έληξε",
|
||||
|
@ -3,16 +3,16 @@
|
||||
"code": "el-GR",
|
||||
"currentLanguage": "Ελληνικά",
|
||||
"lang": "Γλώσσα",
|
||||
"Awaiting Payment...": "Αναμονή Πληρωμής...",
|
||||
"Awaiting Payment...": "Αναμονή πληρωμής...",
|
||||
"Pay with": "Πληρώστε με",
|
||||
"Contact and Refund Email": "Email Επικοινωνίας & Επιστροφής Πληρωμής",
|
||||
"Contact_Body": "Παρακαλούμε εισάγετε το email σας παρακάτω. Θα επικοινωνήσουμε μαζί σας σε αυτή τη διεύθυνση ηλεκτρονικής αλληλογραφίας εαν προκύψει κάποιο θέμα με την πληρωμή σας.",
|
||||
"Contact and Refund Email": "Email επικοινωνίας & επιστροφής πληρωμής",
|
||||
"Contact_Body": "Παρακαλούμε εισάγετε το email σας παρακάτω. Θα επικοινωνήσουμε μαζί σας σε αυτή τη διεύθυνση ηλεκτρονικής αλληλογραφίας εάν προκύψει κάποιο θέμα με την πληρωμή σας.",
|
||||
"Your email": "Το email σας",
|
||||
"Continue": "Συνέχεια",
|
||||
"Please enter a valid email address": "Παρακαλούμε εισάγετε μια έγκυρη διεύθυνση email",
|
||||
"Order Amount": "Ποσό Παραγγελίας",
|
||||
"Network Cost": "Κόστος Δικτύου",
|
||||
"Already Paid": "Πληρώθηκαν Ήδη",
|
||||
"Order Amount": "Ποσό παραγγελίας",
|
||||
"Network Cost": "Κόστος δικτύου",
|
||||
"Already Paid": "Πληρώθηκαν ήδη",
|
||||
"Due": "Οφειλόμενα",
|
||||
"Scan": "Σάρωση",
|
||||
"Copy": "Αντιγραφή",
|
||||
@ -34,14 +34,14 @@
|
||||
"InvoiceExpired_Body_1": "Το παρών παραστατικό πληρωμής έχει λήξει. Ένα παραστατικό πληρωμής ισχύει μόνο για {{maxTimeMinutes}} λεπτά.\nΜπορείτε να επιστρέψετε στο {{storeName}} εάν θα θέλατε να υποβάλετε ξανά την πληρωμή σας.",
|
||||
"InvoiceExpired_Body_2": "Εάν επιχειρήσατε να στείλετε την πληρωμή σας, αυτή ακόμη δεν έχει γίνει αποδεκτή απο το δίκτυο. Δέν έχουμε λάβει ακόμη την πληρωμή σας.",
|
||||
"InvoiceExpired_Body_3": "Εάν την λάβουμε αργότερα, είτε θα εκτέλεσουμε την παραγγελία σας ή θα επικοινωνήσουμε μαζί σας για να οργανώσουμε την επιστροφή των χρημάτων σας...",
|
||||
"Invoice ID": "ID Παραστατικού Πληρωμής",
|
||||
"Order ID": "ID Παραγγελίας",
|
||||
"Invoice ID": "ID παραστατικού πληρωμής",
|
||||
"Order ID": "ID παραγγελίας",
|
||||
"Return to StoreName": "Επιστροφή στο {{storeName}}",
|
||||
"This invoice has been paid": "Αυτό το παραστατικό έχει πληρωθεί",
|
||||
"This invoice has been archived": "Αυτό το παραστατικό έχει αρχειοθετηθεί",
|
||||
"Archived_Body": "Παρακαλούμε επικοινωνήστε με το κατάστημα για πληροφορίες σχετικά με την παραγγελία ή εάν χρειάζεστε βοήθεια",
|
||||
"BOLT 11 Invoice": "Παραστατικό BOLT 11",
|
||||
"Node Info": "Πληροφορίες Κόμβου",
|
||||
"Node Info": "Πληροφορίες κόμβου",
|
||||
"txCount": "{{count}} συναλλαγή",
|
||||
"txCount_plural": "{{count}} συναλλαγών",
|
||||
"Pay with CoinSwitch": "Πληρώστε με CoinSwitch",
|
||||
|
@ -10,18 +10,17 @@
|
||||
|
||||
/* Hide sensitive info */
|
||||
[data-hide-sensitive-info="true"] [data-sensitive] {
|
||||
visibility: hidden;
|
||||
display: inline-flex;
|
||||
position: relative;
|
||||
visibility: hidden;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
[data-hide-sensitive-info="true"] [data-sensitive]:before {
|
||||
content: '***';
|
||||
content: '***********************';
|
||||
visibility: visible;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
[data-hide-sensitive-info="true"] .text-end [data-sensitive]:before {
|
||||
right: 0;
|
||||
top: .2em;
|
||||
}
|
||||
|
||||
[data-hide-sensitive-info="true"] .store-wallet-balance .ct-label.ct-vertical.ct-start {
|
||||
|
@ -1,5 +1,5 @@
|
||||
<Project>
|
||||
<PropertyGroup>
|
||||
<Version>1.10.0</Version>
|
||||
<Version>1.10.2</Version>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
|
20
Changelog.md
20
Changelog.md
@ -1,5 +1,24 @@
|
||||
# Changelog
|
||||
|
||||
## 1.10.2
|
||||
|
||||
### Bug fixes
|
||||
|
||||
* Fix: Stale data when fetching invoice after webhook (#5049) @Kukks
|
||||
* Fix: Crash on migation of old instances (#5051) @NicolasDorier
|
||||
* Fix: Hide sensitive info feature not working with custom theme (#5044) @dennisreimann
|
||||
* Fix: Pay button not rendering on the invoice page (#5043) @dennisreimann
|
||||
|
||||
## 1.10.1
|
||||
|
||||
### Bug fixes
|
||||
|
||||
* Point of Sale bug after filling out form Shop + cart (#5031) @Kukks
|
||||
|
||||
### Improvements
|
||||
|
||||
* Language translation update for el-GR
|
||||
|
||||
## 1.10.0
|
||||
|
||||
Notice: Due to the substantial disk space consumption, we are removing all data pertaining to past webhook deliveries (#5005).
|
||||
@ -32,6 +51,7 @@ This data, generally used for debugging integrations, will be regularly purged.
|
||||
* Improve create first store case (#4951) @dennisreimann @dstrukt
|
||||
* Improve Refund UI/UX (#4934 #3839 #4812) @dennisreimann @dstrukt
|
||||
* Prune old webhook delivery data (#5005) @NicolasDorier
|
||||
* Can mark expired invoices as complete or invalid (#5006) @dennisreimann
|
||||
|
||||
## 1.9.3
|
||||
|
||||
|
Reference in New Issue
Block a user