mirror of
https://github.com/btcpayserver/btcpayserver.git
synced 2025-02-20 13:34:37 +01:00
Support Admin being able to view stores (#5782)
* Support Admin being able to view stores * fix null check * Delete obsolete empty view * Add test * Apply CanViewStoreSettings policy changes Taken from #5719 * Fix Selenium tests * Update dashboard permission requirement --------- Co-authored-by: Dennis Reimann <mail@dennisreimann.de>
This commit is contained in:
parent
f1ff913cbe
commit
e497903bf4
49 changed files with 440 additions and 286 deletions
|
@ -645,5 +645,26 @@ retry:
|
|||
Driver.FindElement(By.Id($"SectionNav-{navPages}")).Click();
|
||||
}
|
||||
}
|
||||
|
||||
public void AssertPageAccess(bool shouldHaveAccess, string url)
|
||||
{
|
||||
GoToUrl(url);
|
||||
Assert.DoesNotMatch("404 - Page not found</h", Driver.PageSource);
|
||||
if (shouldHaveAccess)
|
||||
Assert.DoesNotMatch("- Denied</h", Driver.PageSource);
|
||||
else
|
||||
Assert.Contains("- Denied</h", Driver.PageSource);
|
||||
}
|
||||
|
||||
public (string appName, string appId) CreateApp(string type, string name = null)
|
||||
{
|
||||
if (string.IsNullOrEmpty(name)) name = $"{type}-{Guid.NewGuid().ToString()[..14]}";
|
||||
Driver.FindElement(By.Id($"StoreNav-Create{type}")).Click();
|
||||
Driver.FindElement(By.Name("AppName")).SendKeys(name);
|
||||
Driver.FindElement(By.Id("Create")).Click();
|
||||
Assert.Contains("App successfully created", FindAlertMessage().Text);
|
||||
var appId = Driver.Url.Split('/')[4];
|
||||
return (name, appId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -998,7 +998,7 @@ namespace BTCPayServer.Tests
|
|||
|
||||
var storeLink = s.Driver.FindElement(By.Id($"Store-{storeId}"));
|
||||
Assert.Contains(storeName, storeLink.Text);
|
||||
storeLink.Click();
|
||||
s.GoToStore(storeId);
|
||||
s.Driver.FindElement(By.Id("btn-archive-toggle")).Click();
|
||||
Assert.Contains("The store has been unarchived and will appear in the stores list by default again.", s.FindAlertMessage().Text);
|
||||
}
|
||||
|
@ -3359,6 +3359,55 @@ retry:
|
|||
Assert.Contains("Malice",s.Driver.PageSource);
|
||||
Assert.DoesNotContain(Policies.CanModifyServerSettings,s.Driver.PageSource);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Selenium", "Selenium")]
|
||||
[Trait("Lightning", "Lightning")]
|
||||
public async Task CanAccessUserStoreAsAdmin()
|
||||
{
|
||||
using var s = CreateSeleniumTester(newDb: true);
|
||||
s.Server.ActivateLightning();
|
||||
await s.StartAsync();
|
||||
await s.Server.EnsureChannelsSetup();
|
||||
var storeSettingsPaths = new [] {"settings", "rates", "checkout", "tokens", "users", "roles", "webhooks", "payout-processors", "payout-processors/onchain-automated/BTC", "payout-processors/lightning-automated/BTC", "emails", "email-settings", "forms"};
|
||||
|
||||
// Setup user, store and wallets
|
||||
s.RegisterNewUser();
|
||||
(_, string storeId) = s.CreateNewStore();
|
||||
s.GoToStore();
|
||||
s.GenerateWallet(isHotWallet: true);
|
||||
s.AddLightningNode(LightningConnectionType.CLightning, false);
|
||||
|
||||
// Add apps
|
||||
(_, string posId) = s.CreateApp("PointOfSale");
|
||||
(_, string crowdfundId) = s.CreateApp("Crowdfund");
|
||||
s.Logout();
|
||||
|
||||
// Setup admin and check access
|
||||
s.GoToRegister();
|
||||
s.RegisterNewUser(true);
|
||||
string GetStorePath(string subPath) => $"/stores/{storeId}/{subPath}";
|
||||
|
||||
// Owner access
|
||||
s.AssertPageAccess(false, GetStorePath(""));
|
||||
s.AssertPageAccess(true, GetStorePath("reports"));
|
||||
s.AssertPageAccess(true, GetStorePath("invoices"));
|
||||
s.AssertPageAccess(false, GetStorePath("invoices/create"));
|
||||
s.AssertPageAccess(true, GetStorePath("payment-requests"));
|
||||
s.AssertPageAccess(false, GetStorePath("payment-requests/edit"));
|
||||
s.AssertPageAccess(true, GetStorePath("pull-payments"));
|
||||
s.AssertPageAccess(true, GetStorePath("payouts"));
|
||||
s.AssertPageAccess(false, GetStorePath("onchain/BTC"));
|
||||
s.AssertPageAccess(false, GetStorePath("onchain/BTC/settings"));
|
||||
s.AssertPageAccess(false, GetStorePath("lightning/BTC"));
|
||||
s.AssertPageAccess(false, GetStorePath("lightning/BTC/settings"));
|
||||
s.AssertPageAccess(false, GetStorePath("apps/create"));
|
||||
foreach (var path in storeSettingsPaths)
|
||||
{ // should have view access to settings, but no submit buttons or create links
|
||||
s.AssertPageAccess(true, $"stores/{storeId}/{path}");
|
||||
s.Driver.ElementDoesNotExist(By.CssSelector("#mainContent .btn-primary"));
|
||||
}
|
||||
}
|
||||
|
||||
private static void CanBrowseContent(SeleniumTester s)
|
||||
{
|
||||
|
|
|
@ -26,16 +26,16 @@
|
|||
{
|
||||
@if (Model.Store != null)
|
||||
{
|
||||
<div class="accordion-item" permission="@Policies.CanModifyStoreSettings">
|
||||
<div class="accordion-item" permission="@Policies.CanViewStoreSettings">
|
||||
<div class="accordion-body">
|
||||
<ul class="navbar-nav">
|
||||
<li class="nav-item">
|
||||
<li class="nav-item" permission="@Policies.CanModifyStoreSettings">
|
||||
<a asp-area="" asp-controller="UIStores" asp-action="Dashboard" asp-route-storeId="@Model.Store.Id" class="nav-link @ViewData.IsActivePage(StoreNavPages.Dashboard)" id="StoreNav-Dashboard">
|
||||
<vc:icon symbol="home"/>
|
||||
<span>Dashboard</span>
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<li class="nav-item" permission="@Policies.CanViewStoreSettings">
|
||||
<a asp-area="" asp-controller="UIStores" asp-action="GeneralSettings" asp-route-storeId="@Model.Store.Id" class="nav-link @ViewData.IsActivePage(new [] {StoreNavPages.Rates, StoreNavPages.CheckoutAppearance, StoreNavPages.General, StoreNavPages.Tokens, StoreNavPages.Users, StoreNavPages.Webhooks, StoreNavPages.PayoutProcessors, StoreNavPages.Emails})" id="StoreNav-StoreSettings">
|
||||
<vc:icon symbol="settings"/>
|
||||
<span>Settings</span>
|
||||
|
@ -115,7 +115,6 @@
|
|||
</a>
|
||||
</li>
|
||||
}
|
||||
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -76,17 +76,17 @@ namespace BTCPayServer.Controllers
|
|||
if (storeId != null)
|
||||
{
|
||||
// verify store exists and redirect to it
|
||||
var store = await _storeRepository.FindStore(storeId, userId);
|
||||
var store = await _storeRepository.FindStore(storeId);
|
||||
if (store != null)
|
||||
{
|
||||
return RedirectToStore(userId, store);
|
||||
return RedirectToStore(userId, storeId);
|
||||
}
|
||||
}
|
||||
|
||||
var stores = await _storeRepository.GetStoresByUserId(userId);
|
||||
var activeStore = stores.FirstOrDefault(s => !s.Archived);
|
||||
return activeStore != null
|
||||
? RedirectToStore(userId, activeStore)
|
||||
? RedirectToStore(userId, activeStore.Id)
|
||||
: RedirectToAction(nameof(UIUserStoresController.CreateStore), "UIUserStores");
|
||||
}
|
||||
|
||||
|
@ -198,14 +198,9 @@ namespace BTCPayServer.Controllers
|
|||
{
|
||||
return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
|
||||
}
|
||||
public static RedirectToActionResult RedirectToStore(string userId, StoreData store)
|
||||
public static RedirectToActionResult RedirectToStore(string userId, string storeId)
|
||||
{
|
||||
var perms = store.GetPermissionSet(userId);
|
||||
if (perms.Contains(Policies.CanModifyStoreSettings, store.Id))
|
||||
return new RedirectToActionResult("Dashboard", "UIStores", new {storeId = store.Id});
|
||||
if (perms.Contains(Policies.CanViewInvoices, store.Id))
|
||||
return new RedirectToActionResult("ListInvoices", "UIInvoice", new { storeId = store.Id });
|
||||
return new RedirectToActionResult("Index", "UIStores", new {storeId = store.Id});
|
||||
return new RedirectToActionResult("Index", "UIStores", new {storeId});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1144,7 +1144,7 @@ namespace BTCPayServer.Controllers
|
|||
|
||||
[HttpGet("/stores/{storeId}/invoices/create")]
|
||||
[HttpGet("invoices/create")]
|
||||
[Authorize(AuthenticationSchemes = AuthenticationSchemes.Cookie)]
|
||||
[Authorize(Policy = Policies.CanCreateInvoice, AuthenticationSchemes = AuthenticationSchemes.Cookie)]
|
||||
[BitpayAPIConstraint(false)]
|
||||
public async Task<IActionResult> CreateInvoice(InvoicesModel? model = null)
|
||||
{
|
||||
|
@ -1154,7 +1154,7 @@ namespace BTCPayServer.Controllers
|
|||
return RedirectToAction(nameof(UIHomeController.Index), "UIHome");
|
||||
}
|
||||
|
||||
var store = await _StoreRepository.FindStore(model.StoreId, GetUserId());
|
||||
var store = await _StoreRepository.FindStore(model.StoreId);
|
||||
if (store == null)
|
||||
return NotFound();
|
||||
|
||||
|
|
|
@ -108,7 +108,7 @@ namespace BTCPayServer.Controllers
|
|||
}
|
||||
|
||||
[HttpGet("/stores/{storeId}/payment-requests/edit/{payReqId?}")]
|
||||
[Authorize(Policy = Policies.CanViewPaymentRequests, AuthenticationSchemes = AuthenticationSchemes.Cookie)]
|
||||
[Authorize(Policy = Policies.CanModifyPaymentRequests, AuthenticationSchemes = AuthenticationSchemes.Cookie)]
|
||||
public async Task<IActionResult> EditPaymentRequest(string storeId, string payReqId)
|
||||
{
|
||||
var store = GetCurrentStore();
|
||||
|
|
|
@ -83,7 +83,7 @@ namespace BTCPayServer.Controllers
|
|||
Message = "You must enable at least one payment method before creating a pull payment.",
|
||||
Severity = StatusMessageModel.StatusSeverity.Error
|
||||
});
|
||||
return RedirectToAction(nameof(UIStoresController.Dashboard), "UIStores", new { storeId });
|
||||
return RedirectToAction(nameof(UIStoresController.Index), "UIStores", new { storeId });
|
||||
}
|
||||
|
||||
return View(new NewPullPaymentModel
|
||||
|
@ -161,6 +161,7 @@ namespace BTCPayServer.Controllers
|
|||
return RedirectToAction(nameof(PullPayments), new { storeId = storeId });
|
||||
}
|
||||
|
||||
[Authorize(Policy = Policies.CanViewPullPayments, AuthenticationSchemes = AuthenticationSchemes.Cookie)]
|
||||
[HttpGet("stores/{storeId}/pull-payments")]
|
||||
public async Task<IActionResult> PullPayments(
|
||||
string storeId,
|
||||
|
@ -199,7 +200,7 @@ namespace BTCPayServer.Controllers
|
|||
Message = "You must enable at least one payment method before creating a pull payment.",
|
||||
Severity = StatusMessageModel.StatusSeverity.Error
|
||||
});
|
||||
return RedirectToAction(nameof(UIStoresController.Dashboard), "UIStores", new { storeId });
|
||||
return RedirectToAction(nameof(UIStoresController.Index), "UIStores", new { storeId });
|
||||
}
|
||||
|
||||
var vm = this.ParseListQuery(new PullPaymentsModel
|
||||
|
@ -482,7 +483,7 @@ namespace BTCPayServer.Controllers
|
|||
Message = "You must enable at least one payment method before creating a payout.",
|
||||
Severity = StatusMessageModel.StatusSeverity.Error
|
||||
});
|
||||
return RedirectToAction(nameof(UIStoresController.Dashboard), "UIStores", new { storeId });
|
||||
return RedirectToAction(nameof(UIStoresController.Index), "UIStores", new { storeId });
|
||||
}
|
||||
|
||||
var vm = this.ParseListQuery(new PayoutsModel
|
||||
|
|
|
@ -1,12 +1,15 @@
|
|||
#nullable enable
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Abstractions.Constants;
|
||||
using BTCPayServer.Client;
|
||||
using BTCPayServer.Components.StoreLightningBalance;
|
||||
using BTCPayServer.Components.StoreNumbers;
|
||||
using BTCPayServer.Components.StoreRecentInvoices;
|
||||
using BTCPayServer.Components.StoreRecentTransactions;
|
||||
using BTCPayServer.Data;
|
||||
using BTCPayServer.Models.StoreViewModels;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace BTCPayServer.Controllers
|
||||
|
@ -14,9 +17,13 @@ namespace BTCPayServer.Controllers
|
|||
public partial class UIStoresController
|
||||
{
|
||||
[HttpGet("{storeId}")]
|
||||
[Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Cookie)]
|
||||
public async Task<IActionResult> Dashboard()
|
||||
{
|
||||
var store = CurrentStore;
|
||||
if (store is null)
|
||||
return NotFound();
|
||||
|
||||
var storeBlob = store.GetStoreBlob();
|
||||
|
||||
AddPaymentMethods(store, storeBlob,
|
||||
|
@ -38,16 +45,17 @@ namespace BTCPayServer.Controllers
|
|||
};
|
||||
|
||||
// Widget data
|
||||
if (!vm.WalletEnabled && !vm.LightningEnabled)
|
||||
if (vm is { WalletEnabled: false, LightningEnabled: false })
|
||||
return View(vm);
|
||||
|
||||
var userId = GetUserId();
|
||||
if (userId is null)
|
||||
return NotFound();
|
||||
|
||||
var apps = await _appService.GetAllApps(userId, false, store.Id);
|
||||
foreach (var app in apps)
|
||||
{
|
||||
var appData = await _appService.GetAppDataIfOwner(userId, app.Id);
|
||||
var appData = await _appService.GetAppData(userId, app.Id);
|
||||
vm.Apps.Add(appData);
|
||||
}
|
||||
|
||||
|
@ -55,6 +63,7 @@ namespace BTCPayServer.Controllers
|
|||
}
|
||||
|
||||
[HttpGet("{storeId}/dashboard/{cryptoCode}/lightning/balance")]
|
||||
[Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Cookie)]
|
||||
public IActionResult LightningBalance(string storeId, string cryptoCode)
|
||||
{
|
||||
var store = HttpContext.GetStoreData();
|
||||
|
@ -66,6 +75,7 @@ namespace BTCPayServer.Controllers
|
|||
}
|
||||
|
||||
[HttpGet("{storeId}/dashboard/{cryptoCode}/numbers")]
|
||||
[Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Cookie)]
|
||||
public IActionResult StoreNumbers(string storeId, string cryptoCode)
|
||||
{
|
||||
var store = HttpContext.GetStoreData();
|
||||
|
@ -77,6 +87,7 @@ namespace BTCPayServer.Controllers
|
|||
}
|
||||
|
||||
[HttpGet("{storeId}/dashboard/{cryptoCode}/recent-transactions")]
|
||||
[Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Cookie)]
|
||||
public IActionResult RecentTransactions(string storeId, string cryptoCode)
|
||||
{
|
||||
var store = HttpContext.GetStoreData();
|
||||
|
@ -88,6 +99,7 @@ namespace BTCPayServer.Controllers
|
|||
}
|
||||
|
||||
[HttpGet("{storeId}/dashboard/{cryptoCode}/recent-invoices")]
|
||||
[Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Cookie)]
|
||||
public IActionResult RecentInvoices(string storeId, string cryptoCode)
|
||||
{
|
||||
var store = HttpContext.GetStoreData();
|
||||
|
|
|
@ -7,9 +7,11 @@ using System.Threading.Tasks;
|
|||
using BTCPayServer.Abstractions.Constants;
|
||||
using BTCPayServer.Abstractions.Extensions;
|
||||
using BTCPayServer.Abstractions.Models;
|
||||
using BTCPayServer.Client;
|
||||
using BTCPayServer.Data;
|
||||
using BTCPayServer.Models;
|
||||
using BTCPayServer.Services.Mails;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using MimeKit;
|
||||
|
||||
|
@ -43,6 +45,7 @@ namespace BTCPayServer.Controllers
|
|||
}
|
||||
|
||||
[HttpPost("{storeId}/emails")]
|
||||
[Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Cookie)]
|
||||
public async Task<IActionResult> StoreEmails(string storeId, StoreEmailRuleViewModel vm, string command)
|
||||
{
|
||||
vm.Rules ??= new List<StoreEmailRule>();
|
||||
|
@ -185,13 +188,13 @@ namespace BTCPayServer.Controllers
|
|||
}
|
||||
|
||||
[HttpPost("{storeId}/email-settings")]
|
||||
[Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Cookie)]
|
||||
public async Task<IActionResult> StoreEmailSettings(string storeId, EmailsViewModel model, string command)
|
||||
{
|
||||
var store = HttpContext.GetStoreData();
|
||||
if (store == null)
|
||||
return NotFound();
|
||||
|
||||
var emailSender = await _emailSenderFactory.GetEmailSender(store.Id) as StoreEmailSender;
|
||||
var fallbackSettings = await _emailSenderFactory.GetEmailSender(store.Id) is StoreEmailSender { FallbackSender: not null } storeSender
|
||||
? await storeSender.FallbackSender.GetEmailSettings()
|
||||
: null;
|
||||
|
|
|
@ -4,10 +4,12 @@ using System.Threading;
|
|||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Abstractions.Constants;
|
||||
using BTCPayServer.Abstractions.Models;
|
||||
using BTCPayServer.Client;
|
||||
using BTCPayServer.Client.Models;
|
||||
using BTCPayServer.Data;
|
||||
using BTCPayServer.Models;
|
||||
using BTCPayServer.Models.StoreViewModels;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using NBitcoin;
|
||||
using NBitcoin.DataEncoders;
|
||||
|
@ -46,6 +48,7 @@ namespace BTCPayServer.Controllers
|
|||
}
|
||||
|
||||
[HttpGet("{storeId}/webhooks/new")]
|
||||
[Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Cookie)]
|
||||
public IActionResult NewWebhook()
|
||||
{
|
||||
return View(nameof(ModifyWebhook), new EditWebhookViewModel
|
||||
|
@ -58,6 +61,7 @@ namespace BTCPayServer.Controllers
|
|||
}
|
||||
|
||||
[HttpGet("{storeId}/webhooks/{webhookId}/remove")]
|
||||
[Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Cookie)]
|
||||
public async Task<IActionResult> DeleteWebhook(string webhookId)
|
||||
{
|
||||
var webhook = await _Repo.GetWebhook(CurrentStore.Id, webhookId);
|
||||
|
@ -68,6 +72,7 @@ namespace BTCPayServer.Controllers
|
|||
}
|
||||
|
||||
[HttpPost("{storeId}/webhooks/{webhookId}/remove")]
|
||||
[Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Cookie)]
|
||||
public async Task<IActionResult> DeleteWebhookPost(string webhookId)
|
||||
{
|
||||
var webhook = await _Repo.GetWebhook(CurrentStore.Id, webhookId);
|
||||
|
@ -80,6 +85,7 @@ namespace BTCPayServer.Controllers
|
|||
}
|
||||
|
||||
[HttpPost("{storeId}/webhooks/new")]
|
||||
[Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Cookie)]
|
||||
public async Task<IActionResult> NewWebhook(string storeId, EditWebhookViewModel viewModel)
|
||||
{
|
||||
if (!ModelState.IsValid)
|
||||
|
@ -91,6 +97,7 @@ namespace BTCPayServer.Controllers
|
|||
}
|
||||
|
||||
[HttpGet("{storeId}/webhooks/{webhookId}")]
|
||||
[Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Cookie)]
|
||||
public async Task<IActionResult> ModifyWebhook(string webhookId)
|
||||
{
|
||||
var webhook = await _Repo.GetWebhook(CurrentStore.Id, webhookId);
|
||||
|
@ -107,6 +114,7 @@ namespace BTCPayServer.Controllers
|
|||
}
|
||||
|
||||
[HttpPost("{storeId}/webhooks/{webhookId}")]
|
||||
[Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Cookie)]
|
||||
public async Task<IActionResult> ModifyWebhook(string webhookId, EditWebhookViewModel viewModel)
|
||||
{
|
||||
var webhook = await _Repo.GetWebhook(CurrentStore.Id, webhookId);
|
||||
|
@ -121,6 +129,7 @@ namespace BTCPayServer.Controllers
|
|||
}
|
||||
|
||||
[HttpGet("{storeId}/webhooks/{webhookId}/test")]
|
||||
[Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Cookie)]
|
||||
public async Task<IActionResult> TestWebhook(string webhookId)
|
||||
{
|
||||
var webhook = await _Repo.GetWebhook(CurrentStore.Id, webhookId);
|
||||
|
@ -131,6 +140,7 @@ namespace BTCPayServer.Controllers
|
|||
}
|
||||
|
||||
[HttpPost("{storeId}/webhooks/{webhookId}/test")]
|
||||
[Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Cookie)]
|
||||
public async Task<IActionResult> TestWebhook(string webhookId, TestWebhookViewModel viewModel, CancellationToken cancellationToken)
|
||||
{
|
||||
var result = await WebhookNotificationManager.TestWebhook(CurrentStore.Id, webhookId, viewModel.Type, cancellationToken);
|
||||
|
@ -148,6 +158,7 @@ namespace BTCPayServer.Controllers
|
|||
}
|
||||
|
||||
[HttpPost("{storeId}/webhooks/{webhookId}/deliveries/{deliveryId}/redeliver")]
|
||||
[Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Cookie)]
|
||||
public async Task<IActionResult> RedeliverWebhook(string webhookId, string deliveryId)
|
||||
{
|
||||
var delivery = await _Repo.GetWebhookDelivery(CurrentStore.Id, webhookId, deliveryId);
|
||||
|
@ -168,6 +179,7 @@ namespace BTCPayServer.Controllers
|
|||
}
|
||||
|
||||
[HttpGet("{storeId}/webhooks/{webhookId}/deliveries/{deliveryId}/request")]
|
||||
[Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Cookie)]
|
||||
public async Task<IActionResult> WebhookDelivery(string webhookId, string deliveryId)
|
||||
{
|
||||
var delivery = await _Repo.GetWebhookDelivery(CurrentStore.Id, webhookId, deliveryId);
|
||||
|
|
|
@ -5,7 +5,7 @@ using System.Threading;
|
|||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Abstractions.Constants;
|
||||
using BTCPayServer.Abstractions.Extensions;
|
||||
using BTCPayServer.Components.StoreLightningBalance;
|
||||
using BTCPayServer.Client;
|
||||
using BTCPayServer.Configuration;
|
||||
using BTCPayServer.Data;
|
||||
using BTCPayServer.Lightning;
|
||||
|
@ -14,7 +14,7 @@ using BTCPayServer.Models;
|
|||
using BTCPayServer.Models.StoreViewModels;
|
||||
using BTCPayServer.Payments;
|
||||
using BTCPayServer.Payments.Lightning;
|
||||
using BTCPayServer.Services;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
|
@ -22,8 +22,8 @@ namespace BTCPayServer.Controllers
|
|||
{
|
||||
public partial class UIStoresController
|
||||
{
|
||||
|
||||
[HttpGet("{storeId}/lightning/{cryptoCode}")]
|
||||
[Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Cookie)]
|
||||
public IActionResult Lightning(string storeId, string cryptoCode)
|
||||
{
|
||||
var store = HttpContext.GetStoreData();
|
||||
|
@ -85,6 +85,7 @@ namespace BTCPayServer.Controllers
|
|||
}
|
||||
|
||||
[HttpGet("{storeId}/lightning/{cryptoCode}/setup")]
|
||||
[Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Cookie)]
|
||||
public IActionResult SetupLightningNode(string storeId, string cryptoCode)
|
||||
{
|
||||
var store = HttpContext.GetStoreData();
|
||||
|
@ -101,6 +102,7 @@ namespace BTCPayServer.Controllers
|
|||
}
|
||||
|
||||
[HttpPost("{storeId}/lightning/{cryptoCode}/setup")]
|
||||
[Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Cookie)]
|
||||
public async Task<IActionResult> SetupLightningNode(string storeId, LightningNodeViewModel vm, string command, string cryptoCode)
|
||||
{
|
||||
vm.CryptoCode = cryptoCode;
|
||||
|
@ -217,6 +219,7 @@ namespace BTCPayServer.Controllers
|
|||
}
|
||||
|
||||
[HttpGet("{storeId}/lightning/{cryptoCode}/settings")]
|
||||
[Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Cookie)]
|
||||
public IActionResult LightningSettings(string storeId, string cryptoCode)
|
||||
{
|
||||
var store = HttpContext.GetStoreData();
|
||||
|
@ -257,6 +260,7 @@ namespace BTCPayServer.Controllers
|
|||
}
|
||||
|
||||
[HttpPost("{storeId}/lightning/{cryptoCode}/settings")]
|
||||
[Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Cookie)]
|
||||
public async Task<IActionResult> LightningSettings(LightningSettingsViewModel vm)
|
||||
{
|
||||
var store = HttpContext.GetStoreData();
|
||||
|
@ -310,6 +314,7 @@ namespace BTCPayServer.Controllers
|
|||
}
|
||||
|
||||
[HttpPost("{storeId}/lightning/{cryptoCode}/status")]
|
||||
[Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Cookie)]
|
||||
public async Task<IActionResult> SetLightningNodeEnabled(string storeId, string cryptoCode, bool enabled)
|
||||
{
|
||||
var store = HttpContext.GetStoreData();
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
using System;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
@ -8,12 +7,12 @@ using System.Threading.Tasks;
|
|||
using BTCPayServer.Abstractions.Constants;
|
||||
using BTCPayServer.Abstractions.Extensions;
|
||||
using BTCPayServer.Abstractions.Models;
|
||||
using BTCPayServer.Client;
|
||||
using BTCPayServer.Data;
|
||||
using BTCPayServer.Events;
|
||||
using BTCPayServer.Models;
|
||||
using BTCPayServer.Models.StoreViewModels;
|
||||
using BTCPayServer.Payments;
|
||||
using BTCPayServer.Services;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using NBitcoin;
|
||||
|
@ -27,6 +26,7 @@ namespace BTCPayServer.Controllers
|
|||
public partial class UIStoresController
|
||||
{
|
||||
[HttpGet("{storeId}/onchain/{cryptoCode}")]
|
||||
[Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Cookie)]
|
||||
public ActionResult SetupWallet(WalletSetupViewModel vm)
|
||||
{
|
||||
var checkResult = IsAvailable(vm.CryptoCode, out var store, out _);
|
||||
|
@ -42,6 +42,7 @@ namespace BTCPayServer.Controllers
|
|||
}
|
||||
|
||||
[HttpGet("{storeId}/onchain/{cryptoCode}/import/{method?}")]
|
||||
[Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Cookie)]
|
||||
public async Task<IActionResult> ImportWallet(WalletSetupViewModel vm)
|
||||
{
|
||||
var checkResult = IsAvailable(vm.CryptoCode, out _, out var network);
|
||||
|
@ -71,6 +72,7 @@ namespace BTCPayServer.Controllers
|
|||
|
||||
[HttpPost("{storeId}/onchain/{cryptoCode}/modify")]
|
||||
[HttpPost("{storeId}/onchain/{cryptoCode}/import/{method}")]
|
||||
[Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Cookie)]
|
||||
public async Task<IActionResult> UpdateWallet(WalletSetupViewModel vm)
|
||||
{
|
||||
var checkResult = IsAvailable(vm.CryptoCode, out var store, out var network);
|
||||
|
@ -197,6 +199,7 @@ namespace BTCPayServer.Controllers
|
|||
}
|
||||
|
||||
[HttpGet("{storeId}/onchain/{cryptoCode}/generate/{method?}")]
|
||||
[Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Cookie)]
|
||||
public async Task<IActionResult> GenerateWallet(WalletSetupViewModel vm)
|
||||
{
|
||||
var checkResult = IsAvailable(vm.CryptoCode, out _, out var network);
|
||||
|
@ -235,8 +238,11 @@ namespace BTCPayServer.Controllers
|
|||
|
||||
return View(vm.ViewName, vm);
|
||||
}
|
||||
|
||||
internal GenerateWalletResponse GenerateWalletResponse;
|
||||
|
||||
[HttpPost("{storeId}/onchain/{cryptoCode}/generate/{method}")]
|
||||
[Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Cookie)]
|
||||
public async Task<IActionResult> GenerateWallet(string storeId, string cryptoCode, WalletSetupMethod method, WalletSetupRequest request)
|
||||
{
|
||||
var checkResult = IsAvailable(cryptoCode, out _, out var network);
|
||||
|
@ -356,6 +362,7 @@ namespace BTCPayServer.Controllers
|
|||
// The purpose of this action is to show the user a success message, which confirms
|
||||
// that the store settings have been updated after generating a new wallet.
|
||||
[HttpGet("{storeId}/onchain/{cryptoCode}/generate/confirm")]
|
||||
[Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Cookie)]
|
||||
public ActionResult GenerateWalletConfirm(string storeId, string cryptoCode)
|
||||
{
|
||||
var checkResult = IsAvailable(cryptoCode, out _, out var network);
|
||||
|
@ -371,6 +378,7 @@ namespace BTCPayServer.Controllers
|
|||
}
|
||||
|
||||
[HttpGet("{storeId}/onchain/{cryptoCode}/settings")]
|
||||
[Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Cookie)]
|
||||
public async Task<IActionResult> WalletSettings(string storeId, string cryptoCode)
|
||||
{
|
||||
var checkResult = IsAvailable(cryptoCode, out var store, out var network);
|
||||
|
@ -440,6 +448,7 @@ namespace BTCPayServer.Controllers
|
|||
}
|
||||
|
||||
[HttpPost("{storeId}/onchain/{cryptoCode}/settings/wallet")]
|
||||
[Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Cookie)]
|
||||
public async Task<IActionResult> UpdateWalletSettings(WalletSettingsViewModel vm)
|
||||
{
|
||||
var checkResult = IsAvailable(vm.CryptoCode, out var store, out _);
|
||||
|
@ -549,6 +558,7 @@ namespace BTCPayServer.Controllers
|
|||
}
|
||||
|
||||
[HttpPost("{storeId}/onchain/{cryptoCode}/settings/payment")]
|
||||
[Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Cookie)]
|
||||
public async Task<IActionResult> UpdatePaymentSettings(WalletSettingsViewModel vm)
|
||||
{
|
||||
var checkResult = IsAvailable(vm.CryptoCode, out var store, out _);
|
||||
|
@ -612,6 +622,7 @@ namespace BTCPayServer.Controllers
|
|||
}
|
||||
|
||||
[HttpGet("{storeId}/onchain/{cryptoCode}/seed")]
|
||||
[Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Cookie)]
|
||||
public async Task<IActionResult> WalletSeed(string storeId, string cryptoCode, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var checkResult = IsAvailable(cryptoCode, out var store, out var network);
|
||||
|
@ -658,6 +669,7 @@ namespace BTCPayServer.Controllers
|
|||
}
|
||||
|
||||
[HttpGet("{storeId}/onchain/{cryptoCode}/replace")]
|
||||
[Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Cookie)]
|
||||
public ActionResult ReplaceWallet(string storeId, string cryptoCode)
|
||||
{
|
||||
var checkResult = IsAvailable(cryptoCode, out var store, out var network);
|
||||
|
@ -677,6 +689,7 @@ namespace BTCPayServer.Controllers
|
|||
}
|
||||
|
||||
[HttpPost("{storeId}/onchain/{cryptoCode}/replace")]
|
||||
[Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Cookie)]
|
||||
public IActionResult ConfirmReplaceWallet(string storeId, string cryptoCode)
|
||||
{
|
||||
var checkResult = IsAvailable(cryptoCode, out var store, out _);
|
||||
|
@ -695,6 +708,7 @@ namespace BTCPayServer.Controllers
|
|||
}
|
||||
|
||||
[HttpGet("{storeId}/onchain/{cryptoCode}/delete")]
|
||||
[Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Cookie)]
|
||||
public ActionResult DeleteWallet(string storeId, string cryptoCode)
|
||||
{
|
||||
var checkResult = IsAvailable(cryptoCode, out var store, out var network);
|
||||
|
@ -714,6 +728,7 @@ namespace BTCPayServer.Controllers
|
|||
}
|
||||
|
||||
[HttpPost("{storeId}/onchain/{cryptoCode}/delete")]
|
||||
[Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Cookie)]
|
||||
public async Task<IActionResult> ConfirmDeleteWallet(string storeId, string cryptoCode)
|
||||
{
|
||||
var checkResult = IsAvailable(cryptoCode, out var store, out var network);
|
||||
|
|
|
@ -1,15 +1,12 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Data;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Amazon.S3.Transfer;
|
||||
using BTCPayServer.Abstractions.Constants;
|
||||
using BTCPayServer.Abstractions.Extensions;
|
||||
using BTCPayServer.Abstractions.Models;
|
||||
using BTCPayServer.Client;
|
||||
using BTCPayServer.Models.ServerViewModels;
|
||||
using BTCPayServer.Services.Stores;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace BTCPayServer.Controllers
|
||||
|
@ -60,19 +57,19 @@ namespace BTCPayServer.Controllers
|
|||
ModelState.Remove(nameof(role));
|
||||
return View(new UpdateRoleViewModel());
|
||||
}
|
||||
else
|
||||
|
||||
var roleData = await storeRepository.GetStoreRole(new StoreRoleId(storeId, role));
|
||||
if (roleData == null)
|
||||
return NotFound();
|
||||
return View(new UpdateRoleViewModel
|
||||
{
|
||||
var roleData = await storeRepository.GetStoreRole(new StoreRoleId(storeId, role));
|
||||
if (roleData == null)
|
||||
return NotFound();
|
||||
return View(new UpdateRoleViewModel()
|
||||
{
|
||||
Policies = roleData.Permissions,
|
||||
Role = roleData.Role
|
||||
});
|
||||
}
|
||||
}
|
||||
Policies = roleData.Permissions,
|
||||
Role = roleData.Role
|
||||
});
|
||||
}
|
||||
|
||||
[HttpPost("{storeId}/roles/{role}")]
|
||||
[Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Cookie)]
|
||||
public async Task<IActionResult> CreateOrEditRole(
|
||||
string storeId,
|
||||
[FromServices] StoreRepository storeRepository,
|
||||
|
@ -119,10 +116,9 @@ namespace BTCPayServer.Controllers
|
|||
|
||||
return RedirectToAction(nameof(ListRoles), new { storeId });
|
||||
}
|
||||
|
||||
|
||||
|
||||
[HttpGet("{storeId}/roles/{role}/delete")]
|
||||
[Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Cookie)]
|
||||
public async Task<IActionResult> DeleteRole(
|
||||
string storeId,
|
||||
[FromServices] StoreRepository storeRepository,
|
||||
|
@ -142,6 +138,7 @@ namespace BTCPayServer.Controllers
|
|||
}
|
||||
|
||||
[HttpPost("{storeId}/roles/{role}/delete")]
|
||||
[Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Cookie)]
|
||||
public async Task<IActionResult> DeleteRolePost(
|
||||
string storeId,
|
||||
[FromServices] StoreRepository storeRepository,
|
||||
|
|
|
@ -12,7 +12,6 @@ using BTCPayServer.Abstractions.Models;
|
|||
using BTCPayServer.Client;
|
||||
using BTCPayServer.Configuration;
|
||||
using BTCPayServer.Data;
|
||||
using BTCPayServer.HostedServices;
|
||||
using BTCPayServer.HostedServices.Webhooks;
|
||||
using BTCPayServer.Models;
|
||||
using BTCPayServer.Models.StoreViewModels;
|
||||
|
@ -39,10 +38,9 @@ using StoreData = BTCPayServer.Data.StoreData;
|
|||
|
||||
namespace BTCPayServer.Controllers
|
||||
{
|
||||
|
||||
[Route("stores")]
|
||||
[Authorize(AuthenticationSchemes = AuthenticationSchemes.Cookie)]
|
||||
[Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Cookie)]
|
||||
[Authorize(Policy = Policies.CanViewStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Cookie)]
|
||||
[AutoValidateAntiforgeryToken]
|
||||
public partial class UIStoresController : Controller
|
||||
{
|
||||
|
@ -145,21 +143,19 @@ namespace BTCPayServer.Controllers
|
|||
if (string.IsNullOrEmpty(userId))
|
||||
return Forbid();
|
||||
|
||||
var store = await _Repo.FindStore(storeId, userId);
|
||||
var store = await _Repo.FindStore(storeId);
|
||||
if (store is null)
|
||||
{
|
||||
return Forbid();
|
||||
}
|
||||
HttpContext.SetStoreData(store);
|
||||
if (store.GetPermissionSet(userId).Contains(Policies.CanModifyStoreSettings, storeId))
|
||||
return NotFound();
|
||||
|
||||
if ((await _authorizationService.AuthorizeAsync(User, Policies.CanModifyStoreSettings)).Succeeded)
|
||||
{
|
||||
return RedirectToAction("Dashboard", new { storeId });
|
||||
}
|
||||
if (store.GetPermissionSet(userId).Contains(Policies.CanViewInvoices, storeId))
|
||||
if ((await _authorizationService.AuthorizeAsync(User, Policies.CanViewInvoices)).Succeeded)
|
||||
{
|
||||
return RedirectToAction("ListInvoices", "UIInvoice", new { storeId });
|
||||
}
|
||||
return View();
|
||||
return Forbid();
|
||||
}
|
||||
|
||||
[HttpGet("{storeId}/users")]
|
||||
|
@ -182,9 +178,10 @@ namespace BTCPayServer.Controllers
|
|||
}).ToList();
|
||||
}
|
||||
|
||||
public StoreData CurrentStore => HttpContext.GetStoreData();
|
||||
public StoreData? CurrentStore => HttpContext.GetStoreData();
|
||||
|
||||
[HttpPost("{storeId}/users")]
|
||||
[Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Cookie)]
|
||||
public async Task<IActionResult> StoreUsers(string storeId, StoreUsersViewModel vm)
|
||||
{
|
||||
await FillUsers(vm);
|
||||
|
@ -217,6 +214,7 @@ namespace BTCPayServer.Controllers
|
|||
}
|
||||
|
||||
[HttpGet("{storeId}/users/{userId}/delete")]
|
||||
[Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Cookie)]
|
||||
public async Task<IActionResult> DeleteStoreUser(string userId)
|
||||
{
|
||||
var user = await _UserManager.FindByIdAsync(userId);
|
||||
|
@ -226,6 +224,7 @@ namespace BTCPayServer.Controllers
|
|||
}
|
||||
|
||||
[HttpPost("{storeId}/users/{userId}/delete")]
|
||||
[Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Cookie)]
|
||||
public async Task<IActionResult> DeleteStoreUserPost(string storeId, string userId)
|
||||
{
|
||||
if (await _Repo.RemoveStoreUser(storeId, userId))
|
||||
|
@ -255,6 +254,7 @@ namespace BTCPayServer.Controllers
|
|||
}
|
||||
|
||||
[HttpPost("{storeId}/rates")]
|
||||
[Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Cookie)]
|
||||
public async Task<IActionResult> Rates(RatesViewModel model, string? command = null, string? storeId = null, CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (command == "scripting-on")
|
||||
|
@ -373,6 +373,7 @@ namespace BTCPayServer.Controllers
|
|||
}
|
||||
|
||||
[HttpGet("{storeId}/rates/confirm")]
|
||||
[Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Cookie)]
|
||||
public IActionResult ShowRateRules(bool scripting)
|
||||
{
|
||||
return View("Confirm", new ConfirmModel
|
||||
|
@ -387,6 +388,7 @@ namespace BTCPayServer.Controllers
|
|||
}
|
||||
|
||||
[HttpPost("{storeId}/rates/confirm")]
|
||||
[Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Cookie)]
|
||||
public async Task<IActionResult> ShowRateRulesPost(bool scripting)
|
||||
{
|
||||
var blob = CurrentStore.GetStoreBlob();
|
||||
|
@ -487,6 +489,7 @@ namespace BTCPayServer.Controllers
|
|||
}
|
||||
|
||||
[HttpPost("{storeId}/checkout")]
|
||||
[Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Cookie)]
|
||||
public async Task<IActionResult> CheckoutAppearance(CheckoutAppearanceViewModel model, [FromForm] bool RemoveSoundFile = false)
|
||||
{
|
||||
bool needUpdate = false;
|
||||
|
@ -723,6 +726,7 @@ namespace BTCPayServer.Controllers
|
|||
}
|
||||
|
||||
[HttpPost("{storeId}/settings")]
|
||||
[Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Cookie)]
|
||||
public async Task<IActionResult> GeneralSettings(
|
||||
GeneralSettingsViewModel model,
|
||||
[FromForm] bool RemoveLogoFile = false,
|
||||
|
@ -863,7 +867,7 @@ namespace BTCPayServer.Controllers
|
|||
}
|
||||
|
||||
[HttpPost("{storeId}/archive")]
|
||||
[Authorize(AuthenticationSchemes = AuthenticationSchemes.Cookie, Policy = Policies.CanModifyStoreSettings)]
|
||||
[Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Cookie)]
|
||||
public async Task<IActionResult> ToggleArchive(string storeId)
|
||||
{
|
||||
CurrentStore.Archived = !CurrentStore.Archived;
|
||||
|
@ -880,12 +884,14 @@ namespace BTCPayServer.Controllers
|
|||
}
|
||||
|
||||
[HttpGet("{storeId}/delete")]
|
||||
[Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Cookie)]
|
||||
public IActionResult DeleteStore(string storeId)
|
||||
{
|
||||
return View("Confirm", new ConfirmModel("Delete store", "The store will be permanently deleted. This action will also delete all invoices, apps and data associated with the store. Are you sure?", "Delete"));
|
||||
}
|
||||
|
||||
[HttpPost("{storeId}/delete")]
|
||||
[Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Cookie)]
|
||||
public async Task<IActionResult> DeleteStorePost(string storeId)
|
||||
{
|
||||
await _Repo.DeleteStore(CurrentStore.Id);
|
||||
|
@ -945,6 +951,7 @@ namespace BTCPayServer.Controllers
|
|||
}
|
||||
|
||||
[HttpGet("{storeId}/tokens/{tokenId}/revoke")]
|
||||
[Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Cookie)]
|
||||
public async Task<IActionResult> RevokeToken(string tokenId)
|
||||
{
|
||||
var token = await _TokenRepository.GetToken(tokenId);
|
||||
|
@ -954,6 +961,7 @@ namespace BTCPayServer.Controllers
|
|||
}
|
||||
|
||||
[HttpPost("{storeId}/tokens/{tokenId}/revoke")]
|
||||
[Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Cookie)]
|
||||
public async Task<IActionResult> RevokeTokenConfirm(string tokenId)
|
||||
{
|
||||
var token = await _TokenRepository.GetToken(tokenId);
|
||||
|
@ -967,6 +975,7 @@ namespace BTCPayServer.Controllers
|
|||
}
|
||||
|
||||
[HttpGet("{storeId}/tokens/{tokenId}")]
|
||||
[Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Cookie)]
|
||||
public async Task<IActionResult> ShowToken(string tokenId)
|
||||
{
|
||||
var token = await _TokenRepository.GetToken(tokenId);
|
||||
|
@ -976,6 +985,7 @@ namespace BTCPayServer.Controllers
|
|||
}
|
||||
|
||||
[HttpGet("{storeId}/tokens/create")]
|
||||
[Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Cookie)]
|
||||
public IActionResult CreateToken(string storeId)
|
||||
{
|
||||
var model = new CreateTokenViewModel();
|
||||
|
@ -987,6 +997,7 @@ namespace BTCPayServer.Controllers
|
|||
}
|
||||
|
||||
[HttpPost("{storeId}/tokens/create")]
|
||||
[Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Cookie)]
|
||||
public async Task<IActionResult> CreateToken(string storeId, CreateTokenViewModel model)
|
||||
{
|
||||
if (!ModelState.IsValid)
|
||||
|
@ -1065,6 +1076,7 @@ namespace BTCPayServer.Controllers
|
|||
}
|
||||
|
||||
[HttpPost("{storeId}/tokens/apikey")]
|
||||
[Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Cookie)]
|
||||
public async Task<IActionResult> GenerateAPIKey(string storeId, string command = "")
|
||||
{
|
||||
var store = HttpContext.GetStoreData();
|
||||
|
@ -1129,6 +1141,7 @@ namespace BTCPayServer.Controllers
|
|||
}
|
||||
|
||||
[HttpPost("/api-access-request")]
|
||||
[Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Cookie)]
|
||||
public async Task<IActionResult> Pair(string pairingCode, string storeId)
|
||||
{
|
||||
if (pairingCode == null)
|
||||
|
|
|
@ -439,7 +439,7 @@ namespace BTCPayServer.Controllers
|
|||
{
|
||||
if (walletId?.StoreId == null)
|
||||
return NotFound();
|
||||
var store = await Repository.FindStore(walletId.StoreId, GetUserId());
|
||||
var store = await Repository.FindStore(walletId.StoreId);
|
||||
var paymentMethod = GetDerivationSchemeSettings(walletId);
|
||||
if (paymentMethod == null || store is null)
|
||||
return NotFound();
|
||||
|
@ -564,7 +564,7 @@ namespace BTCPayServer.Controllers
|
|||
{
|
||||
if (walletId?.StoreId == null)
|
||||
return NotFound();
|
||||
var store = await Repository.FindStore(walletId.StoreId, GetUserId());
|
||||
var store = await Repository.FindStore(walletId.StoreId);
|
||||
if (store == null)
|
||||
return NotFound();
|
||||
var network = NetworkProvider.GetNetwork<BTCPayNetwork>(walletId.CryptoCode);
|
||||
|
|
|
@ -10,7 +10,7 @@ namespace BTCPayServer
|
|||
{
|
||||
public static StoreRole? GetStoreRoleOfUser(this StoreData store, string userId)
|
||||
{
|
||||
return store.UserStores.FirstOrDefault(r => r.ApplicationUserId == userId)?.StoreRole;
|
||||
return store.UserStores?.FirstOrDefault(r => r.ApplicationUserId == userId)?.StoreRole;
|
||||
}
|
||||
|
||||
public static PermissionSet GetPermissionSet(this StoreRole storeRole, string storeId)
|
||||
|
|
|
@ -22,7 +22,7 @@ using Newtonsoft.Json.Linq;
|
|||
|
||||
namespace BTCPayServer.Forms;
|
||||
|
||||
[Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Cookie)]
|
||||
[Authorize(Policy = Policies.CanViewStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Cookie)]
|
||||
public class UIFormsController : Controller
|
||||
{
|
||||
private readonly FormDataService _formDataService;
|
||||
|
@ -48,6 +48,7 @@ public class UIFormsController : Controller
|
|||
}
|
||||
|
||||
[HttpGet("~/stores/{storeId}/forms/new")]
|
||||
[Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Cookie)]
|
||||
public IActionResult Create(string storeId)
|
||||
{
|
||||
var vm = new ModifyForm { FormConfig = new Form().ToString() };
|
||||
|
@ -55,6 +56,7 @@ public class UIFormsController : Controller
|
|||
}
|
||||
|
||||
[HttpGet("~/stores/{storeId}/forms/modify/{id}")]
|
||||
[Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Cookie)]
|
||||
public async Task<IActionResult> Modify(string storeId, string id)
|
||||
{
|
||||
var form = await _formDataService.GetForm(storeId, id);
|
||||
|
@ -66,6 +68,7 @@ public class UIFormsController : Controller
|
|||
}
|
||||
|
||||
[HttpPost("~/stores/{storeId}/forms/modify/{id?}")]
|
||||
[Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Cookie)]
|
||||
public async Task<IActionResult> Modify(string storeId, string? id, ModifyForm modifyForm)
|
||||
{
|
||||
if (id is not null)
|
||||
|
@ -122,6 +125,7 @@ public class UIFormsController : Controller
|
|||
}
|
||||
|
||||
[HttpPost("~/stores/{storeId}/forms/{id}/remove")]
|
||||
[Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Cookie)]
|
||||
public async Task<IActionResult> Remove(string storeId, string id)
|
||||
{
|
||||
await _formDataService.RemoveForm(id, storeId);
|
||||
|
|
|
@ -31,9 +31,10 @@ public class UILightningAutomatedPayoutProcessorsController : Controller
|
|||
_lightningAutomatedPayoutSenderFactory = lightningAutomatedPayoutSenderFactory;
|
||||
_payoutProcessorService = payoutProcessorService;
|
||||
}
|
||||
|
||||
[HttpGet("~/stores/{storeId}/payout-processors/lightning-automated/{cryptocode}")]
|
||||
[Authorize(AuthenticationSchemes = AuthenticationSchemes.Cookie)]
|
||||
[Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Cookie)]
|
||||
[Authorize(Policy = Policies.CanViewStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Cookie)]
|
||||
public async Task<IActionResult> Configure(string storeId, string cryptoCode)
|
||||
{
|
||||
if (!_lightningAutomatedPayoutSenderFactory.GetSupportedPaymentMethods().Any(id =>
|
||||
|
|
|
@ -34,10 +34,9 @@ public class UIOnChainAutomatedPayoutProcessorsController : Controller
|
|||
_payoutProcessorService = payoutProcessorService;
|
||||
}
|
||||
|
||||
|
||||
[HttpGet("~/stores/{storeId}/payout-processors/onchain-automated/{cryptocode}")]
|
||||
[Authorize(AuthenticationSchemes = AuthenticationSchemes.Cookie)]
|
||||
[Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Cookie)]
|
||||
[Authorize(Policy = Policies.CanViewStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Cookie)]
|
||||
public async Task<IActionResult> Configure(string storeId, string cryptoCode)
|
||||
{
|
||||
if (!_onChainAutomatedPayoutSenderFactory.GetSupportedPaymentMethods().Any(id =>
|
||||
|
|
|
@ -34,7 +34,7 @@ public class UIPayoutProcessorsController : Controller
|
|||
|
||||
[HttpGet("~/stores/{storeId}/payout-processors")]
|
||||
[Authorize(AuthenticationSchemes = AuthenticationSchemes.Cookie)]
|
||||
[Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Cookie)]
|
||||
[Authorize(Policy = Policies.CanViewStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Cookie)]
|
||||
public async Task<IActionResult> ConfigureStorePayoutProcessors(string storeId)
|
||||
{
|
||||
var activeProcessors =
|
||||
|
|
|
@ -379,7 +379,7 @@ namespace BTCPayServer.Plugins.Crowdfund.Controllers
|
|||
return View("Views/UIForms/View", viewModel);
|
||||
}
|
||||
|
||||
[Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Cookie)]
|
||||
[Authorize(Policy = Policies.CanViewStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Cookie)]
|
||||
[HttpGet("{appId}/settings/crowdfund")]
|
||||
public async Task<IActionResult> UpdateCrowdfund(string appId)
|
||||
{
|
||||
|
|
|
@ -558,7 +558,7 @@ namespace BTCPayServer.Plugins.PointOfSale.Controllers
|
|||
return Json(recent);
|
||||
}
|
||||
|
||||
[Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Cookie)]
|
||||
[Authorize(Policy = Policies.CanViewStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Cookie)]
|
||||
[HttpGet("{appId}/settings/pos")]
|
||||
public async Task<IActionResult> UpdatePointOfSale(string appId)
|
||||
{
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Abstractions.Constants;
|
||||
using BTCPayServer.Abstractions.Contracts;
|
||||
|
@ -42,7 +42,10 @@ namespace BTCPayServer.Security
|
|||
_pluginHookService = pluginHookService;
|
||||
_paymentRequestRepository = paymentRequestRepository;
|
||||
}
|
||||
|
||||
//TODO: In the future, we will add these store permissions to actual aspnet roles, and remove this class.
|
||||
private static readonly PermissionSet ServerAdminRolePermissions =
|
||||
new PermissionSet(new[] {Permission.Create(Policies.CanViewStoreSettings, null)});
|
||||
|
||||
protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, PolicyRequirement requirement)
|
||||
{
|
||||
if (context.User.Identity.AuthenticationType != AuthenticationSchemes.Cookie)
|
||||
|
@ -67,7 +70,10 @@ namespace BTCPayServer.Security
|
|||
storeId = s;
|
||||
}
|
||||
else
|
||||
{
|
||||
storeId = _httpContext.GetImplicitStoreId();
|
||||
store = _httpContext.GetStoreData();
|
||||
}
|
||||
var routeData = _httpContext.GetRouteData();
|
||||
if (routeData != null)
|
||||
{
|
||||
|
@ -124,12 +130,9 @@ namespace BTCPayServer.Security
|
|||
storeId = null;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(storeId))
|
||||
if (!string.IsNullOrEmpty(storeId) && store is null)
|
||||
{
|
||||
var cachedStore = _httpContext.GetStoreData();
|
||||
store = cachedStore?.Id == storeId
|
||||
? cachedStore
|
||||
: await _storeRepository.FindStore(storeId, userId);
|
||||
store = await _storeRepository.FindStore(storeId, userId);
|
||||
}
|
||||
|
||||
if (Policies.IsServerPolicy(policy) && isAdmin)
|
||||
|
@ -142,14 +145,18 @@ namespace BTCPayServer.Security
|
|||
}
|
||||
else if (Policies.IsStorePolicy(policy))
|
||||
{
|
||||
if (store is not null)
|
||||
if (isAdmin && storeId is not null)
|
||||
{
|
||||
if (store.HasPermission(userId,policy))
|
||||
{
|
||||
success = true;
|
||||
}
|
||||
success = ServerAdminRolePermissions.HasPermission(policy, storeId);
|
||||
|
||||
}
|
||||
else if (requiredUnscoped)
|
||||
|
||||
if (!success && store?.HasPermission(userId, policy) is true)
|
||||
{
|
||||
success = true;
|
||||
}
|
||||
|
||||
if (!success && store is null && requiredUnscoped)
|
||||
{
|
||||
success = true;
|
||||
}
|
||||
|
@ -166,6 +173,11 @@ namespace BTCPayServer.Security
|
|||
context.Succeed(requirement);
|
||||
if (!explicitResource)
|
||||
{
|
||||
if (storeId is not null && store is null)
|
||||
{
|
||||
store = await _storeRepository.FindStore(storeId);
|
||||
|
||||
}
|
||||
if (store != null)
|
||||
{
|
||||
if (_httpContext.GetStoreData()?.Id != store.Id)
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
@using BTCPayServer.Client
|
||||
@using Microsoft.AspNetCore.Mvc.TagHelpers
|
||||
@using BTCPayServer.Views.Apps
|
||||
@using BTCPayServer.Abstractions.Extensions
|
||||
@using BTCPayServer.Abstractions.TagHelpers
|
||||
@using BTCPayServer.Plugins.Crowdfund
|
||||
@using BTCPayServer.Services.Apps
|
||||
@inject AppService AppService;
|
||||
|
@ -14,20 +12,30 @@
|
|||
@if (store != null)
|
||||
{
|
||||
var appType = AppService.GetAppType(CrowdfundAppType.AppType)!;
|
||||
var apps = Model.Apps.Where(app => app.AppType == appType.Type).ToList();
|
||||
<li class="nav-item" permission="@Policies.CanModifyStoreSettings">
|
||||
<a asp-area="" asp-controller="UIApps" asp-action="CreateApp" asp-route-storeId="@store.Id" asp-route-appType="@appType.Type" class="nav-link @ViewData.IsActivePage(AppsNavPages.Create, appType.Type)" id="@($"StoreNav-Create{appType.Type}")">
|
||||
<vc:icon symbol="crowdfund" />
|
||||
<span>@appType.Description</span>
|
||||
</a>
|
||||
</li>
|
||||
@foreach (var app in Model.Apps.Where(app => app.AppType == appType.Type))
|
||||
@if (apps.Any())
|
||||
{
|
||||
<li class="nav-item nav-item-sub" permission="@Policies.CanModifyStoreSettings">
|
||||
<li class="nav-item" not-permission="@Policies.CanModifyStoreSettings" permission="@Policies.CanViewStoreSettings">
|
||||
<span class="nav-link">
|
||||
<vc:icon symbol="crowdfund" />
|
||||
<span>@appType.Description</span>
|
||||
</span>
|
||||
</li>
|
||||
}
|
||||
@foreach (var app in apps)
|
||||
{
|
||||
<li class="nav-item nav-item-sub" permission="@Policies.CanViewStoreSettings">
|
||||
<a asp-area="" asp-controller="UICrowdfund" asp-action="UpdateCrowdfund" asp-route-appId="@app.Id" class="nav-link @ViewData.IsActivePage(AppsNavPages.Update, app.Id)" id="@($"StoreNav-App-{app.Id}")">
|
||||
<span>@app.AppName</span>
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item nav-item-sub" not-permission="@Policies.CanModifyStoreSettings">
|
||||
<li class="nav-item nav-item-sub" not-permission="@Policies.CanViewStoreSettings">
|
||||
<a asp-area="" asp-controller="UICrowdfund" asp-action="ViewCrowdfund" asp-route-appId="@app.Id" class="nav-link">
|
||||
<span>@app.AppName</span>
|
||||
</a>
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
@using System.Globalization
|
||||
@using BTCPayServer.Abstractions.Extensions
|
||||
@using BTCPayServer.Abstractions.Models
|
||||
@using BTCPayServer.Client
|
||||
@using BTCPayServer.TagHelpers
|
||||
@using BTCPayServer.Views.Apps
|
||||
@using Microsoft.AspNetCore.Mvc.TagHelpers
|
||||
|
@ -29,10 +30,10 @@
|
|||
<div class="sticky-header d-sm-flex align-items-center justify-content-between">
|
||||
<h2 class="mb-0">@ViewData["Title"]</h2>
|
||||
<div class="d-flex gap-3 mt-3 mt-sm-0">
|
||||
<button type="submit" class="btn btn-primary order-sm-1" id="SaveSettings">Save</button>
|
||||
<button type="submit" class="btn btn-primary order-sm-1" id="SaveSettings" permission="@Policies.CanModifyStoreSettings">Save</button>
|
||||
@if (Model.Archived)
|
||||
{
|
||||
<button type="submit" class="btn btn-outline-secondary" name="Archived" value="False">Unarchive</button>
|
||||
<button type="submit" class="btn btn-outline-secondary" name="Archived" value="False" permission="@Policies.CanModifyStoreSettings">Unarchive</button>
|
||||
}
|
||||
else if (Model.ModelWithMinimumData)
|
||||
{
|
||||
|
@ -348,7 +349,7 @@
|
|||
|
||||
<div class="d-grid d-sm-flex flex-wrap gap-3 mt-3">
|
||||
<a class="btn btn-secondary" asp-action="ListInvoices" asp-controller="UIInvoice" asp-route-storeId="@Model.StoreId" asp-route-searchterm="@Model.SearchTerm">Invoices</a>
|
||||
<form method="post" asp-controller="UIApps" asp-action="ToggleArchive" asp-route-appId="@Model.AppId">
|
||||
<form method="post" asp-controller="UIApps" asp-action="ToggleArchive" asp-route-appId="@Model.AppId" permission="@Policies.CanModifyStoreSettings">
|
||||
<button type="submit" class="w-100 btn btn-outline-secondary" id="btn-archive-toggle">
|
||||
@if (Model.Archived)
|
||||
{
|
||||
|
@ -360,8 +361,8 @@
|
|||
}
|
||||
</button>
|
||||
</form>
|
||||
<a id="DeleteApp" class="btn btn-outline-danger" asp-controller="UIApps" asp-action="DeleteApp" asp-route-appId="@Model.AppId" data-bs-toggle="modal" data-bs-target="#ConfirmModal" data-description="The app <strong>@Html.Encode(Model.AppName)</strong> and its settings will be permanently deleted." data-confirm-input="DELETE">Delete this app</a>
|
||||
<a id="DeleteApp" class="btn btn-outline-danger" asp-controller="UIApps" asp-action="DeleteApp" asp-route-appId="@Model.AppId" data-bs-toggle="modal" data-bs-target="#ConfirmModal" data-description="The app <strong>@Html.Encode(Model.AppName)</strong> and its settings will be permanently deleted." data-confirm-input="DELETE" permission="@Policies.CanModifyStoreSettings">Delete this app</a>
|
||||
</div>
|
||||
|
||||
<partial name="_Confirm" model="@(new ConfirmModel("Delete app", "This app will be removed from this store.", "Delete"))" />
|
||||
<partial name="_Confirm" model="@(new ConfirmModel("Delete app", "This app will be removed from this store.", "Delete"))" permission="@Policies.CanModifyStoreSettings" />
|
||||
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
@using BTCPayServer.Client
|
||||
@using Microsoft.AspNetCore.Mvc.TagHelpers
|
||||
@using BTCPayServer.Abstractions.TagHelpers
|
||||
@model BTCPayServer.Models.EmailsViewModel
|
||||
|
||||
<div class="row">
|
||||
|
@ -41,7 +44,7 @@
|
|||
<div class="form-text">For many email providers (like Gmail) your login is your email address.</div>
|
||||
<span asp-validation-for="Settings.Login" class="text-danger"></span>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="form-group" permission="@Policies.CanModifyStoreSettings">
|
||||
@if (!Model.PasswordSet)
|
||||
{
|
||||
<label asp-for="Settings.Password" class="form-label"></label>
|
||||
|
@ -74,21 +77,7 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary mt-2" name="command" value="Save" id="Save">Save</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-xl-10 col-xxl-constrain">
|
||||
<div class="form-group">
|
||||
<h3 class="mt-5 mb-3">Testing</h3>
|
||||
<p>
|
||||
To test your settings, enter an email address below.
|
||||
</p>
|
||||
<label asp-for="TestEmail" class="form-label"></label>
|
||||
<input asp-for="TestEmail" placeholder="Firstname Lastname <email@example.com>" class="form-control" />
|
||||
<span asp-validation-for="TestEmail" class="text-danger"></span>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-secondary mt-2" name="command" value="Test" id="Test">Send Test Email</button>
|
||||
<button type="submit" class="btn btn-primary mt-2" name="command" value="Save" id="Save" permission="@Policies.CanModifyStoreSettings">Save</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
13
BTCPayServer/Views/Shared/EmailsTest.cshtml
Normal file
13
BTCPayServer/Views/Shared/EmailsTest.cshtml
Normal file
|
@ -0,0 +1,13 @@
|
|||
@model BTCPayServer.Models.EmailsViewModel
|
||||
|
||||
<h3 class="mt-5 mb-3">Testing</h3>
|
||||
<div class="row">
|
||||
<div class="col-xl-10 col-xxl-constrain">
|
||||
<div class="form-group">
|
||||
<label asp-for="TestEmail" class="form-label">To test your settings, enter an email address</label>
|
||||
<input asp-for="TestEmail" placeholder="Firstname Lastname <email@example.com>" class="form-control" />
|
||||
<span asp-validation-for="TestEmail" class="text-danger"></span>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-secondary mt-2" name="command" value="Test" id="Test">Send Test Email</button>
|
||||
</div>
|
||||
</div>
|
|
@ -1,32 +1,24 @@
|
|||
@using BTCPayServer.Components
|
||||
@using BTCPayServer.Views.Server
|
||||
@using BTCPayServer.Views.Stores
|
||||
@using Microsoft.AspNetCore.Mvc.TagHelpers
|
||||
@using BTCPayServer.Abstractions.Extensions
|
||||
@using BTCPayServer.Client
|
||||
@model BTCPayServer.Models.ServerViewModels.RolesViewModel
|
||||
@{
|
||||
Layout = "_NavLayout.cshtml";
|
||||
var storeId = Context.GetRouteValue("storeId") as string;
|
||||
var controller = ViewContext.RouteData.Values["controller"].ToString().TrimEnd("Controller", StringComparison.InvariantCultureIgnoreCase);
|
||||
if (storeId is null)
|
||||
if (string.IsNullOrEmpty(storeId))
|
||||
ViewData.SetActivePage(ServerNavPages.Roles);
|
||||
|
||||
else
|
||||
{
|
||||
ViewData.SetActivePage(StoreNavPages.Roles);
|
||||
}
|
||||
var permission = string.IsNullOrEmpty(storeId) ? Policies.CanModifyServerSettings : Policies.CanModifyStoreSettings;
|
||||
var nextRoleSortOrder = (string) ViewData["NextRoleSortOrder"];
|
||||
String roleSortOrder = null;
|
||||
switch (nextRoleSortOrder)
|
||||
var roleSortOrder = nextRoleSortOrder switch
|
||||
{
|
||||
case "asc":
|
||||
roleSortOrder = "desc";
|
||||
break;
|
||||
case "desc":
|
||||
roleSortOrder = "asc";
|
||||
break;
|
||||
}
|
||||
"asc" => "desc",
|
||||
"desc" => "asc",
|
||||
_ => null
|
||||
};
|
||||
|
||||
var sortIconClass = "fa-sort";
|
||||
if (roleSortOrder != null)
|
||||
|
@ -36,16 +28,12 @@
|
|||
|
||||
var sortByDesc = "Sort by descending...";
|
||||
var sortByAsc = "Sort by ascending...";
|
||||
|
||||
var showInUseColumn = !Model.Roles.Any(r => r.IsUsed is null);
|
||||
}
|
||||
|
||||
<div class="d-flex align-items-center justify-content-between mb-3">
|
||||
<h3 class="mb-0">@ViewData["Title"]</h3>
|
||||
<a asp-action="CreateOrEditRole" asp-route-storeId="@storeId" class="btn btn-primary" role="button" id="CreateRole" asp-route-role="create"
|
||||
asp-controller="@controller">
|
||||
Add Role
|
||||
</a>
|
||||
<a class="btn btn-primary" role="button" id="CreateRole" asp-controller="@controller" asp-action="CreateOrEditRole" asp-route-role="create" asp-route-storeId="@storeId" permission="@permission">Add Role</a>
|
||||
</div>
|
||||
|
||||
<div class="table-responsive">
|
||||
|
@ -61,15 +49,16 @@
|
|||
class="text-nowrap"
|
||||
title="@(nextRoleSortOrder == "desc" ? sortByAsc : sortByDesc)">
|
||||
Role
|
||||
<span class="fa @(sortIconClass)" />
|
||||
<i class="fa @(sortIconClass)"></i>
|
||||
</a>
|
||||
</th>
|
||||
<th >Permissions</th>
|
||||
<th>Scope</th>
|
||||
<th>Permissions</th>
|
||||
@if (showInUseColumn)
|
||||
{
|
||||
<th>In use</th>
|
||||
<th class="text-center">In use</th>
|
||||
}
|
||||
<th class="text-end">Actions</th>
|
||||
<th class="actions-col" permission="@permission">Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
@ -78,21 +67,29 @@
|
|||
<tr>
|
||||
<td>
|
||||
<div class="d-flex flex-wrap align-items-center gap-2">
|
||||
<span class="me-1">@role.Role</span>
|
||||
@if (role.IsServerRole)
|
||||
<span>@role.Role</span>
|
||||
@if (Model.DefaultRole == role.Id)
|
||||
{
|
||||
<span class="badge bg-dark">
|
||||
Server-wide
|
||||
<span class="badge bg-info">
|
||||
Default
|
||||
</span>
|
||||
@if (Model.DefaultRole == role.Id)
|
||||
{
|
||||
<span class="badge bg-info">
|
||||
Default
|
||||
</span>
|
||||
}
|
||||
}
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
@if (role.IsServerRole)
|
||||
{
|
||||
<span class="badge bg-dark">
|
||||
Server-wide
|
||||
</span>
|
||||
}
|
||||
else
|
||||
{
|
||||
<span class="badge bg-light">
|
||||
Store-level
|
||||
</span>
|
||||
}
|
||||
</td>
|
||||
<td>
|
||||
@if (!role.Permissions.Any())
|
||||
{
|
||||
|
@ -122,28 +119,18 @@
|
|||
}
|
||||
</td>
|
||||
}
|
||||
<td class="text-end">
|
||||
<a permission="@(role.IsServerRole ? Policies.CanModifyServerSettings : Policies.CanModifyStoreSettings)" asp-action="CreateOrEditRole" asp-route-storeId="@storeId" asp-route-role="@role.Role"
|
||||
asp-controller="@(role.IsServerRole ? "UIServer" : "UIStores")">
|
||||
Edit
|
||||
</a> -
|
||||
<a permission="@(role.IsServerRole ? Policies.CanModifyServerSettings : Policies.CanModifyStoreSettings)" asp-action="DeleteRole" asp-route-storeId="@storeId" asp-route-role="@role.Role"
|
||||
asp-controller="@(role.IsServerRole ? "UIServer" : "UIStores")">
|
||||
Remove
|
||||
</a>
|
||||
@if (role.IsServerRole && Model.DefaultRole != role.Id)
|
||||
{
|
||||
|
||||
<a permission="@Policies.CanModifyServerSettings" asp-action="SetDefaultRole" asp-route-role="@role.Role"
|
||||
asp-controller="UIServer" id="SetDefault">
|
||||
- Set as default
|
||||
</a>
|
||||
}
|
||||
<td class="actions-col" permission="@permission">
|
||||
<div class="d-inline-flex align-items-center gap-3">
|
||||
@if (role.IsServerRole && Model.DefaultRole != role.Id)
|
||||
{
|
||||
<a permission="@Policies.CanModifyServerSettings" asp-action="SetDefaultRole" asp-route-role="@role.Role" asp-controller="UIServer" id="SetDefault">Set as default</a>
|
||||
}
|
||||
<a permission="@(role.IsServerRole ? Policies.CanModifyServerSettings : Policies.CanModifyStoreSettings)" asp-action="CreateOrEditRole" asp-route-storeId="@storeId" asp-route-role="@role.Role" asp-controller="@(role.IsServerRole ? "UIServer" : "UIStores")">Edit</a>
|
||||
<a permission="@(role.IsServerRole ? Policies.CanModifyServerSettings : Policies.CanModifyStoreSettings)" asp-action="DeleteRole" asp-route-storeId="@storeId" asp-route-role="@role.Role" asp-controller="@(role.IsServerRole ? "UIServer" : "UIStores")">Remove</a>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<vc:pager view-model="Model"></vc:pager>
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
@using BTCPayServer.Client
|
||||
@using Microsoft.AspNetCore.Mvc.TagHelpers
|
||||
@using BTCPayServer.Views.Apps
|
||||
@using BTCPayServer.Abstractions.Extensions
|
||||
@using BTCPayServer.Abstractions.TagHelpers
|
||||
@using BTCPayServer.Plugins.PointOfSale
|
||||
@using BTCPayServer.Services.Apps
|
||||
@inject AppService AppService;
|
||||
|
@ -14,20 +12,30 @@
|
|||
@if (store != null)
|
||||
{
|
||||
var appType = AppService.GetAppType(PointOfSaleAppType.AppType)!;
|
||||
var apps = Model.Apps.Where(app => app.AppType == appType.Type).ToList();
|
||||
<li class="nav-item" permission="@Policies.CanModifyStoreSettings">
|
||||
<a asp-area="" asp-controller="UIApps" asp-action="CreateApp" asp-route-storeId="@store.Id" asp-route-appType="@appType.Type" class="nav-link @ViewData.IsActivePage(AppsNavPages.Create, appType.Type)" id="@($"StoreNav-Create{appType.Type}")">
|
||||
<vc:icon symbol="pointofsale" />
|
||||
<span>@appType.Description</span>
|
||||
</a>
|
||||
</li>
|
||||
@foreach (var app in Model.Apps.Where(app => app.AppType == appType.Type))
|
||||
@if (apps.Any())
|
||||
{
|
||||
<li class="nav-item nav-item-sub" permission="@Policies.CanModifyStoreSettings">
|
||||
<li class="nav-item" not-permission="@Policies.CanModifyStoreSettings" permission="@Policies.CanViewStoreSettings">
|
||||
<span class="nav-link">
|
||||
<vc:icon symbol="pointofsale" />
|
||||
<span>@appType.Description</span>
|
||||
</span>
|
||||
</li>
|
||||
}
|
||||
@foreach (var app in apps)
|
||||
{
|
||||
<li class="nav-item nav-item-sub" permission="@Policies.CanViewStoreSettings">
|
||||
<a asp-area="" asp-controller="UIPointOfSale" asp-action="UpdatePointOfSale" asp-route-appId="@app.Id" class="nav-link @ViewData.IsActivePage(AppsNavPages.Update, app.Id)" id="@($"StoreNav-App-{app.Id}")">
|
||||
<span>@app.AppName</span>
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item nav-item-sub" not-permission="@Policies.CanModifyStoreSettings">
|
||||
<li class="nav-item nav-item-sub" not-permission="@Policies.CanViewStoreSettings">
|
||||
<a asp-area="" asp-controller="UIPointOfSale" asp-action="ViewPointOfSale" asp-route-appId="@app.Id" class="nav-link">
|
||||
<span>@app.AppName</span>
|
||||
</a>
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
@using BTCPayServer.Abstractions.Models
|
||||
@using BTCPayServer.Views.Apps
|
||||
@using BTCPayServer.Abstractions.Extensions
|
||||
@using BTCPayServer.Client
|
||||
@using BTCPayServer.Plugins.PointOfSale
|
||||
@using BTCPayServer.Forms
|
||||
@using BTCPayServer.TagHelpers
|
||||
@using Microsoft.AspNetCore.Mvc.TagHelpers
|
||||
@inject FormDataService FormDataService
|
||||
@inject BTCPayServer.Security.ContentSecurityPolicies Csp
|
||||
@model BTCPayServer.Plugins.PointOfSale.Models.UpdatePointOfSaleViewModel
|
||||
|
@ -35,10 +37,10 @@
|
|||
<div class="sticky-header d-sm-flex align-items-center justify-content-between">
|
||||
<h2 class="mb-0">@ViewData["Title"]</h2>
|
||||
<div class="d-flex gap-3 mt-3 mt-sm-0">
|
||||
<button type="submit" class="btn btn-primary order-sm-1" id="SaveSettings">Save</button>
|
||||
<button type="submit" class="btn btn-primary order-sm-1" id="SaveSettings" permission="@Policies.CanModifyStoreSettings">Save</button>
|
||||
@if (Model.Archived)
|
||||
{
|
||||
<button type="submit" class="btn btn-outline-secondary" name="Archived" value="False">Unarchive</button>
|
||||
<button type="submit" class="btn btn-outline-secondary" name="Archived" value="False" permission="@Policies.CanModifyStoreSettings">Unarchive</button>
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -318,7 +320,7 @@
|
|||
<div class="d-grid d-sm-flex flex-wrap gap-3 mt-3">
|
||||
<a class="btn btn-secondary" asp-action="ListInvoices" asp-controller="UIInvoice" asp-route-storeId="@Model.StoreId" asp-route-searchterm="@Model.SearchTerm">Invoices</a>
|
||||
<form method="post" asp-controller="UIApps" asp-action="ToggleArchive" asp-route-appId="@Model.Id">
|
||||
<button type="submit" class="w-100 btn btn-outline-secondary" id="btn-archive-toggle">
|
||||
<button type="submit" class="w-100 btn btn-outline-secondary" id="btn-archive-toggle" permission="@Policies.CanModifyStoreSettings">
|
||||
@if (Model.Archived)
|
||||
{
|
||||
<span class="text-nowrap">Unarchive this app</span>
|
||||
|
@ -329,11 +331,10 @@
|
|||
}
|
||||
</button>
|
||||
</form>
|
||||
<a id="DeleteApp" class="btn btn-outline-danger" asp-controller="UIApps" asp-action="DeleteApp" asp-route-appId="@Model.Id" data-bs-toggle="modal" data-bs-target="#ConfirmModal" data-description="The app <strong>@Html.Encode(Model.AppName)</strong> and its settings will be permanently deleted." data-confirm-input="DELETE">Delete this app</a>
|
||||
<a id="DeleteApp" class="btn btn-outline-danger" asp-controller="UIApps" asp-action="DeleteApp" asp-route-appId="@Model.Id" data-bs-toggle="modal" data-bs-target="#ConfirmModal" data-description="The app <strong>@Html.Encode(Model.AppName)</strong> and its settings will be permanently deleted." data-confirm-input="DELETE" permission="@Policies.CanModifyStoreSettings">Delete this app</a>
|
||||
</div>
|
||||
|
||||
<partial name="_Confirm" model="@(new ConfirmModel("Delete app", "This app will be removed from this store.", "Delete"))" />
|
||||
|
||||
<partial name="_Confirm" model="@(new ConfirmModel("Delete app", "This app will be removed from this store.", "Delete"))" permission="@Policies.CanModifyStoreSettings" />
|
||||
<partial name="ShowQR" />
|
||||
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
@using Microsoft.AspNetCore.Mvc.TagHelpers
|
||||
@using BTCPayServer.Abstractions.Models
|
||||
@using BTCPayServer.Client
|
||||
@model List<BTCPayServer.Data.FormData>
|
||||
@{
|
||||
Layout = "../Shared/_NavLayout.cshtml";
|
||||
|
@ -17,7 +18,7 @@
|
|||
<vc:icon symbol="info" />
|
||||
</a>
|
||||
</h3>
|
||||
<a asp-action="Create" asp-route-storeId="@storeId" class="btn btn-primary mt-3 mt-sm-0" role="button" id="CreateForm">
|
||||
<a asp-action="Create" asp-route-storeId="@storeId" class="btn btn-primary mt-3 mt-sm-0" role="button" id="CreateForm" permission="@Policies.CanModifyStoreSettings">
|
||||
Create Form
|
||||
</a>
|
||||
</div>
|
||||
|
@ -27,7 +28,7 @@
|
|||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th class="text-end">Actions</th>
|
||||
<th class="actions-col" permission="@Policies.CanModifyStoreSettings">Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
@ -35,10 +36,10 @@
|
|||
{
|
||||
<tr>
|
||||
<td>
|
||||
<a asp-action="Modify" asp-route-storeId="@item.StoreId" asp-route-id="@item.Id" id="Edit-@item.Name">@item.Name</a>
|
||||
<a asp-action="Modify" asp-route-storeId="@item.StoreId" asp-route-id="@item.Id" id="Edit-@item.Name" permission="@Policies.CanModifyStoreSettings">@item.Name</a>
|
||||
<a asp-action="ViewPublicForm" asp-route-formId="@item.Id" id="View-@item.Name" not-permission="@Policies.CanModifyStoreSettings">View</a>
|
||||
</td>
|
||||
|
||||
<td class="text-end">
|
||||
<td class="actions-col" permission="@Policies.CanModifyStoreSettings">
|
||||
<a asp-action="Remove" asp-route-storeId="@item.StoreId" asp-route-id="@item.Id" id="Remove-@item.Id" data-bs-toggle="modal" data-bs-target="#ConfirmModal" data-confirm-input="DELETE">Remove</a> -
|
||||
<a asp-action="ViewPublicForm" asp-route-formId="@item.Id" id="View-@item.Name">View</a>
|
||||
</td>
|
||||
|
@ -56,4 +57,4 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<partial name="_Confirm" model="@(new ConfirmModel("Delete form", "This form will be removed from this store.", "Delete"))" />
|
||||
<partial name="_Confirm" model="@(new ConfirmModel("Delete form", "This form will be removed from this store.", "Delete"))" permission="@Policies.CanModifyStoreSettings" />
|
||||
|
|
|
@ -107,7 +107,12 @@
|
|||
<vc:icon symbol="info" />
|
||||
</a>
|
||||
</h2>
|
||||
<a id="CreateNewInvoice" asp-action="CreateInvoice" asp-route-storeId="@Model.StoreId" asp-route-searchTerm="@Model.SearchTerm" class="btn btn-primary mt-3 mt-sm-0">
|
||||
<a id="CreateNewInvoice"
|
||||
permission="@Policies.CanCreateInvoice"
|
||||
asp-action="CreateInvoice"
|
||||
asp-route-storeId="@Model.StoreId"
|
||||
asp-route-searchTerm="@Model.SearchTerm"
|
||||
class="btn btn-primary mt-3 mt-sm-0">
|
||||
Create Invoice
|
||||
</a>
|
||||
</div>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
@using BTCPayServer.Abstractions.Extensions
|
||||
@using BTCPayServer.Client
|
||||
@using BTCPayServer.Views.Stores
|
||||
@using Microsoft.AspNetCore.Mvc.TagHelpers
|
||||
@model BTCPayServer.PayoutProcessors.Lightning.UILightningAutomatedPayoutProcessorsController.LightningTransferViewModel
|
||||
|
@ -41,7 +41,7 @@
|
|||
<div class="form-text">If a payout fails this many times, it will be cancelled.</div>
|
||||
</div>
|
||||
|
||||
<button name="command" type="submit" class="btn btn-primary mt-2" value="Save" id="Save">Save</button>
|
||||
<button name="command" type="submit" class="btn btn-primary mt-2" value="Save" id="Save" permission="@Policies.CanModifyStoreSettings">Save</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
@using BTCPayServer.Abstractions.Extensions
|
||||
@using BTCPayServer.Client
|
||||
@using BTCPayServer.Views.Stores
|
||||
@using Microsoft.AspNetCore.Mvc.TagHelpers
|
||||
@model BTCPayServer.PayoutProcessors.OnChain.UIOnChainAutomatedPayoutProcessorsController.OnChainTransferViewModel
|
||||
@{
|
||||
ViewData["NavPartialName"] = "../UIStores/_Nav";
|
||||
|
@ -48,7 +49,7 @@
|
|||
</div>
|
||||
<div class="form-text">Only process payouts when this payout sum is reached.</div>
|
||||
</div>
|
||||
<button name="command" type="submit" class="btn btn-primary mt-2" value="Save" id="Save">Save</button>
|
||||
<button name="command" type="submit" class="btn btn-primary mt-2" value="Save" id="Save" permission="@Policies.CanModifyStoreSettings">Save</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
@using Microsoft.AspNetCore.Mvc.TagHelpers
|
||||
@using BTCPayServer.Abstractions.Extensions
|
||||
@using BTCPayServer.Abstractions.Models
|
||||
@using BTCPayServer.Client
|
||||
@model List<BTCPayServer.PayoutProcessors.UIPayoutProcessorsController.StorePayoutProcessorsView>
|
||||
@{
|
||||
ViewData["NavPartialName"] = "../UIStores/_Nav";
|
||||
|
@ -25,7 +26,7 @@
|
|||
<thead>
|
||||
<tr>
|
||||
<th>Payment Method</th>
|
||||
<th class="text-end">Actions</th>
|
||||
<th class="actions-col" permission="@Policies.CanModifyStoreSettings">Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
@ -35,7 +36,7 @@
|
|||
<td>
|
||||
@conf.Key.ToPrettyString()
|
||||
</td>
|
||||
<td class="text-end">
|
||||
<td class="actions-col" permission="@Policies.CanModifyStoreSettings">
|
||||
@if (conf.Value is null)
|
||||
{
|
||||
<a href="@processorsView.Factory.ConfigureLink(storeId, conf.Key, Context.Request)">Configure</a>
|
||||
|
@ -66,7 +67,7 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<partial name="_Confirm" model="@(new ConfirmModel("Delete payout processor", "This payout processor will be removed from this store.", "Delete"))" />
|
||||
<partial name="_Confirm" model="@(new ConfirmModel("Delete payout processor", "This payout processor will be removed from this store.", "Delete"))" permission="@Policies.CanModifyStoreSettings" />
|
||||
@section PageFootContent {
|
||||
<partial name="_ValidationScriptsPartial"/>
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
</div>
|
||||
</div>
|
||||
<partial name="EmailsBody" model="Model" />
|
||||
<partial name="EmailsTest" model="Model" />
|
||||
</form>
|
||||
|
||||
@section PageFootContent {
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
@using Microsoft.AspNetCore.Mvc.TagHelpers
|
||||
@using BTCPayServer.Abstractions.TagHelpers
|
||||
@using BTCPayServer.Abstractions.Contracts
|
||||
@using BTCPayServer.Client
|
||||
@inject IFileService FileService
|
||||
@model CheckoutAppearanceViewModel
|
||||
@{
|
||||
|
@ -147,7 +148,7 @@
|
|||
<label asp-for="SoundFile" class="form-label"></label>
|
||||
@if (!string.IsNullOrEmpty(Model.SoundFileId))
|
||||
{
|
||||
<button type="submit" class="btn btn-link p-0 text-danger" name="RemoveSoundFile" value="true">
|
||||
<button type="submit" class="btn btn-link p-0 text-danger" name="RemoveSoundFile" value="true" permission="@Policies.CanModifyStoreSettings">
|
||||
<span class="fa fa-times"></span> Remove
|
||||
</button>
|
||||
}
|
||||
|
@ -270,7 +271,7 @@
|
|||
<input asp-for="ReceiptOptions.ShowQR" type="checkbox" class="form-check-input" />
|
||||
<label asp-for="ReceiptOptions.ShowQR" class="form-check-label"></label>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary mt-4" id="Save">Save</button>
|
||||
<button type="submit" class="btn btn-primary mt-4" id="Save" permission="@Policies.CanModifyStoreSettings">Save</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
@using BTCPayServer.Components.StoreWalletBalance
|
||||
@using BTCPayServer.Components.AppSales
|
||||
@using BTCPayServer.Components.AppTopItems
|
||||
@using BTCPayServer.Services.Apps
|
||||
@using BTCPayServer.Client
|
||||
@model StoreDashboardViewModel
|
||||
@{
|
||||
|
|
|
@ -159,31 +159,33 @@
|
|||
<span asp-validation-for="BOLT11Expiration" class="text-danger"></span>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn btn-primary mt-2" id="Save">Save</button>
|
||||
<button type="submit" class="btn btn-primary mt-2" id="Save" permission="@Policies.CanModifyStoreSettings">Save</button>
|
||||
</form>
|
||||
<h3 class="mt-5 mb-3">Additional Actions</h3>
|
||||
<div id="danger-zone" class="d-flex flex-wrap align-items-center gap-3 mb-5 mt-2">
|
||||
<form asp-action="ToggleArchive" asp-route-storeId="@Model.Id" method="post" permission="@Policies.CanModifyStoreSettings">
|
||||
<button type="submit" class="btn btn-outline-secondary" id="btn-archive-toggle">
|
||||
@if (Model.Archived)
|
||||
{
|
||||
<span class="text-nowrap" data-bs-toggle="tooltip" title="Unarchive this store">Unarchive this store</span>
|
||||
}
|
||||
else
|
||||
{
|
||||
<span class="text-nowrap" data-bs-toggle="tooltip" title="Archive this store so that it does not appear in the stores list by default">Archive this store</span>
|
||||
}
|
||||
</button>
|
||||
</form>
|
||||
@if (Model.CanDelete)
|
||||
{
|
||||
<a id="DeleteStore" class="btn btn-outline-danger" asp-action="DeleteStore" asp-route-storeId="@Model.Id" data-bs-toggle="modal" data-bs-target="#ConfirmModal" data-description="The store <strong>@Html.Encode(Model.StoreName)</strong> will be permanently deleted. This action will also delete all invoices, apps and data associated with the store." data-confirm-input="DELETE">Delete this store</a>
|
||||
}
|
||||
<div permission="@Policies.CanModifyStoreSettings">
|
||||
<h3 class="mt-5 mb-3">Additional Actions</h3>
|
||||
<div id="danger-zone" class="d-flex flex-wrap align-items-center gap-3 mb-5 mt-2">
|
||||
<form asp-action="ToggleArchive" asp-route-storeId="@Model.Id" method="post">
|
||||
<button type="submit" class="btn btn-outline-secondary" id="btn-archive-toggle">
|
||||
@if (Model.Archived)
|
||||
{
|
||||
<span class="text-nowrap" data-bs-toggle="tooltip" title="Unarchive this store">Unarchive this store</span>
|
||||
}
|
||||
else
|
||||
{
|
||||
<span class="text-nowrap" data-bs-toggle="tooltip" title="Archive this store so that it does not appear in the stores list by default">Archive this store</span>
|
||||
}
|
||||
</button>
|
||||
</form>
|
||||
@if (Model.CanDelete)
|
||||
{
|
||||
<a id="DeleteStore" class="btn btn-outline-danger" asp-action="DeleteStore" asp-route-storeId="@Model.Id" data-bs-toggle="modal" data-bs-target="#ConfirmModal" data-description="The store <strong>@Html.Encode(Model.StoreName)</strong> will be permanently deleted. This action will also delete all invoices, apps and data associated with the store." data-confirm-input="DELETE">Delete this store</a>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<partial name="_Confirm" model="@(new ConfirmModel("Delete store", "The store will be permanently deleted. This action will also delete all invoices, apps and data associated with the store.", "Delete"))" />
|
||||
<partial name="_Confirm" model="@(new ConfirmModel("Delete store", "The store will be permanently deleted. This action will also delete all invoices, apps and data associated with the store.", "Delete"))" permission="@Policies.CanModifyStoreSettings" />
|
||||
|
||||
@section PageFootContent {
|
||||
<partial name="_ValidationScriptsPartial"/>
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
@using BTCPayServer.Abstractions.Models
|
||||
@using BTCPayServer.Client
|
||||
@using Microsoft.AspNetCore.Mvc.TagHelpers
|
||||
@model TokensViewModel
|
||||
@{
|
||||
Layout = "../Shared/_NavLayout.cshtml";
|
||||
|
@ -27,7 +29,7 @@
|
|||
|
||||
<div class="d-flex align-items-center justify-content-between mt-5 mb-3">
|
||||
<h3 class="mb-0">@ViewData["Title"]</h3>
|
||||
<a id="CreateNewToken" asp-action="CreateToken" class="btn btn-primary" role="button" asp-route-storeId="@Context.GetRouteValue("storeId")">
|
||||
<a id="CreateNewToken" asp-action="CreateToken" class="btn btn-primary" role="button" asp-route-storeId="@Context.GetRouteValue("storeId")" permission="@Policies.CanModifyStoreSettings">
|
||||
Create Token
|
||||
</a>
|
||||
</div>
|
||||
|
@ -43,7 +45,7 @@
|
|||
<thead>
|
||||
<tr>
|
||||
<th>Label</th>
|
||||
<th class="text-end">Actions</th>
|
||||
<th class="text-end" permission="@Policies.CanModifyStoreSettings">Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
@ -51,7 +53,7 @@
|
|||
{
|
||||
<tr>
|
||||
<td>@token.Label</td>
|
||||
<td class="text-end">
|
||||
<td class="text-end" permission="@Policies.CanModifyStoreSettings">
|
||||
<a asp-action="ShowToken" asp-route-storeId="@Context.GetRouteValue("storeId")" asp-route-tokenId="@token.Id">See information</a> -
|
||||
<a asp-action="RevokeToken" asp-route-storeId="@Context.GetRouteValue("storeId")" asp-route-tokenId="@token.Id" data-bs-toggle="modal" data-bs-target="#ConfirmModal" data-description="The access token with the label <strong>@Html.Encode(token.Label)</strong> will be revoked." data-confirm-input="REVOKE">Revoke</a>
|
||||
</td>
|
||||
|
@ -71,7 +73,7 @@
|
|||
<p>Alternatively, you can use the invoice API by including the following HTTP Header in your requests:</p>
|
||||
<p><code>Authorization: Basic @Model.EncodedApiKey</code></p>
|
||||
|
||||
<form method="post" asp-action="GenerateAPIKey" asp-route-storeId="@Context.GetRouteValue("storeId")">
|
||||
<form method="post" asp-action="GenerateAPIKey" asp-route-storeId="@Context.GetRouteValue("storeId")" permission="@Policies.CanModifyStoreSettings">
|
||||
<div class="form-group">
|
||||
<label asp-for="ApiKey" class="form-label"></label>
|
||||
<div class="d-flex">
|
||||
|
@ -91,4 +93,4 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<partial name="_Confirm" model="@(new ConfirmModel("Revoke access token", "The access token will be revoked. Do you wish to continue?", "Revoke"))" />
|
||||
<partial name="_Confirm" model="@(new ConfirmModel("Revoke access token", "The access token will be revoked. Do you wish to continue?", "Revoke"))" permission="@Policies.CanModifyStoreSettings" />
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
@using BTCPayServer.Abstractions.Models
|
||||
@using BTCPayServer.Abstractions.TagHelpers
|
||||
@using BTCPayServer.Client
|
||||
@using Microsoft.AspNetCore.Mvc.TagHelpers
|
||||
@model BTCPayServer.Models.StoreViewModels.RatesViewModel
|
||||
@{
|
||||
Layout = "../Shared/_NavLayout.cshtml";
|
||||
|
@ -141,7 +144,7 @@ X_X = kraken(X_X);</code></pre>
|
|||
}
|
||||
<div class="form-group">
|
||||
<label class="d-flex align-items-center">
|
||||
<button type="submit" id="ShowScripting" class="btcpay-toggle me-3 @if (Model.ShowScripting) { @("btcpay-toggle--active") }" value="scripting-@(Model.ShowScripting ? "off" : "on")" name="command" data-bs-toggle="modal" data-bs-target="#ConfirmModal">@(Model.ShowScripting ? "Disable" : "Enable") advanced rate rule scripting</button>
|
||||
<button type="submit" id="ShowScripting" class="btcpay-toggle me-3 @if (Model.ShowScripting) { @("btcpay-toggle--active") }" value="scripting-@(Model.ShowScripting ? "off" : "on")" name="command" data-bs-toggle="modal" data-bs-target="#ConfirmModal" permission="@Policies.CanModifyStoreSettings">@(Model.ShowScripting ? "Disable" : "Enable") advanced rate rule scripting</button>
|
||||
<div class="">
|
||||
<span>Advanced rate rule scripting</span>
|
||||
<div class="form-text">
|
||||
|
@ -164,7 +167,7 @@ X_X = kraken(X_X);</code></pre>
|
|||
<label asp-for="ScriptTest" class="form-label">Currency pairs to test against your rule (e.g. <code>DOGE_USD,DOGE_CAD,BTC_CAD,BTC_USD</code>)</label>
|
||||
<div class="d-flex">
|
||||
<input asp-for="ScriptTest" class="form-control" placeholder="BTC_USD, BTC_CAD" />
|
||||
<button name="command" value="Test" type="submit" class="btn btn-secondary ms-3" title="Test">Test</button>
|
||||
<button name="command" value="Test" type="submit" class="btn btn-secondary ms-3" title="Test" permission="@Policies.CanModifyStoreSettings">Test</button>
|
||||
</div>
|
||||
<span asp-validation-for="ScriptTest" class="text-danger"></span>
|
||||
</div>
|
||||
|
@ -175,13 +178,12 @@ X_X = kraken(X_X);</code></pre>
|
|||
<input asp-for="DefaultCurrencyPairs" class="form-control" placeholder="BTC_USD, BTC_CAD" />
|
||||
<span asp-validation-for="DefaultCurrencyPairs" class="text-danger"></span>
|
||||
</div>
|
||||
<button name="command" type="submit" class="btn btn-primary mt-2" value="Save">Save</button>
|
||||
<button name="command" type="submit" class="btn btn-primary mt-2" value="Save" permission="@Policies.CanModifyStoreSettings">Save</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<partial name="_Confirm" model="@(new ConfirmModel("Rate rule scripting", Model.ShowScripting ? "This action will delete your rate script. Are you sure to turn off rate rules scripting?" : "This action will modify your current rate sources. Are you sure to turn on rate rules scripting? (Advanced users)", "Continue", Model.ShowScripting ? "btn-danger" : "btn-primary"))" />
|
||||
|
||||
<partial name="_Confirm" model="@(new ConfirmModel("Rate rule scripting", Model.ShowScripting ? "This action will delete your rate script. Are you sure to turn off rate rules scripting?" : "This action will modify your current rate sources. Are you sure to turn on rate rules scripting? (Advanced users)", "Continue", Model.ShowScripting ? "btn-danger" : "btn-primary"))" permission="@Policies.CanModifyStoreSettings" />
|
||||
|
||||
@section PageHeadContent {
|
||||
<link rel="stylesheet" href="~/vendor/highlightjs/default.min.css" asp-append-version="true">
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
@using BTCPayServer.Client
|
||||
@using Microsoft.AspNetCore.Mvc.TagHelpers
|
||||
@model BTCPayServer.Models.EmailsViewModel
|
||||
@{
|
||||
Layout = "../Shared/_NavLayout.cshtml";
|
||||
|
@ -9,7 +11,7 @@
|
|||
<div class="col-xl-10 col-xxl-constrain">
|
||||
<div class="d-flex flex-wrap gap-3 align-items-center justify-content-between mt-n1 mb-4">
|
||||
<h3 class="mb-0">Email Rules</h3>
|
||||
<a class="btn btn-secondary" asp-action="StoreEmails" asp-controller="UIStores" asp-route-storeId="@Context.GetStoreData().Id" id="ConfigureEmailRules">
|
||||
<a class="btn btn-secondary" asp-action="StoreEmails" asp-controller="UIStores" asp-route-storeId="@Context.GetStoreData().Id" id="ConfigureEmailRules" permission="@Policies.CanModifyStoreSettings">
|
||||
Configure
|
||||
</a>
|
||||
</div>
|
||||
|
@ -41,6 +43,8 @@
|
|||
{
|
||||
<partial name="EmailsBody" model="Model" />
|
||||
}
|
||||
|
||||
<partial name="EmailsTest" model="Model" permission="@Policies.CanModifyStoreSettings" />
|
||||
</form>
|
||||
|
||||
@section PageFootContent {
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
@using BTCPayServer.HostedServices.Webhooks
|
||||
@using Microsoft.AspNetCore.Mvc.TagHelpers
|
||||
@using BTCPayServer.Client
|
||||
@using BTCPayServer.Abstractions.TagHelpers
|
||||
@model BTCPayServer.Controllers.UIStoresController.StoreEmailRuleViewModel
|
||||
@inject WebhookSender WebhookSender
|
||||
|
||||
|
@ -15,7 +18,7 @@
|
|||
<div class="col-xxl-constrain">
|
||||
<div class="d-flex align-items-center justify-content-between mt-n1 mb-3">
|
||||
<h3 class="mb-0">@ViewData["Title"]</h3>
|
||||
<div class="d-flex gap-3">
|
||||
<div class="d-flex gap-3" permission="@Policies.CanModifyStoreSettings">
|
||||
@if (Model.Rules.Any())
|
||||
{
|
||||
<button class="btn btn-primary" name="command" type="submit" value="save" id="SaveEmailRules">
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
@using BTCPayServer.Abstractions.Models
|
||||
@using BTCPayServer.Services.Stores
|
||||
@using BTCPayServer.Abstractions.Contracts
|
||||
@using BTCPayServer.Client
|
||||
@using Microsoft.AspNetCore.Mvc.TagHelpers
|
||||
@model StoreUsersViewModel
|
||||
@inject IScopeProvider ScopeProvider
|
||||
@inject StoreRepository StoreRepository
|
||||
|
@ -23,48 +25,37 @@
|
|||
<div asp-validation-summary="All"></div>
|
||||
}
|
||||
|
||||
<form method="post">
|
||||
<div class="d-flex">
|
||||
<div class="flex-grow-1">
|
||||
<input asp-for="Email" type="text" class="form-control" placeholder="user@example.com">
|
||||
</div>
|
||||
<div class="ms-3">
|
||||
<select asp-for="Role" class="form-select" asp-items="roles">
|
||||
</select>
|
||||
</div>
|
||||
<div class="ms-3">
|
||||
<button type="submit" role="button" class="btn btn-primary" id="AddUser">Add User</button>
|
||||
</div>
|
||||
</div>
|
||||
<form method="post" class="d-flex flex-wrap align-items-center gap-3" permission="@Policies.CanModifyStoreSettings">
|
||||
<input asp-for="Email" type="text" class="form-control" placeholder="user@example.com" style="flex: 1 1 14rem">
|
||||
<select asp-for="Role" class="form-select w-auto" asp-items="roles"></select>
|
||||
<button type="submit" role="button" class="btn btn-primary text-nowrap flex-grow-1 flex-sm-grow-0" id="AddUser">Add User</button>
|
||||
</form>
|
||||
|
||||
<div class="form-group">
|
||||
<table class="table table-hover table-responsive-md">
|
||||
<thead>
|
||||
<table class="table table-hover table-responsive-md">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Email</th>
|
||||
<th>Role</th>
|
||||
<th class="actions-col" permission="@Policies.CanModifyStoreSettings">Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach (var user in Model.Users)
|
||||
{
|
||||
<tr>
|
||||
<th>Email</th>
|
||||
<th>Role</th>
|
||||
<th style="text-align:right">Actions</th>
|
||||
<td>@user.Email</td>
|
||||
<td>@user.Role</td>
|
||||
<td class="actions-col" permission="@Policies.CanModifyStoreSettings">
|
||||
<a asp-action="DeleteStoreUser" asp-route-storeId="@Model.StoreId" asp-route-userId="@user.Id" data-bs-toggle="modal" data-bs-target="#ConfirmModal" data-description="This action will prevent <strong>@Html.Encode(user.Email)</strong> from accessing this store and its settings." data-confirm-input="REMOVE">Remove</a>
|
||||
</td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach (var user in Model.Users)
|
||||
{
|
||||
<tr>
|
||||
<td>@user.Email</td>
|
||||
<td>@user.Role</td>
|
||||
<td style="text-align:right">
|
||||
<a asp-action="DeleteStoreUser" asp-route-storeId="@Model.StoreId" asp-route-userId="@user.Id" data-bs-toggle="modal" data-bs-target="#ConfirmModal" data-description="This action will prevent <strong>@Html.Encode(user.Email)</strong> from accessing this store and its settings." data-confirm-input="REMOVE">Remove</a>
|
||||
</td>
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<partial name="_Confirm" model="@(new ConfirmModel("Remove store user", "This action will prevent the user from accessing this store and its settings. Are you sure?", "Delete"))" />
|
||||
<partial name="_Confirm" model="@(new ConfirmModel("Remove store user", "This action will prevent the user from accessing this store and its settings. Are you sure?", "Delete"))" permission="@Policies.CanModifyStoreSettings" />
|
||||
|
||||
@section PageFootContent {
|
||||
<partial name="_ValidationScriptsPartial" />
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
@using BTCPayServer.Abstractions.Models
|
||||
@using BTCPayServer.Client
|
||||
@using Microsoft.AspNetCore.Mvc.TagHelpers
|
||||
@model WebhooksViewModel
|
||||
@{
|
||||
Layout = "../Shared/_NavLayout.cshtml";
|
||||
|
@ -8,7 +10,7 @@
|
|||
<div class="col-xl-8 col-xxl-constrain">
|
||||
<div class="d-flex align-items-center justify-content-between mb-3">
|
||||
<h3 class="mb-0">@ViewData["Title"]</h3>
|
||||
<a id="CreateWebhook" asp-action="NewWebhook" class="btn btn-primary" role="button" asp-route-storeId="@Context.GetRouteValue("storeId")">
|
||||
<a id="CreateWebhook" asp-action="NewWebhook" class="btn btn-primary" role="button" asp-route-storeId="@Context.GetRouteValue("storeId")" permission="@Policies.CanModifyStoreSettings">
|
||||
Create Webhook
|
||||
</a>
|
||||
</div>
|
||||
|
@ -21,7 +23,7 @@
|
|||
<tr>
|
||||
<th>Status</th>
|
||||
<th>Url</th>
|
||||
<th class="text-end">Actions</th>
|
||||
<th class="text-end" permission="@Policies.CanModifyStoreSettings">Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
@ -46,7 +48,7 @@
|
|||
}
|
||||
</td>
|
||||
<td class="d-block text-break">@wh.Url</td>
|
||||
<td class="text-end text-md-nowrap">
|
||||
<td class="text-end text-md-nowrap" permission="@Policies.CanModifyStoreSettings">
|
||||
<a asp-action="TestWebhook" asp-route-storeId="@Context.GetRouteValue("storeId")" asp-route-webhookId="@wh.Id">Test</a> -
|
||||
<a asp-action="ModifyWebhook" asp-route-storeId="@Context.GetRouteValue("storeId")" asp-route-webhookId="@wh.Id">Modify</a> -
|
||||
<a asp-action="DeleteWebhook" asp-route-storeId="@Context.GetRouteValue("storeId")" asp-route-webhookId="@wh.Id" data-bs-toggle="modal" data-bs-target="#ConfirmModal" data-confirm-input="DELETE">Delete</a>
|
||||
|
@ -56,7 +58,7 @@
|
|||
</tbody>
|
||||
</table>
|
||||
|
||||
<partial name="_Confirm" model="@(new ConfirmModel("Delete Webhook", "This webhook will be removed from this store.", "Delete"))" />
|
||||
<partial name="_Confirm" model="@(new ConfirmModel("Delete Webhook", "This webhook will be removed from this store.", "Delete"))" permission="@Policies.CanModifyStoreSettings" />
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -6,18 +6,18 @@
|
|||
|
||||
<div class="sticky-header mb-l">
|
||||
<h2 class="mt-1 mb-2 mb-lg-4">Store Settings</h2>
|
||||
<nav id="SectionNav">
|
||||
<nav id="SectionNav" permission="@Policies.CanViewStoreSettings">
|
||||
<div class="nav">
|
||||
<a permission="@Policies.CanModifyStoreSettings" id="SectionNav-@(nameof(StoreNavPages.General))" class="nav-link @ViewData.IsActivePage(StoreNavPages.General)" asp-controller="UIStores" asp-action="GeneralSettings" asp-route-storeId="@storeId">General</a>
|
||||
<a permission="@Policies.CanModifyStoreSettings" id="SectionNav-@(nameof(StoreNavPages.Rates))" class="nav-link @ViewData.IsActivePage(StoreNavPages.Rates)" asp-controller="UIStores" asp-action="Rates" asp-route-storeId="@storeId">Rates</a>
|
||||
<a permission="@Policies.CanModifyStoreSettings" id="SectionNav-@(nameof(StoreNavPages.CheckoutAppearance))" class="nav-link @ViewData.IsActivePage(StoreNavPages.CheckoutAppearance)" asp-controller="UIStores" asp-action="CheckoutAppearance" asp-route-storeId="@storeId">Checkout Appearance</a>
|
||||
<a permission="@Policies.CanModifyStoreSettings" id="SectionNav-@(nameof(StoreNavPages.Tokens))" class="nav-link @ViewData.IsActivePage(StoreNavPages.Tokens)" asp-controller="UIStores" asp-action="ListTokens" asp-route-storeId="@storeId">Access Tokens</a>
|
||||
<a permission="@Policies.CanModifyStoreSettings" id="SectionNav-@(nameof(StoreNavPages.Users))" class="nav-link @ViewData.IsActivePage(StoreNavPages.Users)" asp-controller="UIStores" asp-action="StoreUsers" asp-route-storeId="@storeId">Users</a>
|
||||
<a permission="@Policies.CanModifyStoreSettings" id="SectionNav-@(nameof(StoreNavPages.Roles))" class="nav-link @ViewData.IsActivePage(StoreNavPages.Roles)" asp-controller="UIStores" asp-action="ListRoles" asp-route-storeId="@storeId">Roles</a>
|
||||
<a permission="@Policies.CanModifyStoreSettings" id="SectionNav-@(nameof(StoreNavPages.Webhooks))" class="nav-link @ViewData.IsActivePage(StoreNavPages.Webhooks)" asp-controller="UIStores" asp-action="Webhooks" asp-route-storeId="@storeId">Webhooks</a>
|
||||
<a permission="@Policies.CanModifyStoreSettings" id="SectionNav-@(nameof(StoreNavPages.PayoutProcessors))" class="nav-link @ViewData.IsActivePage(StoreNavPages.PayoutProcessors)" asp-controller="UIPayoutProcessors" asp-action="ConfigureStorePayoutProcessors" asp-route-storeId="@storeId">Payout Processors</a>
|
||||
<a permission="@Policies.CanModifyStoreSettings" id="SectionNav-@(nameof(StoreNavPages.Emails))" class="nav-link @ViewData.IsActivePage(StoreNavPages.Emails)" asp-controller="UIStores" asp-action="StoreEmailSettings" asp-route-storeId="@storeId">Emails</a>
|
||||
<a permission="@Policies.CanModifyStoreSettings" id="SectionNav-@(nameof(StoreNavPages.Forms))" class="nav-link @ViewData.IsActivePage(StoreNavPages.Forms)" asp-controller="UIForms" asp-action="FormsList" asp-route-storeId="@storeId">Forms</a>
|
||||
<a id="SectionNav-@(nameof(StoreNavPages.General))" class="nav-link @ViewData.IsActivePage(StoreNavPages.General)" asp-controller="UIStores" asp-action="GeneralSettings" asp-route-storeId="@storeId">General</a>
|
||||
<a id="SectionNav-@(nameof(StoreNavPages.Rates))" class="nav-link @ViewData.IsActivePage(StoreNavPages.Rates)" asp-controller="UIStores" asp-action="Rates" asp-route-storeId="@storeId">Rates</a>
|
||||
<a id="SectionNav-@(nameof(StoreNavPages.CheckoutAppearance))" class="nav-link @ViewData.IsActivePage(StoreNavPages.CheckoutAppearance)" asp-controller="UIStores" asp-action="CheckoutAppearance" asp-route-storeId="@storeId">Checkout Appearance</a>
|
||||
<a id="SectionNav-@(nameof(StoreNavPages.Tokens))" class="nav-link @ViewData.IsActivePage(StoreNavPages.Tokens)" asp-controller="UIStores" asp-action="ListTokens" asp-route-storeId="@storeId">Access Tokens</a>
|
||||
<a id="SectionNav-@(nameof(StoreNavPages.Users))" class="nav-link @ViewData.IsActivePage(StoreNavPages.Users)" asp-controller="UIStores" asp-action="StoreUsers" asp-route-storeId="@storeId">Users</a>
|
||||
<a id="SectionNav-@(nameof(StoreNavPages.Roles))" class="nav-link @ViewData.IsActivePage(StoreNavPages.Roles)" asp-controller="UIStores" asp-action="ListRoles" asp-route-storeId="@storeId">Roles</a>
|
||||
<a id="SectionNav-@(nameof(StoreNavPages.Webhooks))" class="nav-link @ViewData.IsActivePage(StoreNavPages.Webhooks)" asp-controller="UIStores" asp-action="Webhooks" asp-route-storeId="@storeId">Webhooks</a>
|
||||
<a id="SectionNav-@(nameof(StoreNavPages.PayoutProcessors))" class="nav-link @ViewData.IsActivePage(StoreNavPages.PayoutProcessors)" asp-controller="UIPayoutProcessors" asp-action="ConfigureStorePayoutProcessors" asp-route-storeId="@storeId">Payout Processors</a>
|
||||
<a id="SectionNav-@(nameof(StoreNavPages.Emails))" class="nav-link @ViewData.IsActivePage(StoreNavPages.Emails)" asp-controller="UIStores" asp-action="StoreEmailSettings" asp-route-storeId="@storeId">Emails</a>
|
||||
<a id="SectionNav-@(nameof(StoreNavPages.Forms))" class="nav-link @ViewData.IsActivePage(StoreNavPages.Forms)" asp-controller="UIForms" asp-action="FormsList" asp-route-storeId="@storeId">Forms</a>
|
||||
<vc:ui-extension-point location="store-nav" model="@Model"/>
|
||||
</div>
|
||||
</nav>
|
||||
|
|
|
@ -24,13 +24,7 @@
|
|||
{
|
||||
<tr>
|
||||
<td>
|
||||
<a
|
||||
permission="@Policies.CanModifyStoreSettings"
|
||||
asp-action="GeneralSettings" asp-controller="UIStores" asp-route-storeId="@store.StoreId"
|
||||
id="Store-@store.StoreId">
|
||||
@store.StoreName
|
||||
</a>
|
||||
<span not-permission="@Policies.CanModifyStoreSettings">@store.StoreName</span>
|
||||
<a asp-action="Index" asp-controller="UIStores" asp-route-storeId="@store.StoreId" id="Store-@store.StoreId">@store.StoreName</a>
|
||||
@if (store.Archived)
|
||||
{
|
||||
<span class="badge bg-info ms-2">archived</span>
|
||||
|
|
|
@ -94,14 +94,14 @@
|
|||
white-space: nowrap;
|
||||
}
|
||||
|
||||
#mainNav .navbar-nav > li.nav-item .nav-link:focus,
|
||||
#mainNav .navbar-nav > li.nav-item .nav-link:hover {
|
||||
#mainNav .navbar-nav > li.nav-item a.nav-link:focus,
|
||||
#mainNav .navbar-nav > li.nav-item a.nav-link:hover {
|
||||
color: var(--btcpay-header-link-accent);
|
||||
}
|
||||
|
||||
#mainNav .navbar-nav > li.nav-item .nav-link.active,
|
||||
#mainNav .navbar-nav > li.nav-item .nav-link.active:focus,
|
||||
#mainNav .navbar-nav > li.nav-item .nav-link.active:hover {
|
||||
#mainNav .navbar-nav > li.nav-item a.nav-link.active,
|
||||
#mainNav .navbar-nav > li.nav-item a.nav-link.active:focus,
|
||||
#mainNav .navbar-nav > li.nav-item a.nav-link.active:hover {
|
||||
color: var(--btcpay-header-link-active);
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue