mirror of
https://github.com/btcpayserver/btcpayserver.git
synced 2025-02-21 22:11:48 +01:00
Fix POS item newline break (#2366)
* Fix POS item newline break fixes #2365 * Update TemplateEditor.cshtml * fix template editor with " * apply sanitize on save
This commit is contained in:
parent
923a567822
commit
7035b71ccd
6 changed files with 48 additions and 13 deletions
|
@ -71,7 +71,7 @@ namespace BTCPayServer.Controllers
|
|||
|
||||
try
|
||||
{
|
||||
_AppService.Parse(vm.PerksTemplate, vm.TargetCurrency).ToString();
|
||||
vm.PerksTemplate = _AppService.SerializeTemplate(_AppService.Parse(vm.PerksTemplate, vm.TargetCurrency));
|
||||
}
|
||||
catch
|
||||
{
|
||||
|
|
|
@ -165,7 +165,7 @@ namespace BTCPayServer.Controllers
|
|||
ModelState.AddModelError(nameof(vm.Currency), "Invalid currency");
|
||||
try
|
||||
{
|
||||
_AppService.Parse(vm.Template, vm.Currency);
|
||||
vm.Template = _AppService.SerializeTemplate(_AppService.Parse(vm.Template, vm.Currency));
|
||||
}
|
||||
catch
|
||||
{
|
||||
|
|
|
@ -18,6 +18,7 @@ using NBitcoin;
|
|||
using NBitcoin.DataEncoders;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using NUglify.Helpers;
|
||||
using YamlDotNet.Core;
|
||||
using YamlDotNet.RepresentationModel;
|
||||
using YamlDotNet.Serialization;
|
||||
using static BTCPayServer.Models.AppViewModels.ViewCrowdfundViewModel;
|
||||
|
@ -279,7 +280,10 @@ namespace BTCPayServer.Services.Apps
|
|||
itemNode.Add("price", new YamlScalarNode(item.Price.Value.ToStringInvariant()));
|
||||
if (!string.IsNullOrEmpty(item.Description))
|
||||
{
|
||||
itemNode.Add("description", new YamlScalarNode(item.Description));
|
||||
itemNode.Add("description", new YamlScalarNode(item.Description)
|
||||
{
|
||||
Style = ScalarStyle.DoubleQuoted
|
||||
});
|
||||
}
|
||||
if (!string.IsNullOrEmpty(item.Image))
|
||||
{
|
||||
|
@ -290,6 +294,16 @@ namespace BTCPayServer.Services.Apps
|
|||
{
|
||||
itemNode.Add("inventory", new YamlScalarNode(item.Inventory.ToString()));
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(item.BuyButtonText))
|
||||
{
|
||||
itemNode.Add("buyButtonText", new YamlScalarNode(item.BuyButtonText));
|
||||
}
|
||||
|
||||
if (item.PaymentMethods?.Any() is true)
|
||||
{
|
||||
itemNode.Add("payment_methods", new YamlSequenceNode(item.PaymentMethods.Select(s=> new YamlScalarNode(s))));
|
||||
}
|
||||
mappingNode.Add(item.Id, itemNode);
|
||||
}
|
||||
|
||||
|
@ -306,7 +320,7 @@ namespace BTCPayServer.Services.Apps
|
|||
var root = (YamlMappingNode)stream.Documents[0].RootNode;
|
||||
return root
|
||||
.Children
|
||||
.Select(kv => new PosHolder { Key = (kv.Key as YamlScalarNode)?.Value, Value = kv.Value as YamlMappingNode })
|
||||
.Select(kv => new PosHolder(_HtmlSanitizer) { Key = _HtmlSanitizer.Sanitize((kv.Key as YamlScalarNode)?.Value), Value = kv.Value as YamlMappingNode })
|
||||
.Where(kv => kv.Value != null)
|
||||
.Select(c => new ViewPointOfSaleViewModel.Item()
|
||||
{
|
||||
|
@ -385,6 +399,13 @@ namespace BTCPayServer.Services.Apps
|
|||
|
||||
private class PosHolder
|
||||
{
|
||||
private readonly HtmlSanitizer _htmlSanitizer;
|
||||
|
||||
public PosHolder(HtmlSanitizer htmlSanitizer)
|
||||
{
|
||||
_htmlSanitizer = htmlSanitizer;
|
||||
}
|
||||
|
||||
public string Key { get; set; }
|
||||
public YamlMappingNode Value { get; set; }
|
||||
|
||||
|
@ -399,7 +420,8 @@ namespace BTCPayServer.Services.Apps
|
|||
|
||||
public string GetDetailString(string field)
|
||||
{
|
||||
return GetDetail(field).FirstOrDefault()?.Value?.Value;
|
||||
var raw = GetDetail(field).FirstOrDefault()?.Value?.Value;
|
||||
return raw is null ? null : _htmlSanitizer.Sanitize(raw);
|
||||
}
|
||||
public string[] GetDetailStringList(string field)
|
||||
{
|
||||
|
@ -407,7 +429,7 @@ namespace BTCPayServer.Services.Apps
|
|||
{
|
||||
return null;
|
||||
}
|
||||
return sequenceNode.Children.Select(node => (node as YamlScalarNode)?.Value).Where(s => s != null).ToArray();
|
||||
return sequenceNode.Children.Select(node => (node as YamlScalarNode)?.Value).Where(s => s != null).Select(s=> _htmlSanitizer.Sanitize(s)).ToArray();
|
||||
}
|
||||
}
|
||||
private class PosScalar
|
||||
|
|
|
@ -211,6 +211,13 @@ $(function() {
|
|||
}
|
||||
if (productProperty.indexOf('description:') !== -1) {
|
||||
description =productProperty.replace('description:', '').trim();
|
||||
if (description.startsWith('"') && description.endsWith('"')){
|
||||
description = description.substr(1, description.length-2);
|
||||
}
|
||||
description = description
|
||||
.replaceAll("<br>", "\n")
|
||||
.replaceAll("<br/>", "\n")
|
||||
.replaceAll('\\"', '"')
|
||||
}
|
||||
if (productProperty.indexOf('image:') !== -1) {
|
||||
image = productProperty.replace('image:', '').trim();
|
||||
|
@ -236,7 +243,7 @@ $(function() {
|
|||
title: title,
|
||||
price: price,
|
||||
image: image || null,
|
||||
description: description || '',
|
||||
description: description || '',
|
||||
custom: custom === "true",
|
||||
buyButtonText: buyButtonText,
|
||||
inventory: isNaN(inventory)? null: inventory,
|
||||
|
@ -266,7 +273,7 @@ $(function() {
|
|||
' title: ' + title + '\n';
|
||||
|
||||
if (description) {
|
||||
template += ' description: ' + description + '\n';
|
||||
template += ' description: "' + description.replaceAll("\n", "<br/>").replaceAll('"', '\\"') + '"\n';
|
||||
}
|
||||
if (image) {
|
||||
template += ' image: ' + image + '\n';
|
||||
|
|
|
@ -248,7 +248,7 @@
|
|||
<h6 class="card-title mb-0">@item.Title</h6>
|
||||
@if (!String.IsNullOrWhiteSpace(description))
|
||||
{
|
||||
<p class="card-text">@description</p>
|
||||
<p class="card-text">@Safe.Raw(description))</p>
|
||||
}
|
||||
</div>
|
||||
<div class="card-footer pt-0 bg-transparent border-0">
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
}
|
||||
|
||||
<div class="container d-flex h-100">
|
||||
<div class="justify-content-center align-self-center text-center mx-auto px-2 py-3 w-100" style="margin: auto;">
|
||||
<div class="justify-content-center align-self-center text-center mx-auto px-2 py-3 w-100 m-auto">
|
||||
@if (TempData.HasStatusMessage())
|
||||
{
|
||||
<partial name="_StatusMessage" />
|
||||
|
@ -21,7 +21,13 @@
|
|||
@for (int x = 0; x < Model.Items.Length; x++)
|
||||
{
|
||||
var item = Model.Items[x];
|
||||
|
||||
var buttonText = (string.IsNullOrEmpty(item.BuyButtonText) ?
|
||||
item.Custom?
|
||||
Model.CustomButtonText :
|
||||
Model.ButtonText
|
||||
: item.BuyButtonText)
|
||||
.Replace("{0}",item.Price.Formatted)
|
||||
.Replace("{Price}",item.Price.Formatted);
|
||||
<div class="card my-2" data-id="@x">
|
||||
@if (!String.IsNullOrWhiteSpace(item.Image))
|
||||
{
|
||||
|
@ -31,7 +37,7 @@
|
|||
<h5 class="card-title">@item.Title</h5>
|
||||
@if (!String.IsNullOrWhiteSpace(item.Description))
|
||||
{
|
||||
<p class="card-text">@System.Net.WebUtility.HtmlDecode(item.Description)</p>
|
||||
<p class="card-text">@Safe.Raw(item.Description)</p>
|
||||
}
|
||||
</div>
|
||||
<div class="card-footer bg-transparent border-0">
|
||||
|
@ -60,7 +66,7 @@
|
|||
{
|
||||
<form method="post" asp-controller="AppsPublic" asp-action="ViewPointOfSale" asp-route-appId="@Model.AppId" asp-antiforgery="false">
|
||||
<button type="submit" name="choiceKey" class="js-add-cart btn btn-primary" value="@item.Id">
|
||||
@((item.BuyButtonText ?? Model.ButtonText).Replace("{0}",item.Price.Formatted).Replace("{Price}",item.Price.Formatted))
|
||||
@buttonText
|
||||
</button>
|
||||
</form>
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue