mirror of
https://github.com/aljazceru/btcpayserver.git
synced 2025-12-18 14:34:23 +01:00
Server Settings: Customize instance name and add contact URL (#5718)
* Server Settings: Customize instance name and add contact URL - The custom instance name would improve #5563 - Added contact URL closes #4806 * Fix custom logo display
This commit is contained in:
@@ -252,7 +252,7 @@
|
|||||||
{
|
{
|
||||||
<ul id="mainNavSettings" class="navbar-nav border-top p-3 px-lg-4">
|
<ul id="mainNavSettings" class="navbar-nav border-top p-3 px-lg-4">
|
||||||
<li class="nav-item" permission="@Policies.CanModifyServerSettings">
|
<li class="nav-item" permission="@Policies.CanModifyServerSettings">
|
||||||
<a asp-area="" asp-controller="UIServer" asp-action="ListUsers" class="nav-link @ViewData.IsActivePage(ServerNavPages.Users) @ViewData.IsActivePage(ServerNavPages.Emails) @ViewData.IsActivePage(ServerNavPages.Policies) @ViewData.IsActivePage(ServerNavPages.Services) @ViewData.IsActivePage(ServerNavPages.Theme) @ViewData.IsActivePage(ServerNavPages.Maintenance) @ViewData.IsActivePage(ServerNavPages.Logs) @ViewData.IsActivePage(ServerNavPages.Files)" id="Nav-ServerSettings">
|
<a asp-area="" asp-controller="UIServer" asp-action="ListUsers" class="nav-link @ViewData.IsActivePage(ServerNavPages.Users) @ViewData.IsActivePage(ServerNavPages.Emails) @ViewData.IsActivePage(ServerNavPages.Policies) @ViewData.IsActivePage(ServerNavPages.Services) @ViewData.IsActivePage(ServerNavPages.Branding) @ViewData.IsActivePage(ServerNavPages.Maintenance) @ViewData.IsActivePage(ServerNavPages.Logs) @ViewData.IsActivePage(ServerNavPages.Files)" id="Nav-ServerSettings">
|
||||||
<vc:icon symbol="server-settings"/>
|
<vc:icon symbol="server-settings"/>
|
||||||
<span>Server Settings</span>
|
<span>Server Settings</span>
|
||||||
</a>
|
</a>
|
||||||
|
|||||||
@@ -150,6 +150,7 @@ namespace BTCPayServer.Controllers
|
|||||||
}
|
}
|
||||||
if (!ModelState.IsValid)
|
if (!ModelState.IsValid)
|
||||||
return View(vm);
|
return View(vm);
|
||||||
|
|
||||||
if (command == "changedomain")
|
if (command == "changedomain")
|
||||||
{
|
{
|
||||||
if (string.IsNullOrWhiteSpace(vm.DNSDomain))
|
if (string.IsNullOrWhiteSpace(vm.DNSDomain))
|
||||||
@@ -995,143 +996,167 @@ namespace BTCPayServer.Controllers
|
|||||||
return RedirectToAction(nameof(Services));
|
return RedirectToAction(nameof(Services));
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("server/theme")]
|
[HttpGet("server/branding")]
|
||||||
public async Task<IActionResult> Theme()
|
public async Task<IActionResult> Branding()
|
||||||
{
|
{
|
||||||
var data = await _SettingsRepository.GetSettingAsync<ThemeSettings>() ?? new ThemeSettings();
|
var server = await _SettingsRepository.GetSettingAsync<ServerSettings>() ?? new ServerSettings();
|
||||||
return View(data);
|
var theme = await _SettingsRepository.GetSettingAsync<ThemeSettings>() ?? new ThemeSettings();
|
||||||
|
|
||||||
|
var vm = new BrandingViewModel
|
||||||
|
{
|
||||||
|
ServerName = server.ServerName,
|
||||||
|
ContactUrl = server.ContactUrl,
|
||||||
|
CustomTheme = theme.CustomTheme,
|
||||||
|
CustomThemeExtension = theme.CustomThemeExtension,
|
||||||
|
CustomThemeCssUri = theme.CustomThemeCssUri,
|
||||||
|
CustomThemeFileId = theme.CustomThemeFileId,
|
||||||
|
LogoFileId = theme.LogoFileId
|
||||||
|
};
|
||||||
|
return View(vm);
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpPost("server/theme")]
|
[HttpPost("server/branding")]
|
||||||
public async Task<IActionResult> Theme(
|
public async Task<IActionResult> Branding(
|
||||||
ThemeSettings model,
|
BrandingViewModel vm,
|
||||||
[FromForm] bool RemoveLogoFile,
|
[FromForm] bool RemoveLogoFile,
|
||||||
[FromForm] bool RemoveCustomThemeFile)
|
[FromForm] bool RemoveCustomThemeFile)
|
||||||
{
|
{
|
||||||
var settingsChanged = false;
|
var settingsChanged = false;
|
||||||
var settings = await _SettingsRepository.GetSettingAsync<ThemeSettings>() ?? new ThemeSettings();
|
var server = await _SettingsRepository.GetSettingAsync<ServerSettings>() ?? new ServerSettings();
|
||||||
|
var theme = await _SettingsRepository.GetSettingAsync<ThemeSettings>() ?? new ThemeSettings();
|
||||||
|
|
||||||
var userId = GetUserId();
|
var userId = GetUserId();
|
||||||
if (userId is null)
|
if (userId is null)
|
||||||
return NotFound();
|
return NotFound();
|
||||||
|
|
||||||
if (model.CustomThemeFile != null)
|
vm.LogoFileId = theme.LogoFileId;
|
||||||
|
vm.CustomThemeFileId = theme.CustomThemeFileId;
|
||||||
|
|
||||||
|
if (server.ServerName != vm.ServerName || server.ContactUrl != vm.ContactUrl)
|
||||||
{
|
{
|
||||||
if (model.CustomThemeFile.ContentType.Equals("text/css", StringComparison.InvariantCulture))
|
server.ServerName = vm.ServerName;
|
||||||
|
server.ContactUrl = vm.ContactUrl;
|
||||||
|
settingsChanged = true;
|
||||||
|
await _SettingsRepository.UpdateSetting(server);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vm.CustomThemeFile != null)
|
||||||
|
{
|
||||||
|
if (vm.CustomThemeFile.ContentType.Equals("text/css", StringComparison.InvariantCulture))
|
||||||
{
|
{
|
||||||
// delete existing file
|
// delete existing file
|
||||||
if (!string.IsNullOrEmpty(settings.CustomThemeFileId))
|
if (!string.IsNullOrEmpty(theme.CustomThemeFileId))
|
||||||
{
|
{
|
||||||
await _fileService.RemoveFile(settings.CustomThemeFileId, userId);
|
await _fileService.RemoveFile(theme.CustomThemeFileId, userId);
|
||||||
}
|
}
|
||||||
|
|
||||||
// add new file
|
// add new file
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var storedFile = await _fileService.AddFile(model.CustomThemeFile, userId);
|
var storedFile = await _fileService.AddFile(vm.CustomThemeFile, userId);
|
||||||
settings.CustomThemeFileId = storedFile.Id;
|
vm.CustomThemeFileId = theme.CustomThemeFileId = storedFile.Id;
|
||||||
settingsChanged = true;
|
settingsChanged = true;
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
ModelState.AddModelError(nameof(settings.CustomThemeFile), $"Could not save theme file: {e.Message}");
|
ModelState.AddModelError(nameof(vm.CustomThemeFile), $"Could not save theme file: {e.Message}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ModelState.AddModelError(nameof(settings.CustomThemeFile), "The uploaded theme file needs to be a CSS file");
|
ModelState.AddModelError(nameof(vm.CustomThemeFile), "The uploaded theme file needs to be a CSS file");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (RemoveCustomThemeFile && !string.IsNullOrEmpty(settings.CustomThemeFileId))
|
else if (RemoveCustomThemeFile && !string.IsNullOrEmpty(theme.CustomThemeFileId))
|
||||||
{
|
{
|
||||||
await _fileService.RemoveFile(settings.CustomThemeFileId, userId);
|
await _fileService.RemoveFile(theme.CustomThemeFileId, userId);
|
||||||
settings.CustomThemeFileId = null;
|
vm.CustomThemeFileId = theme.CustomThemeFileId = null;
|
||||||
settingsChanged = true;
|
settingsChanged = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (model.LogoFile != null)
|
if (vm.LogoFile != null)
|
||||||
{
|
{
|
||||||
if (model.LogoFile.Length > 1_000_000)
|
if (vm.LogoFile.Length > 1_000_000)
|
||||||
{
|
{
|
||||||
ModelState.AddModelError(nameof(model.LogoFile), "The uploaded logo file should be less than 1MB");
|
ModelState.AddModelError(nameof(vm.LogoFile), "The uploaded logo file should be less than 1MB");
|
||||||
}
|
}
|
||||||
else if (!model.LogoFile.ContentType.StartsWith("image/", StringComparison.InvariantCulture))
|
else if (!vm.LogoFile.ContentType.StartsWith("image/", StringComparison.InvariantCulture))
|
||||||
{
|
{
|
||||||
ModelState.AddModelError(nameof(model.LogoFile), "The uploaded logo file needs to be an image");
|
ModelState.AddModelError(nameof(vm.LogoFile), "The uploaded logo file needs to be an image");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var formFile = await model.LogoFile.Bufferize();
|
var formFile = await vm.LogoFile.Bufferize();
|
||||||
if (!FileTypeDetector.IsPicture(formFile.Buffer, formFile.FileName))
|
if (!FileTypeDetector.IsPicture(formFile.Buffer, formFile.FileName))
|
||||||
{
|
{
|
||||||
ModelState.AddModelError(nameof(model.LogoFile), "The uploaded logo file needs to be an image");
|
ModelState.AddModelError(nameof(vm.LogoFile), "The uploaded logo file needs to be an image");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
model.LogoFile = formFile;
|
vm.LogoFile = formFile;
|
||||||
// delete existing file
|
// delete existing file
|
||||||
if (!string.IsNullOrEmpty(settings.LogoFileId))
|
if (!string.IsNullOrEmpty(theme.LogoFileId))
|
||||||
{
|
{
|
||||||
await _fileService.RemoveFile(settings.LogoFileId, userId);
|
await _fileService.RemoveFile(theme.LogoFileId, userId);
|
||||||
}
|
}
|
||||||
// add new file
|
// add new file
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var storedFile = await _fileService.AddFile(model.LogoFile, userId);
|
var storedFile = await _fileService.AddFile(vm.LogoFile, userId);
|
||||||
settings.LogoFileId = storedFile.Id;
|
vm.LogoFileId = theme.LogoFileId = storedFile.Id;
|
||||||
settingsChanged = true;
|
settingsChanged = true;
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
ModelState.AddModelError(nameof(settings.LogoFile), $"Could not save logo: {e.Message}");
|
ModelState.AddModelError(nameof(vm.LogoFile), $"Could not save logo: {e.Message}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (RemoveLogoFile && !string.IsNullOrEmpty(settings.LogoFileId))
|
else if (RemoveLogoFile && !string.IsNullOrEmpty(theme.LogoFileId))
|
||||||
{
|
{
|
||||||
await _fileService.RemoveFile(settings.LogoFileId, userId);
|
await _fileService.RemoveFile(theme.LogoFileId, userId);
|
||||||
settings.LogoFileId = null;
|
vm.LogoFileId = theme.LogoFileId = null;
|
||||||
settingsChanged = true;
|
settingsChanged = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (model.CustomTheme && !string.IsNullOrEmpty(model.CustomThemeCssUri) && !Uri.IsWellFormedUriString(model.CustomThemeCssUri, UriKind.RelativeOrAbsolute))
|
if (vm.CustomTheme && !string.IsNullOrEmpty(vm.CustomThemeCssUri) && !Uri.IsWellFormedUriString(vm.CustomThemeCssUri, UriKind.RelativeOrAbsolute))
|
||||||
{
|
{
|
||||||
ModelState.AddModelError(nameof(settings.CustomThemeCssUri), "Please provide a non-empty theme URI");
|
ModelState.AddModelError(nameof(theme.CustomThemeCssUri), "Please provide a non-empty theme URI");
|
||||||
}
|
}
|
||||||
else if (settings.CustomThemeCssUri != model.CustomThemeCssUri)
|
else if (theme.CustomThemeCssUri != vm.CustomThemeCssUri)
|
||||||
{
|
{
|
||||||
settings.CustomThemeCssUri = model.CustomThemeCssUri;
|
theme.CustomThemeCssUri = vm.CustomThemeCssUri;
|
||||||
settingsChanged = true;
|
settingsChanged = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (settings.CustomThemeExtension != model.CustomThemeExtension)
|
if (theme.CustomThemeExtension != vm.CustomThemeExtension)
|
||||||
{
|
{
|
||||||
// Require a custom theme to be defined in that case
|
// Require a custom theme to be defined in that case
|
||||||
if (string.IsNullOrEmpty(model.CustomThemeCssUri) && string.IsNullOrEmpty(settings.CustomThemeFileId))
|
if (string.IsNullOrEmpty(vm.CustomThemeCssUri) && string.IsNullOrEmpty(theme.CustomThemeFileId))
|
||||||
{
|
{
|
||||||
ModelState.AddModelError(nameof(settings.CustomThemeFile), "Please provide a custom theme");
|
ModelState.AddModelError(nameof(vm.CustomThemeFile), "Please provide a custom theme");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
settings.CustomThemeExtension = model.CustomThemeExtension;
|
theme.CustomThemeExtension = vm.CustomThemeExtension;
|
||||||
settingsChanged = true;
|
settingsChanged = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (settings.CustomTheme != model.CustomTheme)
|
if (theme.CustomTheme != vm.CustomTheme)
|
||||||
{
|
{
|
||||||
settings.CustomTheme = model.CustomTheme;
|
theme.CustomTheme = vm.CustomTheme;
|
||||||
settingsChanged = true;
|
settingsChanged = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (settingsChanged)
|
if (settingsChanged)
|
||||||
{
|
{
|
||||||
await _SettingsRepository.UpdateSetting(settings);
|
await _SettingsRepository.UpdateSetting(theme);
|
||||||
TempData[WellKnownTempData.SuccessMessage] = "Theme settings updated successfully";
|
TempData[WellKnownTempData.SuccessMessage] = "Settings updated successfully";
|
||||||
}
|
}
|
||||||
|
|
||||||
return View(settings);
|
return View(vm);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Route("server/emails")]
|
[Route("server/emails")]
|
||||||
|
|||||||
40
BTCPayServer/Models/ServerViewModels/BrandingViewModel.cs
Normal file
40
BTCPayServer/Models/ServerViewModels/BrandingViewModel.cs
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using BTCPayServer.Services;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace BTCPayServer.Models.ServerViewModels;
|
||||||
|
|
||||||
|
public class BrandingViewModel
|
||||||
|
{
|
||||||
|
// Server
|
||||||
|
[Display(Name = "Server Name")]
|
||||||
|
public string ServerName { get; set; }
|
||||||
|
|
||||||
|
[Display(Name = "Contact URL")]
|
||||||
|
public string ContactUrl { get; set; }
|
||||||
|
|
||||||
|
// Theme
|
||||||
|
[Display(Name = "Use custom theme")]
|
||||||
|
public bool CustomTheme { get; set; }
|
||||||
|
|
||||||
|
[Display(Name = "Custom Theme Extension Type")]
|
||||||
|
public ThemeExtension CustomThemeExtension { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Populate)]
|
||||||
|
[MaxLength(500)]
|
||||||
|
[Display(Name = "Custom Theme CSS URL")]
|
||||||
|
public string CustomThemeCssUri { get; set; }
|
||||||
|
|
||||||
|
[Display(Name = "Custom Theme File")]
|
||||||
|
[JsonIgnore]
|
||||||
|
public IFormFile CustomThemeFile { get; set; }
|
||||||
|
|
||||||
|
public string CustomThemeFileId { get; set; }
|
||||||
|
|
||||||
|
[Display(Name = "Logo")]
|
||||||
|
[JsonIgnore]
|
||||||
|
public IFormFile LogoFile { get; set; }
|
||||||
|
|
||||||
|
public string LogoFileId { get; set; }
|
||||||
|
}
|
||||||
14
BTCPayServer/Services/ServerSettings.cs
Normal file
14
BTCPayServer/Services/ServerSettings.cs
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace BTCPayServer.Services;
|
||||||
|
|
||||||
|
public class ServerSettings
|
||||||
|
{
|
||||||
|
[Display(Name = "Server Name")]
|
||||||
|
public string ServerName { get; set; }
|
||||||
|
|
||||||
|
[Display(Name = "Contact URL")]
|
||||||
|
public string ContactUrl { get; set; }
|
||||||
|
}
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using Microsoft.AspNetCore.Http;
|
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
namespace BTCPayServer.Services;
|
namespace BTCPayServer.Services;
|
||||||
@@ -27,16 +26,8 @@ public class ThemeSettings
|
|||||||
[Display(Name = "Custom Theme CSS URL")]
|
[Display(Name = "Custom Theme CSS URL")]
|
||||||
public string CustomThemeCssUri { get; set; }
|
public string CustomThemeCssUri { get; set; }
|
||||||
|
|
||||||
[Display(Name = "Custom Theme File")]
|
|
||||||
[JsonIgnore]
|
|
||||||
public IFormFile CustomThemeFile { get; set; }
|
|
||||||
|
|
||||||
public string CustomThemeFileId { get; set; }
|
public string CustomThemeFileId { get; set; }
|
||||||
|
|
||||||
[Display(Name = "Logo")]
|
|
||||||
[JsonIgnore]
|
|
||||||
public IFormFile LogoFile { get; set; }
|
|
||||||
|
|
||||||
public string LogoFileId { get; set; }
|
public string LogoFileId { get; set; }
|
||||||
|
|
||||||
public bool FirstRun { get; set; }
|
public bool FirstRun { get; set; }
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
@using System.IO
|
@using System.IO
|
||||||
@using BTCPayServer.Services
|
@using BTCPayServer.Services
|
||||||
@inject IWebHostEnvironment WebHostEnvironment
|
@inject IWebHostEnvironment WebHostEnvironment
|
||||||
|
@inject SettingsRepository SettingsRepository
|
||||||
@inject BTCPayServerEnvironment Env
|
@inject BTCPayServerEnvironment Env
|
||||||
@model BTCPayServer.Plugins.PointOfSale.Models.ViewPointOfSaleViewModel
|
@model BTCPayServer.Plugins.PointOfSale.Models.ViewPointOfSaleViewModel
|
||||||
@{
|
@{
|
||||||
@@ -12,6 +13,7 @@
|
|||||||
|
|
||||||
async Task<string> GetDynamicManifest(string title)
|
async Task<string> GetDynamicManifest(string title)
|
||||||
{
|
{
|
||||||
|
var settings = await SettingsRepository.GetSettingAsync<ServerSettings>() ?? new ServerSettings();
|
||||||
var manifest = WebHostEnvironment.WebRootFileProvider.GetFileInfo("manifest.json");
|
var manifest = WebHostEnvironment.WebRootFileProvider.GetFileInfo("manifest.json");
|
||||||
if (!manifest.Exists)
|
if (!manifest.Exists)
|
||||||
{
|
{
|
||||||
@@ -19,8 +21,9 @@
|
|||||||
}
|
}
|
||||||
using var reader = new StreamReader(manifest.CreateReadStream());
|
using var reader = new StreamReader(manifest.CreateReadStream());
|
||||||
var jObject = JObject.Parse(await reader.ReadToEndAsync());
|
var jObject = JObject.Parse(await reader.ReadToEndAsync());
|
||||||
|
var serverName = string.IsNullOrWhiteSpace(settings.ServerName) ? "BTCPay Server" : settings.ServerName;
|
||||||
jObject["short_name"] = title;
|
jObject["short_name"] = title;
|
||||||
jObject["name"] = $"BTCPay Server: {title}";
|
jObject["name"] = $"{serverName}: {title}";
|
||||||
foreach (var jToken in jObject["icons"]!)
|
foreach (var jToken in jObject["icons"]!)
|
||||||
{
|
{
|
||||||
var icon = (JObject)jToken;
|
var icon = (JObject)jToken;
|
||||||
|
|||||||
@@ -1,7 +1,13 @@
|
|||||||
|
@using BTCPayServer.Services
|
||||||
|
@using Microsoft.AspNetCore.Mvc.TagHelpers
|
||||||
|
@using BTCPayServer.Components.MainLogo
|
||||||
|
@inject SettingsRepository SettingsRepository
|
||||||
@{
|
@{
|
||||||
Layout = "_LayoutSimple";
|
Layout = "_LayoutSimple";
|
||||||
ViewBag.ShowTitle ??= true;
|
ViewBag.ShowTitle ??= true;
|
||||||
ViewBag.ShowLeadText ??= false;
|
ViewBag.ShowLeadText ??= false;
|
||||||
|
|
||||||
|
var settings = await SettingsRepository.GetSettingAsync<ServerSettings>() ?? new ServerSettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
@section PageHeadContent {
|
@section PageHeadContent {
|
||||||
@@ -33,7 +39,7 @@
|
|||||||
<vc:main-logo />
|
<vc:main-logo />
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<h1 class="h2 mb-3">Welcome to your BTCPay Server</h1>
|
<h1 class="h2 mb-3">Welcome to @(string.IsNullOrWhiteSpace(settings.ServerName) ? "your BTCPay\u00a0Server" : settings.ServerName)</h1>
|
||||||
@if (ViewBag.ShowLeadText)
|
@if (ViewBag.ShowLeadText)
|
||||||
{
|
{
|
||||||
<p class="lead">
|
<p class="lead">
|
||||||
@@ -54,6 +60,13 @@
|
|||||||
@RenderBody()
|
@RenderBody()
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@if (!string.IsNullOrWhiteSpace(settings.ContactUrl))
|
||||||
|
{
|
||||||
|
<p class="text-center mt-n5 mb-5 pt-2">
|
||||||
|
<a class="text-secondary" href="@settings.ContactUrl" id="ContactLink">Contact Us</a>
|
||||||
|
</p>
|
||||||
|
}
|
||||||
|
|
||||||
<div class="row justify-content-center mt-5">
|
<div class="row justify-content-center mt-5">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<partial name="_BTCPaySupporters"/>
|
<partial name="_BTCPaySupporters"/>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
.main-logo { height: 4rem; width: 18rem; }
|
.main-logo { height: 4.5rem; max-width: 18rem; }
|
||||||
.main-logo-btcpay .main-logo-btcpay--small { display: none; }
|
.main-logo-btcpay .main-logo-btcpay--small { display: none; }
|
||||||
.lead img { max-width: 100%; }
|
.lead img { max-width: 100%; }
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -1,11 +1,15 @@
|
|||||||
|
@using BTCPayServer.Services
|
||||||
|
@using Microsoft.AspNetCore.Mvc.TagHelpers
|
||||||
@model HomeViewModel;
|
@model HomeViewModel;
|
||||||
|
@inject SettingsRepository SettingsRepository
|
||||||
@{
|
@{
|
||||||
ViewData["Title"] = "BTCPay Server";
|
var settings = await SettingsRepository.GetSettingAsync<ServerSettings>() ?? new ServerSettings();
|
||||||
|
ViewData["Title"] = string.IsNullOrWhiteSpace(settings.ServerName) ? "BTCPay Server" : settings.ServerName;
|
||||||
}
|
}
|
||||||
|
|
||||||
<partial name="_StatusMessage" />
|
<partial name="_StatusMessage" />
|
||||||
|
|
||||||
<h2>Welcome to your BTCPay Server</h2>
|
<h2>Welcome to @(string.IsNullOrWhiteSpace(settings.ServerName) ? "your BTCPay\u00a0Server" : settings.ServerName)</h2>
|
||||||
|
|
||||||
@if (!Model.HasStore)
|
@if (!Model.HasStore)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
@using BTCPayServer.Abstractions.Contracts
|
@using BTCPayServer.Abstractions.Contracts
|
||||||
@using BTCPayServer.Services
|
@using BTCPayServer.Services
|
||||||
@model BTCPayServer.Services.ThemeSettings
|
@model BrandingViewModel;
|
||||||
@inject IFileService FileService
|
@inject IFileService FileService
|
||||||
@{
|
@{
|
||||||
ViewData.SetActivePage(ServerNavPages.Theme, "Theme");
|
ViewData.SetActivePage(ServerNavPages.Branding, "Branding");
|
||||||
var canUpload = await FileService.IsAvailable();
|
var canUpload = await FileService.IsAvailable();
|
||||||
var themeExtension = ((ThemeExtension[])Enum.GetValues(typeof(ThemeExtension))).Select(t =>
|
var themeExtension = ((ThemeExtension[])Enum.GetValues(typeof(ThemeExtension))).Select(t =>
|
||||||
new SelectListItem(typeof(ThemeExtension).DisplayName(t.ToString()), t == ThemeExtension.Custom ? null : t.ToString()));
|
new SelectListItem(typeof(ThemeExtension).DisplayName(t.ToString()), t == ThemeExtension.Custom ? null : t.ToString()));
|
||||||
@@ -18,6 +18,51 @@
|
|||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-xl-8 col-xxl-constrain">
|
<div class="col-xl-8 col-xxl-constrain">
|
||||||
<form method="post" enctype="multipart/form-data">
|
<form method="post" enctype="multipart/form-data">
|
||||||
|
<div class="form-group">
|
||||||
|
<label asp-for="ServerName" class="form-label"></label>
|
||||||
|
<input asp-for="ServerName" class="form-control" />
|
||||||
|
<div class="form-text">You can give this server a custom name, which will appear on public facing pages.</div>
|
||||||
|
<span asp-validation-for="ServerName" class="text-danger"></span>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label asp-for="ContactUrl" class="form-label"></label>
|
||||||
|
<input asp-for="ContactUrl" class="form-control" />
|
||||||
|
<div class="form-text">
|
||||||
|
Contact link for support requests related to this BTCPay Server instance.
|
||||||
|
This link will appear on public facing pages.
|
||||||
|
Can be any valid URI, such as a website, email, and Nostr.
|
||||||
|
</div>
|
||||||
|
<span asp-validation-for="ContactUrl" class="text-danger"></span>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="d-flex align-items-center justify-content-between gap-2">
|
||||||
|
<label asp-for="LogoFile" class="form-label"></label>
|
||||||
|
@if (!string.IsNullOrEmpty(Model.LogoFileId))
|
||||||
|
{
|
||||||
|
<button type="submit" class="btn btn-link p-0 text-danger" name="RemoveLogoFile" value="true">
|
||||||
|
<span class="fa fa-times"></span> Remove
|
||||||
|
</button>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
@if (canUpload)
|
||||||
|
{
|
||||||
|
<div class="d-flex align-items-center gap-3">
|
||||||
|
<input asp-for="LogoFile" type="file" class="form-control flex-grow">
|
||||||
|
@if (!string.IsNullOrEmpty(Model.LogoFileId))
|
||||||
|
{
|
||||||
|
<img src="@(await FileService.GetFileUrl(Context.Request.GetAbsoluteRootUri(), Model.LogoFileId))" alt="Logo" style="height:2.1rem;max-width:10.5rem;"/>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
<span asp-validation-for="LogoFile" class="text-danger"></span>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<input asp-for="LogoFile" type="file" class="form-control" disabled>
|
||||||
|
<div class="form-text">In order to upload a logo, a <a asp-controller="UIServer" asp-action="Files">file storage</a> must be configured.</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h3 class="mt-5 mb-3">Theme</h3>
|
||||||
<p>Use the default Light or Dark Themes, or provide a custom CSS theme file below.</p>
|
<p>Use the default Light or Dark Themes, or provide a custom CSS theme file below.</p>
|
||||||
|
|
||||||
<div class="d-flex align-items-center mb-3">
|
<div class="d-flex align-items-center mb-3">
|
||||||
@@ -75,35 +120,6 @@
|
|||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h3 class="mt-5 mb-3">Branding</h3>
|
|
||||||
<div class="form-group">
|
|
||||||
<div class="d-flex align-items-center justify-content-between gap-2">
|
|
||||||
<label asp-for="LogoFile" class="form-label"></label>
|
|
||||||
@if (!string.IsNullOrEmpty(Model.LogoFileId))
|
|
||||||
{
|
|
||||||
<button type="submit" class="btn btn-link p-0 text-danger" name="RemoveLogoFile" value="true">
|
|
||||||
<span class="fa fa-times"></span> Remove
|
|
||||||
</button>
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
@if (canUpload)
|
|
||||||
{
|
|
||||||
<div class="d-flex align-items-center gap-3">
|
|
||||||
<input asp-for="LogoFile" type="file" class="form-control flex-grow">
|
|
||||||
@if (!string.IsNullOrEmpty(Model.LogoFileId))
|
|
||||||
{
|
|
||||||
<img src="@(await FileService.GetFileUrl(Context.Request.GetAbsoluteRootUri(), Model.LogoFileId))" alt="Logo" style="height:2.1rem;max-width:10.5rem;"/>
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
<span asp-validation-for="LogoFile" class="text-danger"></span>
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
<input asp-for="LogoFile" type="file" class="form-control" disabled>
|
|
||||||
<div class="form-text">In order to upload a logo, a <a asp-controller="UIServer" asp-action="Files">file storage</a> must be configured.</div>
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<button type="submit" class="btn btn-primary mt-2" name="command" value="Save">Save</button>
|
<button type="submit" class="btn btn-primary mt-2" name="command" value="Save">Save</button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
@@ -13,10 +13,8 @@
|
|||||||
<input asp-for="DNSDomain" class="form-control" disabled="@(Model.CanUseSSH ? null : "disabled")" />
|
<input asp-for="DNSDomain" class="form-control" disabled="@(Model.CanUseSSH ? null : "disabled")" />
|
||||||
<div class="form-text">You can change the domain name of your server by following <a href="https://docs.btcpayserver.org/FAQ/Deployment/#how-to-change-your-btcpay-server-domain-name" target="_blank" rel="noreferrer noopener">this guide</a>.</div>
|
<div class="form-text">You can change the domain name of your server by following <a href="https://docs.btcpayserver.org/FAQ/Deployment/#how-to-change-your-btcpay-server-domain-name" target="_blank" rel="noreferrer noopener">this guide</a>.</div>
|
||||||
<span asp-validation-for="DNSDomain" class="text-danger"></span>
|
<span asp-validation-for="DNSDomain" class="text-danger"></span>
|
||||||
<button name="command" type="submit" class="btn btn-secondary mt-3" value="changedomain" title="Change domain" disabled="@(Model.CanUseSSH ? null : "disabled")">
|
|
||||||
Confirm
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
|
<button name="command" type="submit" class="btn btn-secondary" value="changedomain" title="Change domain" disabled="@(Model.CanUseSSH ? null : "disabled")">Change Domain</button>
|
||||||
|
|
||||||
<h4 class="mt-5 mb-2">Restart</h4>
|
<h4 class="mt-5 mb-2">Restart</h4>
|
||||||
<p>Restart BTCPay Server and related services.</p>
|
<p>Restart BTCPay Server and related services.</p>
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ namespace BTCPayServer.Views.Server
|
|||||||
{
|
{
|
||||||
public enum ServerNavPages
|
public enum ServerNavPages
|
||||||
{
|
{
|
||||||
Index, Users, Emails, Policies, Theme, Services, Maintenance, Logs, Files, Plugins,
|
Index, Users, Emails, Policies, Branding, Services, Maintenance, Logs, Files, Plugins,
|
||||||
Roles
|
Roles
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
<a asp-controller="UIServer" id="SectionNav-@ServerNavPages.Emails" class="nav-link @ViewData.IsActivePage(ServerNavPages.Emails)" asp-action="Emails">Email</a>
|
<a asp-controller="UIServer" id="SectionNav-@ServerNavPages.Emails" class="nav-link @ViewData.IsActivePage(ServerNavPages.Emails)" asp-action="Emails">Email</a>
|
||||||
<a asp-controller="UIServer" id="SectionNav-@ServerNavPages.Policies" class="nav-link @ViewData.IsActivePage(ServerNavPages.Policies)" asp-action="Policies">Policies</a>
|
<a asp-controller="UIServer" id="SectionNav-@ServerNavPages.Policies" class="nav-link @ViewData.IsActivePage(ServerNavPages.Policies)" asp-action="Policies">Policies</a>
|
||||||
<a asp-controller="UIServer" id="SectionNav-@ServerNavPages.Services" class="nav-link @ViewData.IsActivePage(ServerNavPages.Services)" asp-action="Services">Services</a>
|
<a asp-controller="UIServer" id="SectionNav-@ServerNavPages.Services" class="nav-link @ViewData.IsActivePage(ServerNavPages.Services)" asp-action="Services">Services</a>
|
||||||
<a asp-controller="UIServer" id="SectionNav-@ServerNavPages.Theme" class="nav-link @ViewData.IsActivePage(ServerNavPages.Theme)" asp-action="Theme">Theme</a>
|
<a asp-controller="UIServer" id="SectionNav-@ServerNavPages.Branding" class="nav-link @ViewData.IsActivePage(ServerNavPages.Branding)" asp-action="Branding">Branding</a>
|
||||||
@if (_btcPayServerOptions.DockerDeployment)
|
@if (_btcPayServerOptions.DockerDeployment)
|
||||||
{
|
{
|
||||||
<a asp-controller="UIServer" id="SectionNav-@ServerNavPages.Maintenance" class="nav-link @ViewData.IsActivePage(ServerNavPages.Maintenance)" asp-action="Maintenance">Maintenance</a>
|
<a asp-controller="UIServer" id="SectionNav-@ServerNavPages.Maintenance" class="nav-link @ViewData.IsActivePage(ServerNavPages.Maintenance)" asp-action="Maintenance">Maintenance</a>
|
||||||
|
|||||||
@@ -29,8 +29,8 @@
|
|||||||
@section PageHeadContent {
|
@section PageHeadContent {
|
||||||
<style>
|
<style>
|
||||||
#FirstStore { max-width: 27rem; margin: 0 auto; text-align: center; }
|
#FirstStore { max-width: 27rem; margin: 0 auto; text-align: center; }
|
||||||
#FirstStore .main-logo { height: 4rem; width: 18rem; }
|
#FirstStore .main-logo { height: 4.5rem; max-width: 18rem; }
|
||||||
#FirstStore .main-logo.main-logo-btcpay { height: 4.5rem; width: 2.5rem; }
|
#FirstStore .main-logo.main-logo-btcpay { width: 2.5rem; }
|
||||||
#FirstStore .main-logo-btcpay .main-logo-btcpay--large { display: none; }
|
#FirstStore .main-logo-btcpay .main-logo-btcpay--large { display: none; }
|
||||||
#FirstStore .form-control, #FirstStore .form-select { width: 100%; }
|
#FirstStore .form-control, #FirstStore .form-select { width: 100%; }
|
||||||
#FirstStore .form-text { font-size: var(--btcpay-font-size-s); }
|
#FirstStore .form-text { font-size: var(--btcpay-font-size-s); }
|
||||||
|
|||||||
Reference in New Issue
Block a user