Deploy LittleShop to Hostinger with Docker and BunkerWeb
- Updated Docker configuration for production deployment - Added SilverPay integration settings - Configured for admin.thebankofdebbie.giize.com deployment - Includes all recent security fixes and improvements 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -10,13 +10,16 @@ namespace LittleShop.Areas.Admin.Controllers;
|
||||
public class SystemSettingsController : Controller
|
||||
{
|
||||
private readonly ISystemSettingsService _systemSettingsService;
|
||||
private readonly ISilverPayService _silverPayService;
|
||||
private readonly ILogger<SystemSettingsController> _logger;
|
||||
|
||||
public SystemSettingsController(
|
||||
ISystemSettingsService systemSettingsService,
|
||||
ISilverPayService silverPayService,
|
||||
ILogger<SystemSettingsController> logger)
|
||||
{
|
||||
_systemSettingsService = systemSettingsService;
|
||||
_silverPayService = silverPayService;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
@@ -30,9 +33,21 @@ public class SystemSettingsController : Controller
|
||||
{
|
||||
{ "TBTC", await _systemSettingsService.IsTestCurrencyEnabledAsync("TBTC") },
|
||||
{ "TLTC", await _systemSettingsService.IsTestCurrencyEnabledAsync("TLTC") }
|
||||
},
|
||||
SilverPaySettings = new SilverPaySettingsViewModel
|
||||
{
|
||||
BaseUrl = await _systemSettingsService.GetSettingAsync("SilverPay.BaseUrl") ?? "",
|
||||
ApiKey = await _systemSettingsService.GetSettingAsync("SilverPay.ApiKey") ?? "",
|
||||
WebhookSecret = await _systemSettingsService.GetSettingAsync("SilverPay.WebhookSecret") ?? "",
|
||||
DefaultWebhookUrl = await _systemSettingsService.GetSettingAsync("SilverPay.DefaultWebhookUrl") ?? "",
|
||||
LastTestDate = await _systemSettingsService.GetSettingAsync<DateTime?>("SilverPay.LastTestDate"),
|
||||
LastTestSuccess = await _systemSettingsService.GetSettingAsync<bool>("SilverPay.LastTestSuccess", false),
|
||||
LastTestMessage = await _systemSettingsService.GetSettingAsync("SilverPay.LastTestMessage") ?? ""
|
||||
}
|
||||
};
|
||||
|
||||
viewModel.SilverPaySettings.IsConfigured = !string.IsNullOrEmpty(viewModel.SilverPaySettings.BaseUrl);
|
||||
|
||||
return View(viewModel);
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -67,9 +82,94 @@ public class SystemSettingsController : Controller
|
||||
return View("Index", model);
|
||||
}
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
public async Task<IActionResult> UpdateSilverPaySettings(SilverPaySettingsViewModel model)
|
||||
{
|
||||
try
|
||||
{
|
||||
await _systemSettingsService.SetSettingAsync("SilverPay.BaseUrl", model.BaseUrl ?? "", "SilverPay API base URL");
|
||||
await _systemSettingsService.SetSettingAsync("SilverPay.ApiKey", model.ApiKey ?? "", "SilverPay API authentication key");
|
||||
await _systemSettingsService.SetSettingAsync("SilverPay.WebhookSecret", model.WebhookSecret ?? "", "SilverPay webhook validation secret");
|
||||
await _systemSettingsService.SetSettingAsync("SilverPay.DefaultWebhookUrl", model.DefaultWebhookUrl ?? "", "Default webhook URL for SilverPay notifications");
|
||||
|
||||
_logger.LogInformation("Updated SilverPay settings");
|
||||
TempData["Success"] = "SilverPay settings updated successfully";
|
||||
|
||||
return RedirectToAction("Index");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Error updating SilverPay settings");
|
||||
TempData["Error"] = "Failed to update SilverPay settings";
|
||||
return RedirectToAction("Index");
|
||||
}
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
public async Task<IActionResult> TestSilverPayConnection()
|
||||
{
|
||||
try
|
||||
{
|
||||
var baseUrl = await _systemSettingsService.GetSettingAsync("SilverPay.BaseUrl");
|
||||
|
||||
if (string.IsNullOrEmpty(baseUrl))
|
||||
{
|
||||
TempData["Error"] = "SilverPay base URL not configured";
|
||||
return RedirectToAction("Index");
|
||||
}
|
||||
|
||||
// Test the connection by getting supported currencies
|
||||
var currencies = await _silverPayService.GetSupportedCurrenciesAsync();
|
||||
|
||||
if (currencies != null && currencies.Count > 0)
|
||||
{
|
||||
await _systemSettingsService.SetSettingAsync("SilverPay.LastTestDate", DateTime.UtcNow);
|
||||
await _systemSettingsService.SetSettingAsync("SilverPay.LastTestSuccess", true);
|
||||
await _systemSettingsService.SetSettingAsync("SilverPay.LastTestMessage",
|
||||
$"Successfully connected. Supported currencies: {string.Join(", ", currencies)}");
|
||||
|
||||
TempData["Success"] = $"SilverPay connection successful! Supported currencies: {string.Join(", ", currencies)}";
|
||||
_logger.LogInformation("SilverPay connection test successful. Currencies: {Currencies}", string.Join(", ", currencies));
|
||||
}
|
||||
else
|
||||
{
|
||||
await _systemSettingsService.SetSettingAsync("SilverPay.LastTestDate", DateTime.UtcNow);
|
||||
await _systemSettingsService.SetSettingAsync("SilverPay.LastTestSuccess", false);
|
||||
await _systemSettingsService.SetSettingAsync("SilverPay.LastTestMessage", "Connection established but no currencies returned");
|
||||
|
||||
TempData["Warning"] = "SilverPay connection established but no supported currencies returned";
|
||||
_logger.LogWarning("SilverPay connection test returned no currencies");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await _systemSettingsService.SetSettingAsync("SilverPay.LastTestDate", DateTime.UtcNow);
|
||||
await _systemSettingsService.SetSettingAsync("SilverPay.LastTestSuccess", false);
|
||||
await _systemSettingsService.SetSettingAsync("SilverPay.LastTestMessage", ex.Message);
|
||||
|
||||
TempData["Error"] = $"SilverPay connection test failed: {ex.Message}";
|
||||
_logger.LogError(ex, "SilverPay connection test failed");
|
||||
}
|
||||
|
||||
return RedirectToAction("Index");
|
||||
}
|
||||
}
|
||||
|
||||
public class SystemSettingsViewModel
|
||||
{
|
||||
public Dictionary<string, bool> TestCurrencies { get; set; } = new();
|
||||
public SilverPaySettingsViewModel SilverPaySettings { get; set; } = new();
|
||||
}
|
||||
|
||||
public class SilverPaySettingsViewModel
|
||||
{
|
||||
public string BaseUrl { get; set; } = "";
|
||||
public string ApiKey { get; set; } = "";
|
||||
public string WebhookSecret { get; set; } = "";
|
||||
public string DefaultWebhookUrl { get; set; } = "";
|
||||
public bool IsConfigured { get; set; }
|
||||
public DateTime? LastTestDate { get; set; }
|
||||
public bool LastTestSuccess { get; set; }
|
||||
public string LastTestMessage { get; set; } = "";
|
||||
}
|
||||
@@ -77,11 +77,11 @@
|
||||
<h5><i class="fas fa-list"></i> Product Variations Summary</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
@if ((int)ViewData["TotalVariations"] > 0)
|
||||
@if (ViewData["TotalVariants"] != null && (int)ViewData["TotalVariants"] > 0)
|
||||
{
|
||||
<div class="alert alert-success">
|
||||
<i class="fas fa-check-circle"></i>
|
||||
<strong>@ViewData["TotalVariations"] product variations</strong> have been configured across your catalog.
|
||||
<strong>@ViewData["TotalVariants"] product variations</strong> have been configured across your catalog.
|
||||
Customers can now choose quantity-based pricing options!
|
||||
</div>
|
||||
}
|
||||
|
||||
@@ -11,6 +11,30 @@
|
||||
<h3 class="card-title">System Settings</h3>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
@if (TempData["Success"] != null)
|
||||
{
|
||||
<div class="alert alert-success alert-dismissible fade show" role="alert">
|
||||
@TempData["Success"]
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
||||
</div>
|
||||
}
|
||||
|
||||
@if (TempData["Warning"] != null)
|
||||
{
|
||||
<div class="alert alert-warning alert-dismissible fade show" role="alert">
|
||||
@TempData["Warning"]
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
||||
</div>
|
||||
}
|
||||
|
||||
@if (TempData["Error"] != null)
|
||||
{
|
||||
<div class="alert alert-danger alert-dismissible fade show" role="alert">
|
||||
@TempData["Error"]
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
||||
</div>
|
||||
}
|
||||
|
||||
@if (!string.IsNullOrEmpty(ViewBag.Success))
|
||||
{
|
||||
<div class="alert alert-success alert-dismissible fade show" role="alert">
|
||||
@@ -97,8 +121,185 @@
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<div class="row mt-4">
|
||||
<div class="col-12">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5 class="card-title">SilverPay Integration Settings</h5>
|
||||
<p class="card-subtitle text-muted">
|
||||
Configure SilverPay payment gateway integration for cryptocurrency payments.
|
||||
</p>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form asp-controller="SystemSettings" asp-action="UpdateSilverPaySettings" method="post">
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<div class="mb-3">
|
||||
<label for="silverPayBaseUrl" class="form-label">
|
||||
<strong>Base URL</strong>
|
||||
<small class="text-muted d-block">SilverPay API endpoint URL</small>
|
||||
</label>
|
||||
<input type="url"
|
||||
class="form-control"
|
||||
id="silverPayBaseUrl"
|
||||
name="BaseUrl"
|
||||
value="@Model.SilverPaySettings.BaseUrl"
|
||||
placeholder="http://31.97.57.205:8001"
|
||||
required>
|
||||
<small class="form-text text-muted">
|
||||
Example: http://31.97.57.205:8001 or https://api.silverpay.com
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="mb-3">
|
||||
<label for="silverPayApiKey" class="form-label">
|
||||
<strong>API Key</strong>
|
||||
<small class="text-muted d-block">Authentication key for SilverPay API</small>
|
||||
</label>
|
||||
<div class="input-group">
|
||||
<input type="password"
|
||||
class="form-control"
|
||||
id="silverPayApiKey"
|
||||
name="ApiKey"
|
||||
value="@Model.SilverPaySettings.ApiKey"
|
||||
placeholder="Enter API key">
|
||||
<button class="btn btn-outline-secondary" type="button" onclick="togglePasswordVisibility('silverPayApiKey')">
|
||||
<i class="fas fa-eye"></i>
|
||||
</button>
|
||||
</div>
|
||||
<small class="form-text text-muted">
|
||||
Leave empty if SilverPay doesn't require authentication
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<div class="mb-3">
|
||||
<label for="silverPayWebhookSecret" class="form-label">
|
||||
<strong>Webhook Secret</strong>
|
||||
<small class="text-muted d-block">Secret key for webhook validation</small>
|
||||
</label>
|
||||
<div class="input-group">
|
||||
<input type="password"
|
||||
class="form-control"
|
||||
id="silverPayWebhookSecret"
|
||||
name="WebhookSecret"
|
||||
value="@Model.SilverPaySettings.WebhookSecret"
|
||||
placeholder="Enter webhook secret">
|
||||
<button class="btn btn-outline-secondary" type="button" onclick="togglePasswordVisibility('silverPayWebhookSecret')">
|
||||
<i class="fas fa-eye"></i>
|
||||
</button>
|
||||
</div>
|
||||
<small class="form-text text-muted">
|
||||
Used to validate incoming webhook requests from SilverPay
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="mb-3">
|
||||
<label for="silverPayWebhookUrl" class="form-label">
|
||||
<strong>Default Webhook URL</strong>
|
||||
<small class="text-muted d-block">Your endpoint for receiving payment notifications</small>
|
||||
</label>
|
||||
<input type="url"
|
||||
class="form-control"
|
||||
id="silverPayWebhookUrl"
|
||||
name="DefaultWebhookUrl"
|
||||
value="@Model.SilverPaySettings.DefaultWebhookUrl"
|
||||
placeholder="https://yourdomain.com/api/silverpay/webhook">
|
||||
<small class="form-text text-muted">
|
||||
Example: https://yourdomain.com/api/silverpay/webhook
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<div class="mb-3">
|
||||
<label class="form-label">
|
||||
<strong>Connection Status</strong>
|
||||
</label>
|
||||
<div class="form-control-plaintext">
|
||||
@if (Model.SilverPaySettings.IsConfigured)
|
||||
{
|
||||
<span class="badge bg-success">
|
||||
<i class="fas fa-check-circle"></i> Configured
|
||||
</span>
|
||||
@if (Model.SilverPaySettings.LastTestSuccess)
|
||||
{
|
||||
<span class="badge bg-success ms-2">
|
||||
<i class="fas fa-plug"></i> Connected
|
||||
</span>
|
||||
}
|
||||
else
|
||||
{
|
||||
<span class="badge bg-warning ms-2">
|
||||
<i class="fas fa-exclamation-triangle"></i> Not Tested
|
||||
</span>
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
<span class="badge bg-secondary">
|
||||
<i class="fas fa-times-circle"></i> Not Configured
|
||||
</span>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="mb-3">
|
||||
<label class="form-label">
|
||||
<strong>Last Test</strong>
|
||||
</label>
|
||||
<div class="form-control-plaintext">
|
||||
@if (Model.SilverPaySettings.LastTestDate.HasValue)
|
||||
{
|
||||
<span>@Model.SilverPaySettings.LastTestDate.Value.ToString("yyyy-MM-dd HH:mm:ss")</span>
|
||||
@if (!string.IsNullOrEmpty(Model.SilverPaySettings.LastTestMessage))
|
||||
{
|
||||
<small class="text-muted d-block">@Model.SilverPaySettings.LastTestMessage</small>
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
<span class="text-muted">Never tested</span>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-3">
|
||||
<button type="submit" class="btn btn-primary">
|
||||
<i class="fas fa-save"></i> Save SilverPay Settings
|
||||
</button>
|
||||
<button type="submit" formaction="/Admin/SystemSettings/TestSilverPayConnection" class="btn btn-secondary ms-2">
|
||||
<i class="fas fa-plug"></i> Test Connection
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@section Scripts {
|
||||
<script>
|
||||
function togglePasswordVisibility(inputId) {
|
||||
var input = document.getElementById(inputId);
|
||||
if (input.type === "password") {
|
||||
input.type = "text";
|
||||
} else {
|
||||
input.type = "password";
|
||||
}
|
||||
}
|
||||
</script>
|
||||
}
|
||||
Reference in New Issue
Block a user