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:
Andrew Camilleri 2021-03-19 15:25:04 +01:00 committed by GitHub
parent 923a567822
commit 7035b71ccd
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 48 additions and 13 deletions

View file

@ -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
{

View file

@ -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
{

View file

@ -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

View file

@ -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';

View file

@ -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">

View file

@ -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>
}