2024-04-04 10:47:28 +02:00
#nullable enable
using System ;
using System.Collections.Generic ;
using System.Linq ;
using System.Threading.Tasks ;
using BTCPayServer.Abstractions.Constants ;
2024-05-09 02:18:02 +02:00
using BTCPayServer.Abstractions.Extensions ;
2024-04-04 10:47:28 +02:00
using BTCPayServer.Abstractions.Models ;
using BTCPayServer.Client ;
using BTCPayServer.Data ;
using BTCPayServer.Models.StoreViewModels ;
using BTCPayServer.Payments ;
using BTCPayServer.Payments.Lightning ;
using Microsoft.AspNetCore.Authorization ;
using Microsoft.AspNetCore.Mvc ;
using Microsoft.AspNetCore.Mvc.Rendering ;
2024-04-04 11:00:18 +02:00
namespace BTCPayServer.Controllers ;
public partial class UIStoresController
2024-04-04 10:47:28 +02:00
{
2024-04-04 11:00:18 +02:00
[HttpGet("{storeId}/settings")]
2024-09-30 12:13:51 +02:00
public async Task < IActionResult > GeneralSettings ( string storeId )
2024-04-04 10:47:28 +02:00
{
2024-04-04 11:00:18 +02:00
var store = HttpContext . GetStoreData ( ) ;
2024-09-30 12:13:51 +02:00
if ( store = = null ) return NotFound ( ) ;
2024-04-04 11:00:18 +02:00
var storeBlob = store . GetStoreBlob ( ) ;
var vm = new GeneralSettingsViewModel
2024-04-04 10:47:28 +02:00
{
2024-04-04 11:00:18 +02:00
Id = store . Id ,
StoreName = store . StoreName ,
StoreWebsite = store . StoreWebsite ,
2024-05-09 02:18:02 +02:00
LogoUrl = await _uriResolver . Resolve ( Request . GetAbsoluteRootUri ( ) , storeBlob . LogoUrl ) ,
CssUrl = await _uriResolver . Resolve ( Request . GetAbsoluteRootUri ( ) , storeBlob . CssUrl ) ,
2024-04-04 11:00:18 +02:00
BrandColor = storeBlob . BrandColor ,
2024-09-13 14:39:21 +02:00
ApplyBrandColorToBackend = storeBlob . ApplyBrandColorToBackend ,
2024-04-04 11:00:18 +02:00
NetworkFeeMode = storeBlob . NetworkFeeMode ,
AnyoneCanCreateInvoice = storeBlob . AnyoneCanInvoice ,
PaymentTolerance = storeBlob . PaymentTolerance ,
InvoiceExpiration = ( int ) storeBlob . InvoiceExpiration . TotalMinutes ,
DefaultCurrency = storeBlob . DefaultCurrency ,
BOLT11Expiration = ( long ) storeBlob . RefundBOLT11Expiration . TotalDays ,
2024-09-30 12:13:51 +02:00
Archived = store . Archived ,
MonitoringExpiration = ( int ) storeBlob . MonitoringExpiration . TotalMinutes ,
SpeedPolicy = store . SpeedPolicy ,
ShowRecommendedFee = storeBlob . ShowRecommendedFee ,
RecommendedFeeBlockTarget = storeBlob . RecommendedFeeBlockTarget
2024-04-04 11:00:18 +02:00
} ;
2024-04-04 10:47:28 +02:00
2024-04-04 11:00:18 +02:00
return View ( vm ) ;
}
2024-04-04 10:47:28 +02:00
2024-04-04 11:00:18 +02:00
[HttpPost("{storeId}/settings")]
[Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Cookie)]
public async Task < IActionResult > GeneralSettings (
GeneralSettingsViewModel model ,
[FromForm] bool RemoveLogoFile = false ,
[FromForm] bool RemoveCssFile = false )
{
bool needUpdate = false ;
if ( CurrentStore . StoreName ! = model . StoreName )
{
needUpdate = true ;
CurrentStore . StoreName = model . StoreName ;
2024-04-04 10:47:28 +02:00
}
2024-04-04 11:00:18 +02:00
if ( CurrentStore . StoreWebsite ! = model . StoreWebsite )
2024-04-04 10:47:28 +02:00
{
2024-04-04 11:00:18 +02:00
needUpdate = true ;
CurrentStore . StoreWebsite = model . StoreWebsite ;
}
2024-04-04 10:47:28 +02:00
2024-09-30 12:13:51 +02:00
if ( CurrentStore . SpeedPolicy ! = model . SpeedPolicy )
{
CurrentStore . SpeedPolicy = model . SpeedPolicy ;
needUpdate = true ;
}
2024-04-04 11:00:18 +02:00
var blob = CurrentStore . GetStoreBlob ( ) ;
blob . AnyoneCanInvoice = model . AnyoneCanCreateInvoice ;
blob . NetworkFeeMode = model . NetworkFeeMode ;
blob . PaymentTolerance = model . PaymentTolerance ;
blob . DefaultCurrency = model . DefaultCurrency ;
2024-09-30 12:13:51 +02:00
blob . ShowRecommendedFee = model . ShowRecommendedFee ;
blob . RecommendedFeeBlockTarget = model . RecommendedFeeBlockTarget ;
2024-04-04 11:00:18 +02:00
blob . InvoiceExpiration = TimeSpan . FromMinutes ( model . InvoiceExpiration ) ;
blob . RefundBOLT11Expiration = TimeSpan . FromDays ( model . BOLT11Expiration ) ;
2024-09-30 12:13:51 +02:00
blob . MonitoringExpiration = TimeSpan . FromMinutes ( model . MonitoringExpiration ) ;
2024-04-04 11:00:18 +02:00
if ( ! string . IsNullOrEmpty ( model . BrandColor ) & & ! ColorPalette . IsValid ( model . BrandColor ) )
{
2024-09-13 14:39:21 +02:00
ModelState . AddModelError ( nameof ( model . BrandColor ) , "The brand color needs to be a valid hex color code" ) ;
2024-04-04 11:00:18 +02:00
return View ( model ) ;
}
blob . BrandColor = model . BrandColor ;
2024-09-13 14:39:21 +02:00
blob . ApplyBrandColorToBackend = model . ApplyBrandColorToBackend & & ! string . IsNullOrEmpty ( model . BrandColor ) ;
2024-04-04 10:47:28 +02:00
2024-04-04 11:00:18 +02:00
var userId = GetUserId ( ) ;
if ( userId is null )
return NotFound ( ) ;
2024-04-04 10:47:28 +02:00
2024-04-04 11:00:18 +02:00
if ( model . LogoFile ! = null )
{
if ( model . LogoFile . Length > 1_000_000 )
2024-04-04 10:47:28 +02:00
{
2024-04-04 11:00:18 +02:00
ModelState . AddModelError ( nameof ( model . LogoFile ) , "The uploaded logo file should be less than 1MB" ) ;
2024-04-04 10:47:28 +02:00
}
2024-04-04 11:00:18 +02:00
else if ( ! model . LogoFile . ContentType . StartsWith ( "image/" , StringComparison . InvariantCulture ) )
2024-04-04 10:47:28 +02:00
{
2024-04-04 11:00:18 +02:00
ModelState . AddModelError ( nameof ( model . LogoFile ) , "The uploaded logo file needs to be an image" ) ;
2024-04-04 10:47:28 +02:00
}
2024-04-04 11:00:18 +02:00
else
2024-04-04 10:47:28 +02:00
{
2024-04-04 11:00:18 +02:00
var formFile = await model . LogoFile . Bufferize ( ) ;
if ( ! FileTypeDetector . IsPicture ( formFile . Buffer , formFile . FileName ) )
2024-04-04 10:47:28 +02:00
{
2024-04-04 11:00:18 +02:00
ModelState . AddModelError ( nameof ( model . LogoFile ) , "The uploaded logo file needs to be an image" ) ;
2024-04-04 10:47:28 +02:00
}
else
{
2024-04-04 11:00:18 +02:00
model . LogoFile = formFile ;
// add new image
2024-04-04 10:47:28 +02:00
try
{
2024-04-04 11:00:18 +02:00
var storedFile = await _fileService . AddFile ( model . LogoFile , userId ) ;
2024-05-09 02:18:02 +02:00
blob . LogoUrl = new UnresolvedUri . FileIdUri ( storedFile . Id ) ;
2024-04-04 10:47:28 +02:00
}
catch ( Exception e )
{
2024-04-04 11:00:18 +02:00
ModelState . AddModelError ( nameof ( model . LogoFile ) , $"Could not save logo: {e.Message}" ) ;
2024-04-04 10:47:28 +02:00
}
}
}
2024-04-04 11:00:18 +02:00
}
2024-05-09 02:18:02 +02:00
else if ( RemoveLogoFile & & blob . LogoUrl is not null )
2024-04-04 11:00:18 +02:00
{
2024-05-09 02:18:02 +02:00
blob . LogoUrl = null ;
2024-04-04 11:00:18 +02:00
needUpdate = true ;
}
if ( model . CssFile ! = null )
{
if ( model . CssFile . Length > 1_000_000 )
2024-04-04 10:47:28 +02:00
{
2024-04-04 11:00:18 +02:00
ModelState . AddModelError ( nameof ( model . CssFile ) , "The uploaded file should be less than 1MB" ) ;
2024-04-04 10:47:28 +02:00
}
2024-04-04 11:00:18 +02:00
else if ( ! model . CssFile . ContentType . Equals ( "text/css" , StringComparison . InvariantCulture ) )
2024-04-04 10:47:28 +02:00
{
2024-04-04 11:00:18 +02:00
ModelState . AddModelError ( nameof ( model . CssFile ) , "The uploaded file needs to be a CSS file" ) ;
2024-04-04 10:47:28 +02:00
}
2024-04-04 11:00:18 +02:00
else if ( ! model . CssFile . FileName . EndsWith ( ".css" , StringComparison . OrdinalIgnoreCase ) )
2024-04-04 10:47:28 +02:00
{
2024-04-04 11:00:18 +02:00
ModelState . AddModelError ( nameof ( model . CssFile ) , "The uploaded file needs to be a CSS file" ) ;
2024-04-04 10:47:28 +02:00
}
2024-04-04 11:00:18 +02:00
else
2024-04-04 10:47:28 +02:00
{
2024-04-04 11:00:18 +02:00
// add new file
try
{
var storedFile = await _fileService . AddFile ( model . CssFile , userId ) ;
2024-05-09 02:18:02 +02:00
blob . CssUrl = new UnresolvedUri . FileIdUri ( storedFile . Id ) ;
2024-04-04 11:00:18 +02:00
}
catch ( Exception e )
{
ModelState . AddModelError ( nameof ( model . CssFile ) , $"Could not save CSS file: {e.Message}" ) ;
}
}
2024-04-04 10:47:28 +02:00
}
2024-05-09 02:18:02 +02:00
else if ( RemoveCssFile & & blob . CssUrl is not null )
2024-04-04 10:47:28 +02:00
{
2024-05-09 02:18:02 +02:00
blob . CssUrl = null ;
2024-04-04 11:00:18 +02:00
needUpdate = true ;
2024-04-04 10:47:28 +02:00
}
2024-04-04 11:00:18 +02:00
if ( CurrentStore . SetStoreBlob ( blob ) )
2024-04-04 10:47:28 +02:00
{
2024-04-04 11:00:18 +02:00
needUpdate = true ;
2024-04-04 10:47:28 +02:00
}
2024-04-04 11:00:18 +02:00
if ( needUpdate )
2024-04-04 10:47:28 +02:00
{
2024-04-04 11:00:18 +02:00
await _storeRepo . UpdateStore ( CurrentStore ) ;
TempData [ WellKnownTempData . SuccessMessage ] = "Store successfully updated" ;
2024-04-04 10:47:28 +02:00
}
2024-04-04 11:00:18 +02:00
return RedirectToAction ( nameof ( GeneralSettings ) , new
{
storeId = CurrentStore . Id
} ) ;
}
2024-04-04 10:47:28 +02:00
2024-04-04 11:00:18 +02:00
[HttpPost("{storeId}/archive")]
[Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Cookie)]
public async Task < IActionResult > ToggleArchive ( string storeId )
{
CurrentStore . Archived = ! CurrentStore . Archived ;
await _storeRepo . UpdateStore ( CurrentStore ) ;
TempData [ WellKnownTempData . SuccessMessage ] = CurrentStore . Archived
? "The store has been archived and will no longer appear in the stores list by default."
: "The store has been unarchived and will appear in the stores list by default again." ;
return RedirectToAction ( nameof ( GeneralSettings ) , new
2024-04-04 10:47:28 +02:00
{
2024-04-04 11:00:18 +02:00
storeId = CurrentStore . Id
} ) ;
}
[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 _storeRepo . DeleteStore ( CurrentStore . Id ) ;
TempData [ WellKnownTempData . SuccessMessage ] = "Store successfully deleted." ;
return RedirectToAction ( nameof ( UIHomeController . Index ) , "UIHome" ) ;
}
[HttpGet("{storeId}/checkout")]
2024-05-09 02:18:02 +02:00
public async Task < IActionResult > CheckoutAppearance ( )
2024-04-04 11:00:18 +02:00
{
var storeBlob = CurrentStore . GetStoreBlob ( ) ;
var vm = new CheckoutAppearanceViewModel ( ) ;
SetCryptoCurrencies ( vm , CurrentStore ) ;
vm . PaymentMethodCriteria = CurrentStore . GetPaymentMethodConfigs ( _handlers )
. Where ( s = > ! storeBlob . GetExcludedPaymentMethods ( ) . Match ( s . Key ) & & s . Value is not LNURLPaymentMethodConfig )
. Select ( c = >
2024-04-04 10:47:28 +02:00
{
var pmi = c . Key ;
var existing = storeBlob . PaymentMethodCriteria . SingleOrDefault ( criteria = >
2024-04-04 11:00:18 +02:00
criteria . PaymentMethod = = pmi ) ;
2024-04-04 10:47:28 +02:00
return existing is null
? new PaymentMethodCriteriaViewModel { PaymentMethod = pmi . ToString ( ) , Value = "" }
: new PaymentMethodCriteriaViewModel
{
PaymentMethod = existing . PaymentMethod . ToString ( ) ,
Type = existing . Above
? PaymentMethodCriteriaViewModel . CriteriaType . GreaterThan
: PaymentMethodCriteriaViewModel . CriteriaType . LessThan ,
Value = existing . Value ? . ToString ( ) ? ? ""
} ;
} ) . ToList ( ) ;
2024-04-04 11:00:18 +02:00
vm . CelebratePayment = storeBlob . CelebratePayment ;
vm . PlaySoundOnPayment = storeBlob . PlaySoundOnPayment ;
vm . OnChainWithLnInvoiceFallback = storeBlob . OnChainWithLnInvoiceFallback ;
vm . ShowPayInWalletButton = storeBlob . ShowPayInWalletButton ;
vm . ShowStoreHeader = storeBlob . ShowStoreHeader ;
vm . LightningAmountInSatoshi = storeBlob . LightningAmountInSatoshi ;
vm . LazyPaymentMethods = storeBlob . LazyPaymentMethods ;
vm . RedirectAutomatically = storeBlob . RedirectAutomatically ;
2024-05-09 02:18:02 +02:00
vm . PaymentSoundUrl = storeBlob . PaymentSoundUrl is null
? string . Concat ( Request . GetAbsoluteRootUri ( ) . ToString ( ) , "checkout/payment.mp3" )
: await _uriResolver . Resolve ( Request . GetAbsoluteRootUri ( ) , storeBlob . PaymentSoundUrl ) ;
2024-04-04 11:00:18 +02:00
vm . HtmlTitle = storeBlob . HtmlTitle ;
vm . SupportUrl = storeBlob . StoreSupportUrl ;
vm . DisplayExpirationTimer = ( int ) storeBlob . DisplayExpirationTimer . TotalMinutes ;
vm . ReceiptOptions = CheckoutAppearanceViewModel . ReceiptOptionsViewModel . Create ( storeBlob . ReceiptOptions ) ;
vm . AutoDetectLanguage = storeBlob . AutoDetectLanguage ;
vm . SetLanguages ( _langService , storeBlob . DefaultLang ) ;
2024-04-04 10:47:28 +02:00
2024-04-04 11:00:18 +02:00
return View ( vm ) ;
}
2024-04-04 10:47:28 +02:00
2024-04-04 11:00:18 +02:00
[HttpPost("{storeId}/checkout")]
[Authorize(Policy = Policies.CanModifyStoreSettings, AuthenticationSchemes = AuthenticationSchemes.Cookie)]
public async Task < IActionResult > CheckoutAppearance ( CheckoutAppearanceViewModel model , [ FromForm ] bool RemoveSoundFile = false )
{
bool needUpdate = false ;
var blob = CurrentStore . GetStoreBlob ( ) ;
var defaultPaymentMethodId = model . DefaultPaymentMethod = = null ? null : PaymentMethodId . Parse ( model . DefaultPaymentMethod ) ;
if ( CurrentStore . GetDefaultPaymentId ( ) ! = defaultPaymentMethodId )
2024-04-04 10:47:28 +02:00
{
2024-04-04 11:00:18 +02:00
needUpdate = true ;
CurrentStore . SetDefaultPaymentId ( defaultPaymentMethodId ) ;
}
SetCryptoCurrencies ( model , CurrentStore ) ;
model . SetLanguages ( _langService , model . DefaultLang ) ;
model . PaymentMethodCriteria ? ? = new List < PaymentMethodCriteriaViewModel > ( ) ;
for ( var index = 0 ; index < model . PaymentMethodCriteria . Count ; index + + )
{
var methodCriterion = model . PaymentMethodCriteria [ index ] ;
if ( ! string . IsNullOrWhiteSpace ( methodCriterion . Value ) )
2024-04-04 10:47:28 +02:00
{
2024-04-04 11:00:18 +02:00
if ( ! CurrencyValue . TryParse ( methodCriterion . Value , out _ ) )
2024-04-04 10:47:28 +02:00
{
2024-04-04 11:00:18 +02:00
model . AddModelError ( viewModel = > viewModel . PaymentMethodCriteria [ index ] . Value ,
$"{methodCriterion.PaymentMethod}: Invalid format. Make sure to enter a valid amount and currency code. Examples: '5 USD', '0.001 BTC'" , this ) ;
2024-04-04 10:47:28 +02:00
}
}
2024-04-04 11:00:18 +02:00
}
2024-04-04 10:47:28 +02:00
2024-04-04 11:00:18 +02:00
var userId = GetUserId ( ) ;
if ( userId is null )
return NotFound ( ) ;
2024-04-04 10:47:28 +02:00
2024-04-04 11:00:18 +02:00
if ( model . SoundFile ! = null )
{
if ( model . SoundFile . Length > 1_000_000 )
2024-04-04 10:47:28 +02:00
{
2024-04-04 11:00:18 +02:00
ModelState . AddModelError ( nameof ( model . SoundFile ) , "The uploaded sound file should be less than 1MB" ) ;
}
else if ( ! model . SoundFile . ContentType . StartsWith ( "audio/" , StringComparison . InvariantCulture ) )
{
ModelState . AddModelError ( nameof ( model . SoundFile ) , "The uploaded sound file needs to be an audio file" ) ;
}
else
{
var formFile = await model . SoundFile . Bufferize ( ) ;
if ( ! FileTypeDetector . IsAudio ( formFile . Buffer , formFile . FileName ) )
2024-04-04 10:47:28 +02:00
{
ModelState . AddModelError ( nameof ( model . SoundFile ) , "The uploaded sound file needs to be an audio file" ) ;
}
else
{
2024-04-04 11:00:18 +02:00
model . SoundFile = formFile ;
// add new file
try
{
var storedFile = await _fileService . AddFile ( model . SoundFile , userId ) ;
2024-05-09 02:18:02 +02:00
blob . PaymentSoundUrl = new UnresolvedUri . FileIdUri ( storedFile . Id ) ;
2024-04-04 11:00:18 +02:00
needUpdate = true ;
}
catch ( Exception e )
{
ModelState . AddModelError ( nameof ( model . SoundFile ) , $"Could not save sound: {e.Message}" ) ;
2024-04-04 10:47:28 +02:00
}
}
}
2024-04-04 11:00:18 +02:00
}
2024-05-09 02:18:02 +02:00
else if ( RemoveSoundFile & & blob . PaymentSoundUrl is not null )
2024-04-04 11:00:18 +02:00
{
2024-05-09 02:18:02 +02:00
blob . PaymentSoundUrl = null ;
2024-04-04 11:00:18 +02:00
needUpdate = true ;
}
2024-04-04 10:47:28 +02:00
2024-04-04 11:00:18 +02:00
if ( ! ModelState . IsValid )
{
return View ( model ) ;
}
2024-04-04 10:47:28 +02:00
2024-04-04 11:00:18 +02:00
// Payment criteria for Off-Chain should also affect LNUrl
foreach ( var newCriteria in model . PaymentMethodCriteria . ToList ( ) )
{
var paymentMethodId = PaymentMethodId . Parse ( newCriteria . PaymentMethod ) ;
if ( _handlers . TryGet ( paymentMethodId ) is LightningLikePaymentHandler h )
model . PaymentMethodCriteria . Add ( new PaymentMethodCriteriaViewModel
2024-04-04 10:47:28 +02:00
{
2024-04-04 11:00:18 +02:00
PaymentMethod = PaymentTypes . LNURL . GetPaymentMethodId ( h . Network . CryptoCode ) . ToString ( ) ,
Type = newCriteria . Type ,
Value = newCriteria . Value
2024-04-04 10:47:28 +02:00
} ) ;
2024-04-04 11:00:18 +02:00
// Should not be able to set LNUrlPay criteria directly in UI
if ( _handlers . TryGet ( paymentMethodId ) is LNURLPayPaymentHandler )
model . PaymentMethodCriteria . Remove ( newCriteria ) ;
}
blob . PaymentMethodCriteria ? ? = new List < PaymentMethodCriteria > ( ) ;
foreach ( var newCriteria in model . PaymentMethodCriteria )
{
var paymentMethodId = PaymentMethodId . Parse ( newCriteria . PaymentMethod ) ;
var existingCriteria = blob . PaymentMethodCriteria . FirstOrDefault ( c = > c . PaymentMethod = = paymentMethodId ) ;
if ( existingCriteria ! = null )
blob . PaymentMethodCriteria . Remove ( existingCriteria ) ;
2024-10-04 15:24:44 +02:00
if ( CurrencyValue . TryParse ( newCriteria . Value , out var cv ) )
{
var currencyData = _currencyNameTable . GetCurrencyData ( cv . Currency , false ) ;
if ( currencyData is not null )
cv = cv . Round ( currencyData . Divisibility ) ;
}
2024-04-04 11:00:18 +02:00
blob . PaymentMethodCriteria . Add ( new PaymentMethodCriteria ( )
2024-04-04 10:47:28 +02:00
{
2024-04-04 11:00:18 +02:00
Above = newCriteria . Type = = PaymentMethodCriteriaViewModel . CriteriaType . GreaterThan ,
Value = cv ,
PaymentMethod = paymentMethodId
2024-04-04 10:47:28 +02:00
} ) ;
}
2024-04-04 11:00:18 +02:00
blob . ShowPayInWalletButton = model . ShowPayInWalletButton ;
blob . ShowStoreHeader = model . ShowStoreHeader ;
blob . CelebratePayment = model . CelebratePayment ;
blob . PlaySoundOnPayment = model . PlaySoundOnPayment ;
blob . OnChainWithLnInvoiceFallback = model . OnChainWithLnInvoiceFallback ;
blob . LightningAmountInSatoshi = model . LightningAmountInSatoshi ;
blob . LazyPaymentMethods = model . LazyPaymentMethods ;
blob . RedirectAutomatically = model . RedirectAutomatically ;
blob . ReceiptOptions = model . ReceiptOptions . ToDTO ( ) ;
blob . HtmlTitle = string . IsNullOrWhiteSpace ( model . HtmlTitle ) ? null : model . HtmlTitle ;
blob . StoreSupportUrl = string . IsNullOrWhiteSpace ( model . SupportUrl ) ? null : model . SupportUrl . IsValidEmail ( ) ? $"mailto:{model.SupportUrl}" : model . SupportUrl ;
blob . DisplayExpirationTimer = TimeSpan . FromMinutes ( model . DisplayExpirationTimer ) ;
blob . AutoDetectLanguage = model . AutoDetectLanguage ;
blob . DefaultLang = model . DefaultLang ;
if ( CurrentStore . SetStoreBlob ( blob ) )
2024-04-04 10:47:28 +02:00
{
2024-04-04 11:00:18 +02:00
needUpdate = true ;
}
if ( needUpdate )
{
await _storeRepo . UpdateStore ( CurrentStore ) ;
TempData [ WellKnownTempData . SuccessMessage ] = "Store successfully updated" ;
2024-04-04 10:47:28 +02:00
}
2024-04-04 11:00:18 +02:00
return RedirectToAction ( nameof ( CheckoutAppearance ) , new
2024-04-04 10:47:28 +02:00
{
2024-04-04 11:00:18 +02:00
storeId = CurrentStore . Id
} ) ;
}
void SetCryptoCurrencies ( CheckoutAppearanceViewModel vm , StoreData storeData )
{
var choices = GetEnabledPaymentMethodChoices ( storeData ) ;
var chosen = GetDefaultPaymentMethodChoice ( storeData ) ;
vm . PaymentMethods = new SelectList ( choices , nameof ( chosen . Value ) , nameof ( chosen . Name ) , chosen ? . Value ) ;
vm . DefaultPaymentMethod = chosen ? . Value ;
}
2024-04-04 10:47:28 +02:00
2024-04-04 11:00:18 +02:00
PaymentMethodOptionViewModel . Format ? GetDefaultPaymentMethodChoice ( StoreData storeData )
{
var enabled = storeData . GetEnabledPaymentIds ( ) ;
var defaultPaymentId = storeData . GetDefaultPaymentId ( ) ;
var defaultChoice = defaultPaymentId ? . FindNearest ( enabled ) ;
if ( defaultChoice is null )
{
defaultChoice = enabled . FirstOrDefault ( e = > e = = PaymentTypes . CHAIN . GetPaymentMethodId ( _networkProvider . DefaultNetwork . CryptoCode ) ) ? ?
enabled . FirstOrDefault ( e = > e = = PaymentTypes . LN . GetPaymentMethodId ( _networkProvider . DefaultNetwork . CryptoCode ) ) ? ?
enabled . FirstOrDefault ( ) ;
2024-04-04 10:47:28 +02:00
}
2024-04-04 11:00:18 +02:00
var choices = GetEnabledPaymentMethodChoices ( storeData ) ;
return defaultChoice is null ? null : choices . FirstOrDefault ( c = > defaultChoice . ToString ( ) . Equals ( c . Value , StringComparison . OrdinalIgnoreCase ) ) ;
2024-04-04 10:47:28 +02:00
}
}