mirror of
https://github.com/aljazceru/btcpayserver.git
synced 2026-01-01 05:04:28 +01:00
HTML lang setting and Head tags for POS and Crowdfund public pages (#6229)
* HTML lang setting and Head tags for POS and Crowdfund public pages * updates #6229 * updates 6229 * resolve conflict * updated according to Nicolas' recommendations * updates #6229 * Add RawMeta method in safe.cs * ... * resolve conflicts * resolve conflict * resolve conflicts * Updates as Nicolas request * updates --------- Co-authored-by: d11n <mail@dennisreimann.de>
This commit is contained in:
@@ -8,6 +8,7 @@ using BTCPayServer.Abstractions.Contracts;
|
||||
using BTCPayServer.Abstractions.Extensions;
|
||||
using BTCPayServer.Abstractions.Form;
|
||||
using BTCPayServer.Abstractions.Models;
|
||||
using BTCPayServer.Abstractions.Services;
|
||||
using BTCPayServer.Client;
|
||||
using BTCPayServer.Client.Models;
|
||||
using BTCPayServer.Controllers;
|
||||
@@ -22,6 +23,7 @@ using BTCPayServer.Services.Apps;
|
||||
using BTCPayServer.Services.Invoices;
|
||||
using BTCPayServer.Services.Rates;
|
||||
using BTCPayServer.Services.Stores;
|
||||
using Ganss.Xss;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Cors;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
@@ -51,7 +53,8 @@ namespace BTCPayServer.Plugins.Crowdfund.Controllers
|
||||
UserManager<ApplicationUser> userManager,
|
||||
FormDataService formDataService,
|
||||
IStringLocalizer stringLocalizer,
|
||||
CrowdfundAppType app)
|
||||
CrowdfundAppType app,
|
||||
Safe safe)
|
||||
{
|
||||
_currencies = currencies;
|
||||
_appService = appService;
|
||||
@@ -64,6 +67,7 @@ namespace BTCPayServer.Plugins.Crowdfund.Controllers
|
||||
_invoiceController = invoiceController;
|
||||
FormDataService = formDataService;
|
||||
StringLocalizer = stringLocalizer;
|
||||
_safe = safe;
|
||||
}
|
||||
|
||||
private readonly EventAggregator _eventAggregator;
|
||||
@@ -75,6 +79,8 @@ namespace BTCPayServer.Plugins.Crowdfund.Controllers
|
||||
private readonly UIInvoiceController _invoiceController;
|
||||
private readonly UserManager<ApplicationUser> _userManager;
|
||||
private readonly CrowdfundAppType _app;
|
||||
private readonly Safe _safe;
|
||||
|
||||
public FormDataService FormDataService { get; }
|
||||
public IStringLocalizer StringLocalizer { get; }
|
||||
|
||||
@@ -403,6 +409,8 @@ namespace BTCPayServer.Plugins.Crowdfund.Controllers
|
||||
Enabled = settings.Enabled,
|
||||
EnforceTargetAmount = settings.EnforceTargetAmount,
|
||||
StartDate = settings.StartDate,
|
||||
HtmlMetaTags= settings.HtmlMetaTags,
|
||||
Language = settings.Language,
|
||||
TargetCurrency = settings.TargetCurrency,
|
||||
MainImageUrl = settings.MainImageUrl == null ? null : await _uriResolver.Resolve(Request.GetAbsoluteRootUri(), settings.MainImageUrl),
|
||||
Description = settings.Description,
|
||||
@@ -524,6 +532,8 @@ namespace BTCPayServer.Plugins.Crowdfund.Controllers
|
||||
|
||||
app.Name = vm.AppName;
|
||||
app.Archived = vm.Archived;
|
||||
|
||||
bool wasHtmlModified;
|
||||
var newSettings = new CrowdfundSettings
|
||||
{
|
||||
Title = vm.Title,
|
||||
@@ -531,6 +541,8 @@ namespace BTCPayServer.Plugins.Crowdfund.Controllers
|
||||
EnforceTargetAmount = vm.EnforceTargetAmount,
|
||||
StartDate = vm.StartDate?.ToUniversalTime(),
|
||||
TargetCurrency = vm.TargetCurrency,
|
||||
HtmlMetaTags= _safe.RawMeta(vm.HtmlMetaTags, out wasHtmlModified),
|
||||
Language = vm.Language,
|
||||
Description = vm.Description,
|
||||
EndDate = vm.EndDate?.ToUniversalTime(),
|
||||
TargetAmount = vm.TargetAmount,
|
||||
@@ -574,7 +586,14 @@ namespace BTCPayServer.Plugins.Crowdfund.Controllers
|
||||
StoreId = app.StoreDataId,
|
||||
Settings = newSettings
|
||||
});
|
||||
TempData[WellKnownTempData.SuccessMessage] = StringLocalizer["App updated"].Value;
|
||||
if (wasHtmlModified)
|
||||
{
|
||||
TempData[WellKnownTempData.ErrorMessage] = StringLocalizer["Only meta tags are allowed in HTML headers. Your HTML code has been cleaned up accordingly."].Value;
|
||||
}
|
||||
else
|
||||
{
|
||||
TempData[WellKnownTempData.SuccessMessage] = StringLocalizer["App updated"].Value;
|
||||
}
|
||||
return RedirectToAction(nameof(UpdateCrowdfund), new { appId });
|
||||
}
|
||||
|
||||
|
||||
@@ -194,6 +194,8 @@ namespace BTCPayServer.Plugins.Crowdfund
|
||||
{
|
||||
Title = settings.Title,
|
||||
Tagline = settings.Tagline,
|
||||
Lang = settings.Language,
|
||||
HtmlMetaTags= settings.HtmlMetaTags,
|
||||
Description = settings.Description,
|
||||
StoreName = store.StoreName,
|
||||
StoreId = appData.StoreDataId,
|
||||
|
||||
@@ -28,6 +28,13 @@ namespace BTCPayServer.Plugins.Crowdfund.Models
|
||||
|
||||
public string Tagline { get; set; }
|
||||
|
||||
|
||||
public string Language { get; set; }
|
||||
|
||||
[Display(Name = "HTML Meta Tags")]
|
||||
public string HtmlMetaTags{ get; set; }
|
||||
|
||||
|
||||
[Required]
|
||||
public string Description { get; set; }
|
||||
|
||||
|
||||
@@ -14,6 +14,8 @@ namespace BTCPayServer.Plugins.Crowdfund.Models
|
||||
public string AppId { get; set; }
|
||||
public string Title { get; set; }
|
||||
public string Description { get; set; }
|
||||
public string Lang { get; set; }
|
||||
public string HtmlMetaTags{ get; set; }
|
||||
public string MainImageUrl { get; set; }
|
||||
public string StoreName { get; set; }
|
||||
public DateTime? StartDate { get; set; }
|
||||
|
||||
@@ -2,6 +2,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Text;
|
||||
using System.Text.Encodings.Web;
|
||||
using System.Text.RegularExpressions;
|
||||
@@ -11,6 +12,7 @@ using BTCPayServer.Abstractions.Constants;
|
||||
using BTCPayServer.Abstractions.Extensions;
|
||||
using BTCPayServer.Abstractions.Form;
|
||||
using BTCPayServer.Abstractions.Models;
|
||||
using BTCPayServer.Abstractions.Services;
|
||||
using BTCPayServer.Client;
|
||||
using BTCPayServer.Client.Models;
|
||||
using BTCPayServer.Controllers;
|
||||
@@ -26,6 +28,7 @@ using BTCPayServer.Services.Apps;
|
||||
using BTCPayServer.Services.Invoices;
|
||||
using BTCPayServer.Services.Rates;
|
||||
using BTCPayServer.Services.Stores;
|
||||
using Ganss.Xss;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Cors;
|
||||
using Microsoft.AspNetCore.Http.Extensions;
|
||||
@@ -55,7 +58,8 @@ namespace BTCPayServer.Plugins.PointOfSale.Controllers
|
||||
IStringLocalizer stringLocalizer,
|
||||
DisplayFormatter displayFormatter,
|
||||
IRateLimitService rateLimitService,
|
||||
IAuthorizationService authorizationService)
|
||||
IAuthorizationService authorizationService,
|
||||
Safe safe)
|
||||
{
|
||||
_currencies = currencies;
|
||||
_appService = appService;
|
||||
@@ -66,6 +70,7 @@ namespace BTCPayServer.Plugins.PointOfSale.Controllers
|
||||
_displayFormatter = displayFormatter;
|
||||
_rateLimitService = rateLimitService;
|
||||
_authorizationService = authorizationService;
|
||||
_safe = safe;
|
||||
StringLocalizer = stringLocalizer;
|
||||
FormDataService = formDataService;
|
||||
}
|
||||
@@ -79,6 +84,7 @@ namespace BTCPayServer.Plugins.PointOfSale.Controllers
|
||||
private readonly DisplayFormatter _displayFormatter;
|
||||
private readonly IRateLimitService _rateLimitService;
|
||||
private readonly IAuthorizationService _authorizationService;
|
||||
private readonly Safe _safe;
|
||||
public FormDataService FormDataService { get; }
|
||||
public IStringLocalizer StringLocalizer { get; }
|
||||
|
||||
@@ -132,6 +138,8 @@ namespace BTCPayServer.Plugins.PointOfSale.Controllers
|
||||
CustomTipPercentages = settings.CustomTipPercentages,
|
||||
AppId = appId,
|
||||
StoreId = store.Id,
|
||||
Lang = settings.Language,
|
||||
HtmlMetaTags= settings.HtmlMetaTags,
|
||||
Description = settings.Description,
|
||||
});
|
||||
}
|
||||
@@ -611,6 +619,8 @@ namespace BTCPayServer.Plugins.PointOfSale.Controllers
|
||||
CustomButtonText = settings.CustomButtonText ?? PointOfSaleSettings.CUSTOM_BUTTON_TEXT_DEF,
|
||||
CustomTipText = settings.CustomTipText ?? PointOfSaleSettings.CUSTOM_TIP_TEXT_DEF,
|
||||
CustomTipPercentages = settings.CustomTipPercentages != null ? string.Join(",", settings.CustomTipPercentages) : string.Join(",", PointOfSaleSettings.CUSTOM_TIP_PERCENTAGES_DEF),
|
||||
Language = settings.Language,
|
||||
HtmlMetaTags= settings.HtmlMetaTags,
|
||||
Description = settings.Description,
|
||||
NotificationUrl = settings.NotificationUrl,
|
||||
RedirectUrl = settings.RedirectUrl,
|
||||
@@ -687,6 +697,7 @@ namespace BTCPayServer.Plugins.PointOfSale.Controllers
|
||||
return View("PointOfSale/UpdatePointOfSale", vm);
|
||||
}
|
||||
|
||||
bool wasHtmlModified;
|
||||
var settings = new PointOfSaleSettings
|
||||
{
|
||||
Title = vm.Title,
|
||||
@@ -705,6 +716,8 @@ namespace BTCPayServer.Plugins.PointOfSale.Controllers
|
||||
CustomTipPercentages = ListSplit(vm.CustomTipPercentages),
|
||||
NotificationUrl = vm.NotificationUrl,
|
||||
RedirectUrl = vm.RedirectUrl,
|
||||
Language = vm.Language,
|
||||
HtmlMetaTags = _safe.RawMeta(vm.HtmlMetaTags, out wasHtmlModified),
|
||||
Description = vm.Description,
|
||||
RedirectAutomatically = string.IsNullOrEmpty(vm.RedirectAutomatically) ? null : bool.Parse(vm.RedirectAutomatically),
|
||||
FormId = vm.FormId
|
||||
@@ -714,7 +727,12 @@ namespace BTCPayServer.Plugins.PointOfSale.Controllers
|
||||
app.Archived = vm.Archived;
|
||||
app.SetSettings(settings);
|
||||
await _appService.UpdateOrCreateApp(app);
|
||||
TempData[WellKnownTempData.SuccessMessage] = StringLocalizer["App updated"].Value;
|
||||
if (wasHtmlModified)
|
||||
{
|
||||
TempData[WellKnownTempData.ErrorMessage] = StringLocalizer["Only meta tags are allowed in HTML headers. Your HTML code has been cleaned up accordingly."].Value;
|
||||
} else {
|
||||
TempData[WellKnownTempData.SuccessMessage] = StringLocalizer["App updated"].Value;
|
||||
}
|
||||
return RedirectToAction(nameof(UpdatePointOfSale), new { appId });
|
||||
}
|
||||
|
||||
|
||||
@@ -86,6 +86,11 @@ namespace BTCPayServer.Plugins.PointOfSale.Models
|
||||
new() { Text = "Use Store Settings", Value = "" }
|
||||
}, nameof(SelectListItem.Value), nameof(SelectListItem.Text), RedirectAutomatically);
|
||||
|
||||
public string Language { get; set; }
|
||||
|
||||
[Display(Name = "HTML Meta Tags")]
|
||||
public string HtmlMetaTags{ get; set; }
|
||||
|
||||
public string Description { get; set; }
|
||||
|
||||
[Display(Name = "Request customer data on checkout")]
|
||||
|
||||
@@ -68,6 +68,8 @@ namespace BTCPayServer.Plugins.PointOfSale.Models
|
||||
public string CustomButtonText { get; set; }
|
||||
public string CustomTipText { get; set; }
|
||||
public int[] CustomTipPercentages { get; set; }
|
||||
public string Lang { get; set; }
|
||||
public string HtmlMetaTags{ get; set; }
|
||||
public string Description { get; set; }
|
||||
public SelectList AllCategories { get; set; }
|
||||
public string StoreId { get; set; }
|
||||
|
||||
@@ -1,13 +1,22 @@
|
||||
using System;
|
||||
using BTCPayServer.JsonConverters;
|
||||
using Newtonsoft.Json;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
|
||||
namespace BTCPayServer.Services.Apps
|
||||
{
|
||||
public class CrowdfundSettings
|
||||
{
|
||||
public CrowdfundSettings()
|
||||
{
|
||||
Language = "en";
|
||||
}
|
||||
|
||||
public string Title { get; set; }
|
||||
public string Description { get; set; }
|
||||
public string Language { get; set; }
|
||||
public string HtmlMetaTags{ get; set; }
|
||||
public bool Enabled { get; set; } = true;
|
||||
public DateTime? StartDate { get; set; }
|
||||
public DateTime? EndDate { get; set; }
|
||||
|
||||
@@ -8,6 +8,7 @@ namespace BTCPayServer.Services.Apps
|
||||
public PointOfSaleSettings()
|
||||
{
|
||||
Title = "Tea shop";
|
||||
Language = "en";
|
||||
Template = AppService.SerializeTemplate([
|
||||
new AppItem
|
||||
{
|
||||
@@ -99,6 +100,8 @@ namespace BTCPayServer.Services.Apps
|
||||
public string CustomTipText { get; set; } = CUSTOM_TIP_TEXT_DEF;
|
||||
public static readonly int[] CUSTOM_TIP_PERCENTAGES_DEF = { 15, 18, 20 };
|
||||
public int[] CustomTipPercentages { get; set; } = CUSTOM_TIP_PERCENTAGES_DEF;
|
||||
public string Language { get; set; }
|
||||
public string HtmlMetaTags{ get; set; }
|
||||
public string Description { get; set; }
|
||||
public string NotificationUrl { get; set; }
|
||||
public string RedirectUrl { get; set; }
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
}
|
||||
}
|
||||
<!DOCTYPE html>
|
||||
<html class="h-100" @(Env.IsDeveloping ? " data-devenv" : "") id="Crowdfund-@Model.AppId">
|
||||
<html lang="@Model.Lang" class="h-100" @(Env.IsDeveloping ? " data-devenv" : "") id="Crowdfund-@Model.AppId">
|
||||
<head>
|
||||
<partial name="LayoutHead" />
|
||||
<link href="~/vendor/bootstrap-vue/bootstrap-vue.min.css" asp-append-version="true" rel="stylesheet" />
|
||||
@@ -35,6 +35,8 @@
|
||||
object-fit: scale-down;
|
||||
}
|
||||
</style>
|
||||
@* Html.Raw OK here since Html has been cleaned before in controller *@
|
||||
@Html.Raw(Model.HtmlMetaTags)
|
||||
<vc:ui-extension-point location="crowdfund-head" model="@Model"/>
|
||||
</head>
|
||||
<body class="min-vh-100 p-2">
|
||||
|
||||
@@ -240,6 +240,36 @@
|
||||
<h3 class="mt-5 mb-2" text-translate="true">Additional Options</h3>
|
||||
<div class="form-group">
|
||||
<div class="accordion" id="additional">
|
||||
|
||||
<div class="accordion-item">
|
||||
<h2 class="accordion-header" id="additional-htmlheader-header">
|
||||
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#additional-htmlheader" aria-expanded="false" aria-controls="additional-htmlheader">
|
||||
<span text-translate="true">HTML Headers</span>
|
||||
<vc:icon symbol="caret-down" />
|
||||
</button>
|
||||
</h2>
|
||||
<div id="additional-htmlheader" class="accordion-collapse collapse" aria-labelledby="additional-htmlheader-header">
|
||||
<div class="accordion-body">
|
||||
<div class="form-group">
|
||||
<label asp-for="Language" class="form-label"></label>
|
||||
<input asp-for="Language" class="form-control" maxlength="2" required />
|
||||
<div class="form-text">Fix the HTML page language</div>
|
||||
<span asp-validation-for="Language" class="text-danger"></span>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label asp-for="HtmlMetaTags" class="form-label"></label>
|
||||
<textarea asp-for="HtmlMetaTags" rows="5" cols="40" class="form-control"
|
||||
placeholder='<meta name="description" content="Your description">
|
||||
<meta name="keywords" content="keyword1, keyword2, keyword3">
|
||||
<meta name="author" content="John Doe">
|
||||
Please insert valid HTML here. Only meta tags accepted.'>
|
||||
</textarea>
|
||||
<span asp-validation-for="HtmlMetaTags" class="text-danger"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="accordion-item">
|
||||
<h2 class="accordion-header" id="additional-sound-header">
|
||||
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#additional-sound" aria-expanded="false" aria-controls="additional-sound">
|
||||
@@ -295,7 +325,7 @@
|
||||
<div class="accordion-item">
|
||||
<h2 class="accordion-header" id="additional-discussion-header">
|
||||
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#additional-discussion" aria-expanded="false" aria-controls="additional-discussion">
|
||||
Discussion
|
||||
<span text-translate="true">Discussion</span>
|
||||
<vc:icon symbol="caret-down" />
|
||||
</button>
|
||||
</h2>
|
||||
@@ -321,7 +351,7 @@
|
||||
<div class="accordion-item">
|
||||
<h2 class="accordion-header" id="additional-notification-header">
|
||||
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#additional-notification" aria-expanded="false" aria-controls="additional-notification">
|
||||
Notification URL Callbacks
|
||||
<span text-translate="true">Notification URL Callbacks</span>
|
||||
<vc:icon symbol="caret-down" />
|
||||
</button>
|
||||
</h2>
|
||||
|
||||
@@ -33,13 +33,15 @@
|
||||
}
|
||||
}
|
||||
<!DOCTYPE html>
|
||||
<html class="h-100" lang="en" @(Env.IsDeveloping ? " data-devenv" : "") id="POS-@Model.AppId">
|
||||
<html class="h-100" lang="@Model.Lang" @(Env.IsDeveloping ? " data-devenv" : "") id="POS-@Model.AppId">
|
||||
<head>
|
||||
<partial name="LayoutHead" />
|
||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||
<link rel="apple-touch-startup-image" href="~/img/splash.png">
|
||||
<link rel="manifest" href="@(await GetDynamicManifest(ViewData["Title"]!.ToString()))">
|
||||
<link href="~/pos/common.css" asp-append-version="true" rel="stylesheet" />
|
||||
@* Html.Raw OK here since Html has been cleaned before in controller *@
|
||||
@Html.Raw(Model.HtmlMetaTags)
|
||||
@await RenderSectionAsync("PageHeadContent", false)
|
||||
</head>
|
||||
<body class="min-vh-100">
|
||||
|
||||
@@ -93,6 +93,7 @@
|
||||
<span asp-validation-for="Currency" class="text-danger"></span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="description" class="row mt-4">
|
||||
<div class="col-xxl-constrain">
|
||||
<div class="form-group mb-0">
|
||||
@@ -196,6 +197,36 @@
|
||||
<h3 class="mb-2">Additional Options</h3>
|
||||
<div class="form-group">
|
||||
<div class="accordion" id="additional">
|
||||
|
||||
<div class="accordion-item">
|
||||
<h2 class="accordion-header" id="additional-htmlheader-header">
|
||||
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#additional-htmlheader" aria-expanded="false" aria-controls="additional-htmlheader">
|
||||
<span text-translate="true">HTML Headers</span>
|
||||
<vc:icon symbol="caret-down" />
|
||||
</button>
|
||||
</h2>
|
||||
<div id="additional-htmlheader" class="accordion-collapse collapse" aria-labelledby="additional-htmlheader-header">
|
||||
<div class="accordion-body">
|
||||
<div class="form-group">
|
||||
<label asp-for="Language" class="form-label"></label>
|
||||
<input asp-for="Language" class="form-control" maxlength="2" required />
|
||||
<div class="form-text">Fix the HTML page language</div>
|
||||
<span asp-validation-for="Language" class="text-danger"></span>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label asp-for="HtmlMetaTags" class="form-label"></label>
|
||||
<textarea asp-for="HtmlMetaTags" rows="5" cols="40" class="form-control"
|
||||
placeholder='<meta name="description" content="Your description">
|
||||
<meta name="keywords" content="keyword1, keyword2, keyword3">
|
||||
<meta name="author" content="John Doe">
|
||||
Please insert valid HTML here. Only meta tags accepted.'>
|
||||
</textarea>
|
||||
<span asp-validation-for="HtmlMetaTags" class="text-danger"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="accordion-item">
|
||||
<h2 class="accordion-header" id="additional-embed-payment-button-header">
|
||||
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#additional-embed-payment-button" aria-expanded="false" aria-controls="additional-embed-payment-button">
|
||||
|
||||
Reference in New Issue
Block a user