diff --git a/BTCPayServer.Tests/CheckoutUITests.cs b/BTCPayServer.Tests/CheckoutUITests.cs index a3620866b..96d315d3d 100644 --- a/BTCPayServer.Tests/CheckoutUITests.cs +++ b/BTCPayServer.Tests/CheckoutUITests.cs @@ -18,7 +18,7 @@ namespace BTCPayServer.Tests [Trait("Selenium", "Selenium")] public class CheckoutUITests { - public const int TestTimeout = 60_000; + public const int TestTimeout = TestUtils.TestTimeout; public CheckoutUITests(ITestOutputHelper helper) { Logs.Tester = new XUnitLog(helper) { Name = "Tests" }; @@ -32,6 +32,7 @@ namespace BTCPayServer.Tests using (var s = SeleniumTester.Create()) { await s.StartAsync(); + s.GoToRegister(); s.RegisterNewUser(); var store = s.CreateNewStore(); s.AddDerivationScheme("BTC"); @@ -80,6 +81,7 @@ namespace BTCPayServer.Tests using (var s = SeleniumTester.Create()) { await s.StartAsync(); + s.GoToRegister(); s.RegisterNewUser(); var store = s.CreateNewStore(); s.AddDerivationScheme("BTC"); @@ -109,6 +111,7 @@ namespace BTCPayServer.Tests using (var s = SeleniumTester.Create()) { await s.StartAsync(); + s.GoToRegister(); s.RegisterNewUser(); var store = s.CreateNewStore(); s.AddDerivationScheme("BTC"); @@ -152,6 +155,7 @@ namespace BTCPayServer.Tests using (var s = SeleniumTester.Create()) { await s.StartAsync(); + s.GoToRegister(); s.RegisterNewUser(); var store = s.CreateNewStore(); s.AddInternalLightningNode("BTC"); diff --git a/BTCPayServer.Tests/Extensions.cs b/BTCPayServer.Tests/Extensions.cs index 6d3c9a799..0f6d36b4e 100644 --- a/BTCPayServer.Tests/Extensions.cs +++ b/BTCPayServer.Tests/Extensions.cs @@ -28,8 +28,11 @@ namespace BTCPayServer.Tests try { Assert.NotEmpty(driver.FindElements(By.ClassName("navbar-brand"))); - foreach (var dangerAlert in driver.FindElements(By.ClassName("alert-danger"))) - Assert.False(dangerAlert.Displayed, "No alert should be displayed"); + if (driver.PageSource.Contains("alert-danger")) + { + foreach (var dangerAlert in driver.FindElements(By.ClassName("alert-danger"))) + Assert.False(dangerAlert.Displayed, "No alert should be displayed"); + } } catch { diff --git a/BTCPayServer.Tests/SeleniumTester.cs b/BTCPayServer.Tests/SeleniumTester.cs index 170d2082a..5900ad77a 100644 --- a/BTCPayServer.Tests/SeleniumTester.cs +++ b/BTCPayServer.Tests/SeleniumTester.cs @@ -66,7 +66,7 @@ namespace BTCPayServer.Tests Logs.Tester.LogInformation("Selenium: Browsing to " + Server.PayTester.ServerUri); Logs.Tester.LogInformation($"Selenium: Resolution {Driver.Manage().Window.Size}"); Driver.Manage().Timeouts().ImplicitWait = ImplicitWait; - Driver.Navigate().GoToUrl(Server.PayTester.ServerUri); + GoToRegister(); Driver.AssertNoError(); } @@ -76,10 +76,13 @@ namespace BTCPayServer.Tests return Server.PayTester.ServerUri.AbsoluteUri.WithoutEndingSlash() + relativeLink.WithStartingSlash(); } + public void GoToRegister() + { + Driver.Navigate().GoToUrl(this.Link("/Account/Register")); + } public string RegisterNewUser(bool isAdmin = false) { var usr = RandomUtils.GetUInt256().ToString().Substring(64 - 20) + "@a.com"; - Driver.FindElement(By.Id("Register")).Click(); Driver.FindElement(By.Id("Email")).SendKeys(usr); Driver.FindElement(By.Id("Password")).SendKeys("123456"); Driver.FindElement(By.Id("ConfirmPassword")).SendKeys("123456"); diff --git a/BTCPayServer.Tests/SeleniumTests.cs b/BTCPayServer.Tests/SeleniumTests.cs index f1655a977..a109dff42 100644 --- a/BTCPayServer.Tests/SeleniumTests.cs +++ b/BTCPayServer.Tests/SeleniumTests.cs @@ -46,8 +46,7 @@ namespace BTCPayServer.Tests var email = s.RegisterNewUser(); s.Driver.FindElement(By.Id("Logout")).Click(); s.Driver.AssertNoError(); - s.Driver.FindElement(By.Id("Login")).Click(); - s.Driver.AssertNoError(); + Assert.Contains("Account/Login", s.Driver.Url); s.Driver.Navigate().GoToUrl(s.Link("/invoices")); Assert.Contains("ReturnUrl=%2Finvoices", s.Driver.Url); @@ -76,7 +75,6 @@ namespace BTCPayServer.Tests s.Driver.AssertNoError(); //Log In With New Password - s.Driver.FindElement(By.Id("Login")).Click(); s.Driver.FindElement(By.Id("Email")).SendKeys(email); s.Driver.FindElement(By.Id("Password")).SendKeys("abc???"); s.Driver.FindElement(By.Id("LoginButton")).Click(); @@ -91,7 +89,6 @@ namespace BTCPayServer.Tests static void LogIn(SeleniumTester s, string email) { - s.Driver.FindElement(By.Id("Login")).Click(); s.Driver.FindElement(By.Id("Email")).SendKeys(email); s.Driver.FindElement(By.Id("Password")).SendKeys("123456"); s.Driver.FindElement(By.Id("LoginButton")).Click(); @@ -208,7 +205,7 @@ namespace BTCPayServer.Tests Assert.Contains("ReturnUrl", s.Driver.Url); s.Driver.Navigate().GoToUrl(invoiceUrl); Assert.Contains("ReturnUrl", s.Driver.Url); - s.Driver.Navigate().GoToUrl(s.Link("/")); + s.GoToRegister(); // When logged we should not be able to access store and invoice details var bob = s.RegisterNewUser(); s.Driver.Navigate().GoToUrl(storeUrl); @@ -252,7 +249,7 @@ namespace BTCPayServer.Tests await s.StartAsync(); s.Driver.Navigate().GoToUrl(s.Link("/api-access-request")); Assert.Contains("ReturnUrl", s.Driver.Url); - s.Driver.Navigate().GoToUrl(s.Link("/")); + s.GoToRegister(); var alice = s.RegisterNewUser(); var store = s.CreateNewStore().storeName; s.AddDerivationScheme(); diff --git a/BTCPayServer/Controllers/AccountController.cs b/BTCPayServer/Controllers/AccountController.cs index 6f2115849..4cd84d90f 100644 --- a/BTCPayServer/Controllers/AccountController.cs +++ b/BTCPayServer/Controllers/AccountController.cs @@ -398,7 +398,9 @@ namespace BTCPayServer.Controllers { await _RoleManager.CreateAsync(new IdentityRole(Roles.ServerAdmin)); await _userManager.AddToRoleAsync(user, Roles.ServerAdmin); - + var settings = await _SettingsRepository.GetSettingAsync(); + settings.FirstRun = false; + await _SettingsRepository.UpdateSetting(settings); if(_Options.DisableRegistration) { // Once the admin user has been created lock subsequent user registrations (needs to be disabled for unit tests that require multiple users). diff --git a/BTCPayServer/Controllers/HomeController.cs b/BTCPayServer/Controllers/HomeController.cs index 858416fc9..5363081e1 100644 --- a/BTCPayServer/Controllers/HomeController.cs +++ b/BTCPayServer/Controllers/HomeController.cs @@ -12,6 +12,8 @@ using Newtonsoft.Json; using BTCPayServer.Services; using BTCPayServer.HostedServices; using BTCPayServer.Services.Apps; +using Microsoft.AspNetCore.Identity; +using BTCPayServer.Data; namespace BTCPayServer.Controllers { @@ -20,11 +22,15 @@ namespace BTCPayServer.Controllers private readonly CssThemeManager _cachedServerSettings; public IHttpClientFactory HttpClientFactory { get; } + SignInManager SignInManager { get; } - public HomeController(IHttpClientFactory httpClientFactory, CssThemeManager cachedServerSettings) + public HomeController(IHttpClientFactory httpClientFactory, + CssThemeManager cachedServerSettings, + SignInManager signInManager) { HttpClientFactory = httpClientFactory; _cachedServerSettings = cachedServerSettings; + SignInManager = signInManager; } private async Task GoToApp(string appId, AppType? appType) @@ -71,14 +77,26 @@ namespace BTCPayServer.Controllers public async Task Index() { + if (_cachedServerSettings.FirstRun) + { + return RedirectToAction(nameof(AccountController.Register), "Account"); + } var matchedDomainMapping = _cachedServerSettings.DomainToAppMapping.FirstOrDefault(item => item.Domain.Equals(Request.Host.Host, StringComparison.InvariantCultureIgnoreCase)); if (matchedDomainMapping != null) { - return await GoToApp(matchedDomainMapping.AppId, matchedDomainMapping.AppType) ?? View("Home"); + return await GoToApp(matchedDomainMapping.AppId, matchedDomainMapping.AppType) ?? GoToHome(); } - return await GoToApp(_cachedServerSettings.RootAppId, _cachedServerSettings.RootAppType) ?? View("Home"); + return await GoToApp(_cachedServerSettings.RootAppId, _cachedServerSettings.RootAppType) ?? GoToHome(); + } + + private IActionResult GoToHome() + { + if (SignInManager.IsSignedIn(User)) + return View("Home"); + else + return RedirectToAction(nameof(AccountController.Login), "Account"); } [Route("translate")] diff --git a/BTCPayServer/HostedServices/CssThemeManager.cs b/BTCPayServer/HostedServices/CssThemeManager.cs index 51aa391dc..7545d1c53 100644 --- a/BTCPayServer/HostedServices/CssThemeManager.cs +++ b/BTCPayServer/HostedServices/CssThemeManager.cs @@ -31,6 +31,7 @@ namespace BTCPayServer.HostedServices _creativeStartUri = "/vendor/bootstrap4-creativestart/creative.css?v=" + DateTime.Now.Ticks; else _creativeStartUri = data.CreativeStartCssUri; + FirstRun = data.FirstRun; } private string _bootstrapUri; @@ -52,6 +53,8 @@ namespace BTCPayServer.HostedServices public AppType? RootAppType { get; set; } public string RootAppId { get; set; } + public bool FirstRun { get; set; } + public List DomainToAppMapping { get; set; } = new List(); internal void Update(PoliciesSettings data) diff --git a/BTCPayServer/MigrationStartupTask.cs b/BTCPayServer/MigrationStartupTask.cs index 076100cc8..3e4cb1aaf 100644 --- a/BTCPayServer/MigrationStartupTask.cs +++ b/BTCPayServer/MigrationStartupTask.cs @@ -10,6 +10,7 @@ using BTCPayServer.Services.Stores; using BTCPayServer.Logging; using System.Threading; using Npgsql; +using Microsoft.AspNetCore.Identity; namespace BTCPayServer { @@ -19,16 +20,19 @@ namespace BTCPayServer private StoreRepository _StoreRepository; private BTCPayNetworkProvider _NetworkProvider; private SettingsRepository _Settings; + private readonly UserManager _userManager; public MigrationStartupTask( BTCPayNetworkProvider networkProvider, StoreRepository storeRepository, ApplicationDbContextFactory dbContextFactory, + UserManager userManager, SettingsRepository settingsRepository) { _DBContextFactory = dbContextFactory; _StoreRepository = storeRepository; _NetworkProvider = networkProvider; _Settings = settingsRepository; + _userManager = userManager; } public async Task ExecuteAsync(CancellationToken cancellationToken = default) { @@ -72,6 +76,15 @@ namespace BTCPayServer settings.ConvertWalletKeyPathRoots = true; await _Settings.UpdateSetting(settings); } + if (!settings.CheckedFirstRun) + { + var themeSettings = await _Settings.GetSettingAsync() ?? new ThemeSettings(); + var admin = await _userManager.GetUsersInRoleAsync(Roles.ServerAdmin); + themeSettings.FirstRun = admin.Count == 0; + await _Settings.UpdateSetting(themeSettings); + settings.CheckedFirstRun = true; + await _Settings.UpdateSetting(settings); + } } catch (Exception ex) { diff --git a/BTCPayServer/Services/MigrationSettings.cs b/BTCPayServer/Services/MigrationSettings.cs index 671a53a03..56266662d 100644 --- a/BTCPayServer/Services/MigrationSettings.cs +++ b/BTCPayServer/Services/MigrationSettings.cs @@ -13,6 +13,7 @@ namespace BTCPayServer.Services public bool ConvertNetworkFeeProperty { get; set; } public bool ConvertCrowdfundOldSettings { get; set; } public bool ConvertWalletKeyPathRoots { get; set; } + public bool CheckedFirstRun { get; set; } public override string ToString() { return string.Empty; diff --git a/BTCPayServer/Services/ThemesSettings.cs b/BTCPayServer/Services/ThemesSettings.cs index 2912ec31c..c27e2e3bd 100644 --- a/BTCPayServer/Services/ThemesSettings.cs +++ b/BTCPayServer/Services/ThemesSettings.cs @@ -16,5 +16,11 @@ namespace BTCPayServer.Services [JsonProperty(DefaultValueHandling = DefaultValueHandling.Populate)] public string CreativeStartCssUri { get; set; } + public bool FirstRun { get; set; } + public override string ToString() + { + // no logs + return string.Empty; + } } }