From b665099657bd2fa9f6ec6da9328fb540ca35fc09 Mon Sep 17 00:00:00 2001 From: Andy Butland Date: Thu, 23 Mar 2023 08:59:28 +0100 Subject: [PATCH 01/13] Updated reference for JSON schema to latest release of Forms 10. (#13996) --- src/JsonSchema/JsonSchema.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/JsonSchema/JsonSchema.csproj b/src/JsonSchema/JsonSchema.csproj index 901f89e8b2..3d31dd265d 100644 --- a/src/JsonSchema/JsonSchema.csproj +++ b/src/JsonSchema/JsonSchema.csproj @@ -13,6 +13,6 @@ - + From 5598cc2491f32ca6329d2c1e7641b55cef09eb8f Mon Sep 17 00:00:00 2001 From: Nikolaj Date: Thu, 23 Mar 2023 09:20:20 +0100 Subject: [PATCH 02/13] Convert path to absolute --- .../PropertyEditors/RichTextEditorPastedImages.cs | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/Umbraco.Infrastructure/PropertyEditors/RichTextEditorPastedImages.cs b/src/Umbraco.Infrastructure/PropertyEditors/RichTextEditorPastedImages.cs index 569f38139d..5044a5b13e 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/RichTextEditorPastedImages.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/RichTextEditorPastedImages.cs @@ -29,6 +29,7 @@ public sealed class RichTextEditorPastedImages private readonly IPublishedUrlProvider _publishedUrlProvider; private readonly IShortStringHelper _shortStringHelper; private readonly IUmbracoContextAccessor _umbracoContextAccessor; + private readonly string _tempFolderAbsolutePath; public RichTextEditorPastedImages( IUmbracoContextAccessor umbracoContextAccessor, @@ -52,6 +53,9 @@ public sealed class RichTextEditorPastedImages _mediaUrlGenerators = mediaUrlGenerators; _shortStringHelper = shortStringHelper; _publishedUrlProvider = publishedUrlProvider; + + _tempFolderAbsolutePath = _hostingEnvironment.MapPathContentRoot(Constants.SystemDirectories.TempImageUploads); + } /// @@ -85,12 +89,14 @@ public sealed class RichTextEditorPastedImages continue; } - if (IsValidPath(tmpImgPath) == false) + + var absoluteTempImagePath = Path.GetFullPath(_hostingEnvironment.MapPathContentRoot(tmpImgPath)); + + if (IsValidPath(absoluteTempImagePath) == false) { continue; } - var absoluteTempImagePath = _hostingEnvironment.MapPathContentRoot(tmpImgPath); var fileName = Path.GetFileName(absoluteTempImagePath); var safeFileName = fileName.ToSafeFileName(_shortStringHelper); @@ -191,5 +197,8 @@ public sealed class RichTextEditorPastedImages return htmlDoc.DocumentNode.OuterHtml; } - private bool IsValidPath(string imagePath) => imagePath.StartsWith(Constants.SystemDirectories.TempImageUploads); + private bool IsValidPath(string imagePath) + { + return imagePath.StartsWith(_tempFolderAbsolutePath); + } } From 1ece9627f73e5ba8e5b4a562a19183e94f2c594b Mon Sep 17 00:00:00 2001 From: Nikolaj Date: Thu, 23 Mar 2023 09:20:20 +0100 Subject: [PATCH 03/13] Convert path to absolute --- .../PropertyEditors/RichTextEditorPastedImages.cs | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/Umbraco.Infrastructure/PropertyEditors/RichTextEditorPastedImages.cs b/src/Umbraco.Infrastructure/PropertyEditors/RichTextEditorPastedImages.cs index 569f38139d..5044a5b13e 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/RichTextEditorPastedImages.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/RichTextEditorPastedImages.cs @@ -29,6 +29,7 @@ public sealed class RichTextEditorPastedImages private readonly IPublishedUrlProvider _publishedUrlProvider; private readonly IShortStringHelper _shortStringHelper; private readonly IUmbracoContextAccessor _umbracoContextAccessor; + private readonly string _tempFolderAbsolutePath; public RichTextEditorPastedImages( IUmbracoContextAccessor umbracoContextAccessor, @@ -52,6 +53,9 @@ public sealed class RichTextEditorPastedImages _mediaUrlGenerators = mediaUrlGenerators; _shortStringHelper = shortStringHelper; _publishedUrlProvider = publishedUrlProvider; + + _tempFolderAbsolutePath = _hostingEnvironment.MapPathContentRoot(Constants.SystemDirectories.TempImageUploads); + } /// @@ -85,12 +89,14 @@ public sealed class RichTextEditorPastedImages continue; } - if (IsValidPath(tmpImgPath) == false) + + var absoluteTempImagePath = Path.GetFullPath(_hostingEnvironment.MapPathContentRoot(tmpImgPath)); + + if (IsValidPath(absoluteTempImagePath) == false) { continue; } - var absoluteTempImagePath = _hostingEnvironment.MapPathContentRoot(tmpImgPath); var fileName = Path.GetFileName(absoluteTempImagePath); var safeFileName = fileName.ToSafeFileName(_shortStringHelper); @@ -191,5 +197,8 @@ public sealed class RichTextEditorPastedImages return htmlDoc.DocumentNode.OuterHtml; } - private bool IsValidPath(string imagePath) => imagePath.StartsWith(Constants.SystemDirectories.TempImageUploads); + private bool IsValidPath(string imagePath) + { + return imagePath.StartsWith(_tempFolderAbsolutePath); + } } From b8899459dc7fd50f167ac1516c7a05553eb1ea45 Mon Sep 17 00:00:00 2001 From: Bjarke Berg Date: Thu, 30 Mar 2023 10:19:35 +0200 Subject: [PATCH 04/13] Determine correct if we can create a database with current connectionstring (#14030) * Fix CanForceCreateDatabase method and add some unit tests * Fixed an old copy/paste error * A little nitpicking over wording and formatting --------- Co-authored-by: kjac --- .../Constants.cs | 4 +- .../SqlAzureDatabaseProviderMetadata.cs | 20 ++++++++++ .../SqlLocalDbDatabaseProviderMetadata.cs | 21 +++++++++++ .../SqlServerDatabaseProviderMetadata.cs | 23 ++++++++++++ .../SqliteDatabaseProviderMetadata.cs | 20 ++++++++++ .../Install/InstallHelper.cs | 2 +- .../DatabaseProviderMetadataExtensions.cs | 27 +++++++++++++- .../Persistence/IDatabaseProviderMetadata.cs | 6 +++ .../Runtime/RuntimeState.cs | 2 +- .../SqAzureDatabaseProviderMetadataTests.cs | 37 +++++++++++++++++++ ...SqlLocalDbDatabaseProviderMetadataTests.cs | 37 +++++++++++++++++++ .../SqlServerDatabaseProviderMetadataTests.cs | 37 +++++++++++++++++++ .../SqliteDatabaseProviderMetadataTests.cs | 37 +++++++++++++++++++ .../Factories/DatabaseSettingsFactoryTests.cs | 2 + .../Umbraco.Tests.UnitTests.csproj | 1 + 15 files changed, 271 insertions(+), 5 deletions(-) create mode 100644 tests/Umbraco.Tests.UnitTests/Umbraco.Cms.Persistence.SqlServer/SqAzureDatabaseProviderMetadataTests.cs create mode 100644 tests/Umbraco.Tests.UnitTests/Umbraco.Cms.Persistence.SqlServer/SqlLocalDbDatabaseProviderMetadataTests.cs create mode 100644 tests/Umbraco.Tests.UnitTests/Umbraco.Cms.Persistence.SqlServer/SqlServerDatabaseProviderMetadataTests.cs create mode 100644 tests/Umbraco.Tests.UnitTests/Umbraco.Cms.Persistence.Sqlite/SqliteDatabaseProviderMetadataTests.cs diff --git a/src/Umbraco.Cms.Persistence.SqlServer/Constants.cs b/src/Umbraco.Cms.Persistence.SqlServer/Constants.cs index ae16a9735f..6b5099b314 100644 --- a/src/Umbraco.Cms.Persistence.SqlServer/Constants.cs +++ b/src/Umbraco.Cms.Persistence.SqlServer/Constants.cs @@ -1,12 +1,12 @@ namespace Umbraco.Cms.Persistence.SqlServer; /// -/// Constants related to SQLite. +/// Constants related to SQL Server. /// public static class Constants { /// - /// SQLite provider name. + /// SQL Server provider name. /// public const string ProviderName = "Microsoft.Data.SqlClient"; } diff --git a/src/Umbraco.Cms.Persistence.SqlServer/Services/SqlAzureDatabaseProviderMetadata.cs b/src/Umbraco.Cms.Persistence.SqlServer/Services/SqlAzureDatabaseProviderMetadata.cs index 112d556712..95dda5fe7b 100644 --- a/src/Umbraco.Cms.Persistence.SqlServer/Services/SqlAzureDatabaseProviderMetadata.cs +++ b/src/Umbraco.Cms.Persistence.SqlServer/Services/SqlAzureDatabaseProviderMetadata.cs @@ -1,4 +1,5 @@ using System.Runtime.Serialization; +using Microsoft.Data.SqlClient; using Umbraco.Cms.Core.Install.Models; using Umbraco.Cms.Infrastructure.Persistence; using Umbraco.Extensions; @@ -50,6 +51,25 @@ public class SqlAzureDatabaseProviderMetadata : IDatabaseProviderMetadata /// public bool ForceCreateDatabase => false; + /// + public bool CanRecognizeConnectionString(string? connectionString) + { + if (connectionString is null) + { + return false; + } + + try + { + var builder = new SqlConnectionStringBuilder(connectionString); + + return string.IsNullOrEmpty(builder.AttachDBFilename) && builder.DataSource.Contains("database.windows.net"); + } + catch (ArgumentException) + { + return false; + } + } /// public string GenerateConnectionString(DatabaseModel databaseModel) { diff --git a/src/Umbraco.Cms.Persistence.SqlServer/Services/SqlLocalDbDatabaseProviderMetadata.cs b/src/Umbraco.Cms.Persistence.SqlServer/Services/SqlLocalDbDatabaseProviderMetadata.cs index 30a503e5f9..589ef5a623 100644 --- a/src/Umbraco.Cms.Persistence.SqlServer/Services/SqlLocalDbDatabaseProviderMetadata.cs +++ b/src/Umbraco.Cms.Persistence.SqlServer/Services/SqlLocalDbDatabaseProviderMetadata.cs @@ -51,6 +51,27 @@ public class SqlLocalDbDatabaseProviderMetadata : IDatabaseProviderMetadata /// public bool ForceCreateDatabase => true; + /// + public bool CanRecognizeConnectionString(string? connectionString) + { + if (connectionString is null) + { + return false; + } + + try + { + var builder = new SqlConnectionStringBuilder(connectionString); + + return !string.IsNullOrEmpty(builder.AttachDBFilename); + + } + catch (ArgumentException) + { + return false; + } + } + /// public string GenerateConnectionString(DatabaseModel databaseModel) { diff --git a/src/Umbraco.Cms.Persistence.SqlServer/Services/SqlServerDatabaseProviderMetadata.cs b/src/Umbraco.Cms.Persistence.SqlServer/Services/SqlServerDatabaseProviderMetadata.cs index 8b36736804..edb44700d8 100644 --- a/src/Umbraco.Cms.Persistence.SqlServer/Services/SqlServerDatabaseProviderMetadata.cs +++ b/src/Umbraco.Cms.Persistence.SqlServer/Services/SqlServerDatabaseProviderMetadata.cs @@ -1,6 +1,9 @@ +using System.Data.Common; using System.Runtime.Serialization; +using Microsoft.Data.SqlClient; using Umbraco.Cms.Core.Install.Models; using Umbraco.Cms.Infrastructure.Persistence; +using Umbraco.Extensions; namespace Umbraco.Cms.Persistence.SqlServer.Services; @@ -49,6 +52,26 @@ public class SqlServerDatabaseProviderMetadata : IDatabaseProviderMetadata /// public bool ForceCreateDatabase => false; + /// + public bool CanRecognizeConnectionString(string? connectionString) + { + if (connectionString is null) + { + return false; + } + + try + { + var builder = new SqlConnectionStringBuilder(connectionString); + + return string.IsNullOrEmpty(builder.AttachDBFilename); + } + catch (ArgumentException) + { + return false; + } + } + /// public string GenerateConnectionString(DatabaseModel databaseModel) => databaseModel.IntegratedAuth diff --git a/src/Umbraco.Cms.Persistence.Sqlite/Services/SqliteDatabaseProviderMetadata.cs b/src/Umbraco.Cms.Persistence.Sqlite/Services/SqliteDatabaseProviderMetadata.cs index 54a7a5cb1d..d087acc8cb 100644 --- a/src/Umbraco.Cms.Persistence.Sqlite/Services/SqliteDatabaseProviderMetadata.cs +++ b/src/Umbraco.Cms.Persistence.Sqlite/Services/SqliteDatabaseProviderMetadata.cs @@ -56,6 +56,26 @@ public class SqliteDatabaseProviderMetadata : IDatabaseProviderMetadata /// public bool ForceCreateDatabase => true; + /// + public bool CanRecognizeConnectionString(string? connectionString) + { + if (connectionString is null) + { + return false; + } + + try + { + var builder = new SqliteConnectionStringBuilder(connectionString); + + return !string.IsNullOrEmpty(builder.DataSource); + + } + catch (ArgumentException) + { + return false; + } + } /// public string GenerateConnectionString(DatabaseModel databaseModel) { diff --git a/src/Umbraco.Infrastructure/Install/InstallHelper.cs b/src/Umbraco.Infrastructure/Install/InstallHelper.cs index 4686625895..82d4905f12 100644 --- a/src/Umbraco.Infrastructure/Install/InstallHelper.cs +++ b/src/Umbraco.Infrastructure/Install/InstallHelper.cs @@ -164,7 +164,7 @@ namespace Umbraco.Cms.Infrastructure.Install private bool IsBrandNewInstall => _connectionStrings.CurrentValue.IsConnectionStringConfigured() == false || _databaseBuilder.IsDatabaseConfigured == false || - (_databaseBuilder.CanConnectToDatabase == false && _databaseProviderMetadata.CanForceCreateDatabase(_umbracoDatabaseFactory.SqlContext.SqlSyntax.DbProvider)) || + (_databaseBuilder.CanConnectToDatabase == false && _databaseProviderMetadata.CanForceCreateDatabase(_umbracoDatabaseFactory)) || _databaseBuilder.IsUmbracoInstalled() == false; } } diff --git a/src/Umbraco.Infrastructure/Persistence/DatabaseProviderMetadataExtensions.cs b/src/Umbraco.Infrastructure/Persistence/DatabaseProviderMetadataExtensions.cs index 1ea941932e..09c0a121dc 100644 --- a/src/Umbraco.Infrastructure/Persistence/DatabaseProviderMetadataExtensions.cs +++ b/src/Umbraco.Infrastructure/Persistence/DatabaseProviderMetadataExtensions.cs @@ -1,4 +1,5 @@ using Umbraco.Cms.Core.Install.Models; +using Umbraco.Cms.Infrastructure.Persistence.SqlSyntax; namespace Umbraco.Cms.Infrastructure.Persistence; @@ -26,8 +27,32 @@ public static class DatabaseProviderMetadataExtensions /// /// true if a database can be created for the specified provider name; otherwise, false. /// + [Obsolete("Use CanForceCreateDatabase that takes an IUmbracoDatabaseFactory. Scheduled for removal in Umbraco 13.")] public static bool CanForceCreateDatabase(this IEnumerable databaseProviderMetadata, string? providerName) - => databaseProviderMetadata.FirstOrDefault(x => string.Equals(x.ProviderName, providerName, StringComparison.InvariantCultureIgnoreCase))?.ForceCreateDatabase == true; + { + return databaseProviderMetadata + .FirstOrDefault(x => + string.Equals(x.ProviderName, providerName, StringComparison.InvariantCultureIgnoreCase)) + ?.ForceCreateDatabase == true; + } + + /// + /// Determines whether a database can be created for the specified provider name while ignoring the value of . + /// + /// The database provider metadata. + /// The database factory. + /// + /// true if a database can be created for the specified database; otherwise, false. + /// + public static bool CanForceCreateDatabase(this IEnumerable databaseProviderMetadata, IUmbracoDatabaseFactory umbracoDatabaseFactory) + { + // In case more metadata providers can recognize the connection string, we need to check if any can force create. + // E.g. Both SqlServer and SqlAzure will recognize an azure connection string, but luckily none of those can force create. + return databaseProviderMetadata + .Where(x => + string.Equals(x.ProviderName, umbracoDatabaseFactory.SqlContext.SqlSyntax.ProviderName, StringComparison.InvariantCultureIgnoreCase) + && x.CanRecognizeConnectionString(umbracoDatabaseFactory.ConnectionString) && x.IsAvailable).Any(x => x.ForceCreateDatabase == true); + } /// /// Generates the connection string. diff --git a/src/Umbraco.Infrastructure/Persistence/IDatabaseProviderMetadata.cs b/src/Umbraco.Infrastructure/Persistence/IDatabaseProviderMetadata.cs index 1c06dd089f..55a7c3a686 100644 --- a/src/Umbraco.Infrastructure/Persistence/IDatabaseProviderMetadata.cs +++ b/src/Umbraco.Infrastructure/Persistence/IDatabaseProviderMetadata.cs @@ -82,6 +82,12 @@ public interface IDatabaseProviderMetadata /// public bool ForceCreateDatabase { get; } + + /// + /// Gets a value indicating whether this connections could have been build using . + /// + public bool CanRecognizeConnectionString(string? connectionString) => false; + /// /// Creates a connection string for this provider. /// diff --git a/src/Umbraco.Infrastructure/Runtime/RuntimeState.cs b/src/Umbraco.Infrastructure/Runtime/RuntimeState.cs index f0679aa470..6597fadf61 100644 --- a/src/Umbraco.Infrastructure/Runtime/RuntimeState.cs +++ b/src/Umbraco.Infrastructure/Runtime/RuntimeState.cs @@ -209,7 +209,7 @@ public class RuntimeState : IRuntimeState // cannot connect to configured database, this is bad, fail _logger.LogDebug("Could not connect to database."); - if (_globalSettings.Value.InstallMissingDatabase || _databaseProviderMetadata.CanForceCreateDatabase(_databaseFactory.ProviderName)) + if (_globalSettings.Value.InstallMissingDatabase || _databaseProviderMetadata.CanForceCreateDatabase(_databaseFactory)) { // ok to install on a configured but missing database Level = RuntimeLevel.Install; diff --git a/tests/Umbraco.Tests.UnitTests/Umbraco.Cms.Persistence.SqlServer/SqAzureDatabaseProviderMetadataTests.cs b/tests/Umbraco.Tests.UnitTests/Umbraco.Cms.Persistence.SqlServer/SqAzureDatabaseProviderMetadataTests.cs new file mode 100644 index 0000000000..e945eeae07 --- /dev/null +++ b/tests/Umbraco.Tests.UnitTests/Umbraco.Cms.Persistence.SqlServer/SqAzureDatabaseProviderMetadataTests.cs @@ -0,0 +1,37 @@ +using NUnit.Framework; +using Umbraco.Cms.Core.Install.Models; +using Umbraco.Cms.Persistence.SqlServer.Services; + +namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Cms.Persistence.SqlServer; + +[TestFixture] +public class SqlAzureDatabaseProviderMetadataTests +{ + [Test] + [TestCase("myServer", "myDatabase", "myLogin", "myPassword", true /*ignored*/, ExpectedResult = "Server=tcp:myServer.database.windows.net,1433;Database=myDatabase;User ID=myLogin@myServer;Password=myPassword")] + [TestCase("myServer", "myDatabase", "myLogin", "myPassword", false, ExpectedResult = "Server=tcp:myServer.database.windows.net,1433;Database=myDatabase;User ID=myLogin@myServer;Password=myPassword")] + public string GenerateConnectionString(string server, string databaseName, string login, string password, bool integratedAuth) + { + var sut = new SqlAzureDatabaseProviderMetadata(); + return sut.GenerateConnectionString(new DatabaseModel() + { + DatabaseName = databaseName, + Login = login, + Password = password, + Server = server, + IntegratedAuth = integratedAuth + }); + } + + [Test] + [TestCase("Server=myServer;Database=myDatabase;Integrated Security=true", ExpectedResult = false)] // SqlServer + [TestCase("Server=myServer;Database=myDatabase;User Id=myLogin;Password=myPassword", ExpectedResult = false)] // SqlServer + [TestCase("Server=tcp:cmstest27032000.database.windows.net,1433;Database=test_27032000;User ID=asdasdas@cmstest27032000;Password=123456879", ExpectedResult = true)] // Azure + [TestCase("Data Source=|DataDirectory|/Umbraco.sqlite.db;Cache=Shared;Foreign Keys=True;Pooling=True", ExpectedResult = false)] // Sqlite + [TestCase("Data Source=(LocalDb)\\MSSQLLocalDB;Initial Catalog=aspnet-MvcMovie;Integrated Security=SSPI;AttachDBFilename=|DataDirectory|\\umbraco.mdf", ExpectedResult = false)] // localDB + public bool CanRecognizeConnectionString(string connectionString) + { + var sut = new SqlAzureDatabaseProviderMetadata(); + return sut.CanRecognizeConnectionString(connectionString); + } +} diff --git a/tests/Umbraco.Tests.UnitTests/Umbraco.Cms.Persistence.SqlServer/SqlLocalDbDatabaseProviderMetadataTests.cs b/tests/Umbraco.Tests.UnitTests/Umbraco.Cms.Persistence.SqlServer/SqlLocalDbDatabaseProviderMetadataTests.cs new file mode 100644 index 0000000000..24728a6c3e --- /dev/null +++ b/tests/Umbraco.Tests.UnitTests/Umbraco.Cms.Persistence.SqlServer/SqlLocalDbDatabaseProviderMetadataTests.cs @@ -0,0 +1,37 @@ +using NUnit.Framework; +using Umbraco.Cms.Core.Install.Models; +using Umbraco.Cms.Persistence.SqlServer.Services; + +namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Cms.Persistence.SqlServer; + +[TestFixture] +public class SqlLocalDbDatabaseProviderMetadataTests +{ + [Test] + [TestCase("ignored", "myDatabase", "ignored", "ignored", true, ExpectedResult = "Data Source=(localdb)\\MSSQLLocalDB;AttachDbFilename=|DataDirectory|\\myDatabase.mdf;Integrated Security=True")] + [TestCase("ignored", "myDatabase2", "ignored", "ignored", false /*ignored*/, ExpectedResult = "Data Source=(localdb)\\MSSQLLocalDB;AttachDbFilename=|DataDirectory|\\myDatabase2.mdf;Integrated Security=True")] + public string GenerateConnectionString(string server, string databaseName, string login, string password, bool integratedAuth) + { + var sut = new SqlLocalDbDatabaseProviderMetadata(); + return sut.GenerateConnectionString(new DatabaseModel() + { + DatabaseName = databaseName, + Login = login, + Password = password, + Server = server, + IntegratedAuth = integratedAuth, + }); + } + + [Test] + [TestCase("Server=myServer;Database=myDatabase;Integrated Security=true", ExpectedResult = false)] // SqlServer + [TestCase("Server=myServer;Database=myDatabase;User Id=myLogin;Password=myPassword", ExpectedResult = false)] // SqlServer + [TestCase("Server=tcp:cmstest27032000.database.windows.net,1433;Database=test_27032000;User ID=asdasdas@cmstest27032000;Password=123456879", ExpectedResult = false)] // Azure + [TestCase("Data Source=|DataDirectory|/Umbraco.sqlite.db;Cache=Shared;Foreign Keys=True;Pooling=True", ExpectedResult = false)] // Sqlite + [TestCase("Data Source=(LocalDb)\\MSSQLLocalDB;Initial Catalog=aspnet-MvcMovie;Integrated Security=SSPI;AttachDBFilename=|DataDirectory|\\umbraco.mdf", ExpectedResult = true)] // localDB + public bool CanRecognizeConnectionString(string connectionString) + { + var sut = new SqlLocalDbDatabaseProviderMetadata(); + return sut.CanRecognizeConnectionString(connectionString); + } +} diff --git a/tests/Umbraco.Tests.UnitTests/Umbraco.Cms.Persistence.SqlServer/SqlServerDatabaseProviderMetadataTests.cs b/tests/Umbraco.Tests.UnitTests/Umbraco.Cms.Persistence.SqlServer/SqlServerDatabaseProviderMetadataTests.cs new file mode 100644 index 0000000000..4e96c375e1 --- /dev/null +++ b/tests/Umbraco.Tests.UnitTests/Umbraco.Cms.Persistence.SqlServer/SqlServerDatabaseProviderMetadataTests.cs @@ -0,0 +1,37 @@ +using NUnit.Framework; +using Umbraco.Cms.Core.Install.Models; +using Umbraco.Cms.Persistence.SqlServer.Services; + +namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Cms.Persistence.SqlServer; + +[TestFixture] +public class SqlServerDatabaseProviderMetadataTests +{ + [Test] + [TestCase("myServer", "myDatabase", "myLogin", "myPassword", true, ExpectedResult = "Server=myServer;Database=myDatabase;Integrated Security=true")] + [TestCase("myServer", "myDatabase", "myLogin", "myPassword", false, ExpectedResult = "Server=myServer;Database=myDatabase;User Id=myLogin;Password=myPassword")] + public string GenerateConnectionString(string server, string databaseName, string login, string password, bool integratedAuth) + { + var sut = new SqlServerDatabaseProviderMetadata(); + return sut.GenerateConnectionString(new DatabaseModel() + { + DatabaseName = databaseName, + Login = login, + Password = password, + Server = server, + IntegratedAuth = integratedAuth + }); + } + + [Test] + [TestCase("Server=myServer;Database=myDatabase;Integrated Security=true", ExpectedResult = true)] // SqlServer + [TestCase("Server=myServer;Database=myDatabase;User Id=myLogin;Password=myPassword", ExpectedResult = true)] // SqlServer + [TestCase("Server=tcp:cmstest27032000.database.windows.net,1433;Database=test_27032000;User ID=asdasdas@cmstest27032000;Password=123456879", ExpectedResult = true)] // Azure + [TestCase("Data Source=|DataDirectory|/Umbraco.sqlite.db;Cache=Shared;Foreign Keys=True;Pooling=True", ExpectedResult = false)] // Sqlite + [TestCase("Data Source=(LocalDb)\\MSSQLLocalDB;Initial Catalog=aspnet-MvcMovie;Integrated Security=SSPI;AttachDBFilename=|DataDirectory|\\umbraco.mdf", ExpectedResult = false)] // localDB + public bool CanRecognizeConnectionString(string connectionString) + { + var sut = new SqlServerDatabaseProviderMetadata(); + return sut.CanRecognizeConnectionString(connectionString); + } +} diff --git a/tests/Umbraco.Tests.UnitTests/Umbraco.Cms.Persistence.Sqlite/SqliteDatabaseProviderMetadataTests.cs b/tests/Umbraco.Tests.UnitTests/Umbraco.Cms.Persistence.Sqlite/SqliteDatabaseProviderMetadataTests.cs new file mode 100644 index 0000000000..63eb6c86fd --- /dev/null +++ b/tests/Umbraco.Tests.UnitTests/Umbraco.Cms.Persistence.Sqlite/SqliteDatabaseProviderMetadataTests.cs @@ -0,0 +1,37 @@ +using NUnit.Framework; +using Umbraco.Cms.Core.Install.Models; +using Umbraco.Cms.Persistence.Sqlite.Services; + +namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Cms.Persistence.Sqlite; + +[TestFixture] +public class SqliteDatabaseProviderMetadataTests +{ + [Test] + [TestCase("ignored", "myDatabase", "ignored", "ignored", true /*ignored*/, ExpectedResult = "Data Source=|DataDirectory|/myDatabase.sqlite.db;Cache=Shared;Foreign Keys=True;Pooling=True")] + [TestCase("ignored", "myDatabase2", "ignored", "ignored", false /*ignored*/, ExpectedResult = "Data Source=|DataDirectory|/myDatabase2.sqlite.db;Cache=Shared;Foreign Keys=True;Pooling=True")] + public string GenerateConnectionString(string server, string databaseName, string login, string password, bool integratedAuth) + { + var sut = new SqliteDatabaseProviderMetadata(); + return sut.GenerateConnectionString(new DatabaseModel() + { + DatabaseName = databaseName, + Login = login, + Password = password, + Server = server, + IntegratedAuth = integratedAuth + }); + } + + [Test] + [TestCase("Server=myServer;Database=myDatabase;Integrated Security=true", ExpectedResult = false)] // SqlServer + [TestCase("Server=myServer;Database=myDatabase;User Id=myLogin;Password=myPassword", ExpectedResult = false)] // SqlServer + [TestCase("Server=tcp:cmstest27032000.database.windows.net,1433;Database=test_27032000;User ID=asdasdas@cmstest27032000;Password=123456879", ExpectedResult = false)] // Azure + [TestCase("Data Source=|DataDirectory|/Umbraco.sqlite.db;Cache=Shared;Foreign Keys=True;Pooling=True", ExpectedResult = true)] // Sqlite + [TestCase("Data Source=(LocalDb)\\MSSQLLocalDB;Initial Catalog=aspnet-MvcMovie;Integrated Security=SSPI;AttachDBFilename=|DataDirectory|\\umbraco.mdf", ExpectedResult = false)] // localDB + public bool CanRecognizeConnectionString(string connectionString) + { + var sut = new SqliteDatabaseProviderMetadata(); + return sut.CanRecognizeConnectionString(connectionString); + } +} diff --git a/tests/Umbraco.Tests.UnitTests/Umbraco.New.Cms.Infrastructure/Factories/DatabaseSettingsFactoryTests.cs b/tests/Umbraco.Tests.UnitTests/Umbraco.New.Cms.Infrastructure/Factories/DatabaseSettingsFactoryTests.cs index fd2c7315b0..82beaeeab9 100644 --- a/tests/Umbraco.Tests.UnitTests/Umbraco.New.Cms.Infrastructure/Factories/DatabaseSettingsFactoryTests.cs +++ b/tests/Umbraco.Tests.UnitTests/Umbraco.New.Cms.Infrastructure/Factories/DatabaseSettingsFactoryTests.cs @@ -177,6 +177,8 @@ public class DatabaseSettingsFactoryTests public Func GenerateConnectionStringDelegate { get; set; } = _ => "ConnectionString"; + public bool CanRecognizeConnectionString(string? connectionString) => false; + public string? GenerateConnectionString(DatabaseModel databaseModel) => GenerateConnectionStringDelegate(databaseModel); } } diff --git a/tests/Umbraco.Tests.UnitTests/Umbraco.Tests.UnitTests.csproj b/tests/Umbraco.Tests.UnitTests/Umbraco.Tests.UnitTests.csproj index 8b59b8193f..8a79dd6d19 100644 --- a/tests/Umbraco.Tests.UnitTests/Umbraco.Tests.UnitTests.csproj +++ b/tests/Umbraco.Tests.UnitTests/Umbraco.Tests.UnitTests.csproj @@ -15,6 +15,7 @@ + From ce47281c04f20e476b99c1a178818d4aece80eab Mon Sep 17 00:00:00 2001 From: Bjarke Berg Date: Thu, 30 Mar 2023 10:19:35 +0200 Subject: [PATCH 05/13] Determine correct if we can create a database with current connectionstring (#14030) * Fix CanForceCreateDatabase method and add some unit tests * Fixed an old copy/paste error * A little nitpicking over wording and formatting --------- Co-authored-by: kjac --- .../Constants.cs | 4 +- .../SqlAzureDatabaseProviderMetadata.cs | 20 ++++++++++ .../SqlLocalDbDatabaseProviderMetadata.cs | 21 +++++++++++ .../SqlServerDatabaseProviderMetadata.cs | 23 ++++++++++++ .../SqliteDatabaseProviderMetadata.cs | 20 ++++++++++ .../Install/InstallHelper.cs | 2 +- .../DatabaseProviderMetadataExtensions.cs | 27 +++++++++++++- .../Persistence/IDatabaseProviderMetadata.cs | 6 +++ .../Runtime/RuntimeState.cs | 2 +- .../SqAzureDatabaseProviderMetadataTests.cs | 37 +++++++++++++++++++ ...SqlLocalDbDatabaseProviderMetadataTests.cs | 37 +++++++++++++++++++ .../SqlServerDatabaseProviderMetadataTests.cs | 37 +++++++++++++++++++ .../SqliteDatabaseProviderMetadataTests.cs | 37 +++++++++++++++++++ .../Factories/DatabaseSettingsFactoryTests.cs | 2 + .../Umbraco.Tests.UnitTests.csproj | 1 + 15 files changed, 271 insertions(+), 5 deletions(-) create mode 100644 tests/Umbraco.Tests.UnitTests/Umbraco.Cms.Persistence.SqlServer/SqAzureDatabaseProviderMetadataTests.cs create mode 100644 tests/Umbraco.Tests.UnitTests/Umbraco.Cms.Persistence.SqlServer/SqlLocalDbDatabaseProviderMetadataTests.cs create mode 100644 tests/Umbraco.Tests.UnitTests/Umbraco.Cms.Persistence.SqlServer/SqlServerDatabaseProviderMetadataTests.cs create mode 100644 tests/Umbraco.Tests.UnitTests/Umbraco.Cms.Persistence.Sqlite/SqliteDatabaseProviderMetadataTests.cs diff --git a/src/Umbraco.Cms.Persistence.SqlServer/Constants.cs b/src/Umbraco.Cms.Persistence.SqlServer/Constants.cs index ae16a9735f..6b5099b314 100644 --- a/src/Umbraco.Cms.Persistence.SqlServer/Constants.cs +++ b/src/Umbraco.Cms.Persistence.SqlServer/Constants.cs @@ -1,12 +1,12 @@ namespace Umbraco.Cms.Persistence.SqlServer; /// -/// Constants related to SQLite. +/// Constants related to SQL Server. /// public static class Constants { /// - /// SQLite provider name. + /// SQL Server provider name. /// public const string ProviderName = "Microsoft.Data.SqlClient"; } diff --git a/src/Umbraco.Cms.Persistence.SqlServer/Services/SqlAzureDatabaseProviderMetadata.cs b/src/Umbraco.Cms.Persistence.SqlServer/Services/SqlAzureDatabaseProviderMetadata.cs index 112d556712..95dda5fe7b 100644 --- a/src/Umbraco.Cms.Persistence.SqlServer/Services/SqlAzureDatabaseProviderMetadata.cs +++ b/src/Umbraco.Cms.Persistence.SqlServer/Services/SqlAzureDatabaseProviderMetadata.cs @@ -1,4 +1,5 @@ using System.Runtime.Serialization; +using Microsoft.Data.SqlClient; using Umbraco.Cms.Core.Install.Models; using Umbraco.Cms.Infrastructure.Persistence; using Umbraco.Extensions; @@ -50,6 +51,25 @@ public class SqlAzureDatabaseProviderMetadata : IDatabaseProviderMetadata /// public bool ForceCreateDatabase => false; + /// + public bool CanRecognizeConnectionString(string? connectionString) + { + if (connectionString is null) + { + return false; + } + + try + { + var builder = new SqlConnectionStringBuilder(connectionString); + + return string.IsNullOrEmpty(builder.AttachDBFilename) && builder.DataSource.Contains("database.windows.net"); + } + catch (ArgumentException) + { + return false; + } + } /// public string GenerateConnectionString(DatabaseModel databaseModel) { diff --git a/src/Umbraco.Cms.Persistence.SqlServer/Services/SqlLocalDbDatabaseProviderMetadata.cs b/src/Umbraco.Cms.Persistence.SqlServer/Services/SqlLocalDbDatabaseProviderMetadata.cs index 30a503e5f9..589ef5a623 100644 --- a/src/Umbraco.Cms.Persistence.SqlServer/Services/SqlLocalDbDatabaseProviderMetadata.cs +++ b/src/Umbraco.Cms.Persistence.SqlServer/Services/SqlLocalDbDatabaseProviderMetadata.cs @@ -51,6 +51,27 @@ public class SqlLocalDbDatabaseProviderMetadata : IDatabaseProviderMetadata /// public bool ForceCreateDatabase => true; + /// + public bool CanRecognizeConnectionString(string? connectionString) + { + if (connectionString is null) + { + return false; + } + + try + { + var builder = new SqlConnectionStringBuilder(connectionString); + + return !string.IsNullOrEmpty(builder.AttachDBFilename); + + } + catch (ArgumentException) + { + return false; + } + } + /// public string GenerateConnectionString(DatabaseModel databaseModel) { diff --git a/src/Umbraco.Cms.Persistence.SqlServer/Services/SqlServerDatabaseProviderMetadata.cs b/src/Umbraco.Cms.Persistence.SqlServer/Services/SqlServerDatabaseProviderMetadata.cs index 8b36736804..edb44700d8 100644 --- a/src/Umbraco.Cms.Persistence.SqlServer/Services/SqlServerDatabaseProviderMetadata.cs +++ b/src/Umbraco.Cms.Persistence.SqlServer/Services/SqlServerDatabaseProviderMetadata.cs @@ -1,6 +1,9 @@ +using System.Data.Common; using System.Runtime.Serialization; +using Microsoft.Data.SqlClient; using Umbraco.Cms.Core.Install.Models; using Umbraco.Cms.Infrastructure.Persistence; +using Umbraco.Extensions; namespace Umbraco.Cms.Persistence.SqlServer.Services; @@ -49,6 +52,26 @@ public class SqlServerDatabaseProviderMetadata : IDatabaseProviderMetadata /// public bool ForceCreateDatabase => false; + /// + public bool CanRecognizeConnectionString(string? connectionString) + { + if (connectionString is null) + { + return false; + } + + try + { + var builder = new SqlConnectionStringBuilder(connectionString); + + return string.IsNullOrEmpty(builder.AttachDBFilename); + } + catch (ArgumentException) + { + return false; + } + } + /// public string GenerateConnectionString(DatabaseModel databaseModel) => databaseModel.IntegratedAuth diff --git a/src/Umbraco.Cms.Persistence.Sqlite/Services/SqliteDatabaseProviderMetadata.cs b/src/Umbraco.Cms.Persistence.Sqlite/Services/SqliteDatabaseProviderMetadata.cs index 54a7a5cb1d..d087acc8cb 100644 --- a/src/Umbraco.Cms.Persistence.Sqlite/Services/SqliteDatabaseProviderMetadata.cs +++ b/src/Umbraco.Cms.Persistence.Sqlite/Services/SqliteDatabaseProviderMetadata.cs @@ -56,6 +56,26 @@ public class SqliteDatabaseProviderMetadata : IDatabaseProviderMetadata /// public bool ForceCreateDatabase => true; + /// + public bool CanRecognizeConnectionString(string? connectionString) + { + if (connectionString is null) + { + return false; + } + + try + { + var builder = new SqliteConnectionStringBuilder(connectionString); + + return !string.IsNullOrEmpty(builder.DataSource); + + } + catch (ArgumentException) + { + return false; + } + } /// public string GenerateConnectionString(DatabaseModel databaseModel) { diff --git a/src/Umbraco.Infrastructure/Install/InstallHelper.cs b/src/Umbraco.Infrastructure/Install/InstallHelper.cs index 9305c4444e..0ea4a1a84c 100644 --- a/src/Umbraco.Infrastructure/Install/InstallHelper.cs +++ b/src/Umbraco.Infrastructure/Install/InstallHelper.cs @@ -164,7 +164,7 @@ namespace Umbraco.Cms.Infrastructure.Install private bool IsBrandNewInstall => _connectionStrings.CurrentValue.IsConnectionStringConfigured() == false || _databaseBuilder.IsDatabaseConfigured == false || - (_databaseBuilder.CanConnectToDatabase == false && _databaseProviderMetadata.CanForceCreateDatabase(_umbracoDatabaseFactory.SqlContext.SqlSyntax.DbProvider)) || + (_databaseBuilder.CanConnectToDatabase == false && _databaseProviderMetadata.CanForceCreateDatabase(_umbracoDatabaseFactory)) || _databaseBuilder.IsUmbracoInstalled() == false; } } diff --git a/src/Umbraco.Infrastructure/Persistence/DatabaseProviderMetadataExtensions.cs b/src/Umbraco.Infrastructure/Persistence/DatabaseProviderMetadataExtensions.cs index 1ea941932e..09c0a121dc 100644 --- a/src/Umbraco.Infrastructure/Persistence/DatabaseProviderMetadataExtensions.cs +++ b/src/Umbraco.Infrastructure/Persistence/DatabaseProviderMetadataExtensions.cs @@ -1,4 +1,5 @@ using Umbraco.Cms.Core.Install.Models; +using Umbraco.Cms.Infrastructure.Persistence.SqlSyntax; namespace Umbraco.Cms.Infrastructure.Persistence; @@ -26,8 +27,32 @@ public static class DatabaseProviderMetadataExtensions /// /// true if a database can be created for the specified provider name; otherwise, false. /// + [Obsolete("Use CanForceCreateDatabase that takes an IUmbracoDatabaseFactory. Scheduled for removal in Umbraco 13.")] public static bool CanForceCreateDatabase(this IEnumerable databaseProviderMetadata, string? providerName) - => databaseProviderMetadata.FirstOrDefault(x => string.Equals(x.ProviderName, providerName, StringComparison.InvariantCultureIgnoreCase))?.ForceCreateDatabase == true; + { + return databaseProviderMetadata + .FirstOrDefault(x => + string.Equals(x.ProviderName, providerName, StringComparison.InvariantCultureIgnoreCase)) + ?.ForceCreateDatabase == true; + } + + /// + /// Determines whether a database can be created for the specified provider name while ignoring the value of . + /// + /// The database provider metadata. + /// The database factory. + /// + /// true if a database can be created for the specified database; otherwise, false. + /// + public static bool CanForceCreateDatabase(this IEnumerable databaseProviderMetadata, IUmbracoDatabaseFactory umbracoDatabaseFactory) + { + // In case more metadata providers can recognize the connection string, we need to check if any can force create. + // E.g. Both SqlServer and SqlAzure will recognize an azure connection string, but luckily none of those can force create. + return databaseProviderMetadata + .Where(x => + string.Equals(x.ProviderName, umbracoDatabaseFactory.SqlContext.SqlSyntax.ProviderName, StringComparison.InvariantCultureIgnoreCase) + && x.CanRecognizeConnectionString(umbracoDatabaseFactory.ConnectionString) && x.IsAvailable).Any(x => x.ForceCreateDatabase == true); + } /// /// Generates the connection string. diff --git a/src/Umbraco.Infrastructure/Persistence/IDatabaseProviderMetadata.cs b/src/Umbraco.Infrastructure/Persistence/IDatabaseProviderMetadata.cs index 1c06dd089f..55a7c3a686 100644 --- a/src/Umbraco.Infrastructure/Persistence/IDatabaseProviderMetadata.cs +++ b/src/Umbraco.Infrastructure/Persistence/IDatabaseProviderMetadata.cs @@ -82,6 +82,12 @@ public interface IDatabaseProviderMetadata /// public bool ForceCreateDatabase { get; } + + /// + /// Gets a value indicating whether this connections could have been build using . + /// + public bool CanRecognizeConnectionString(string? connectionString) => false; + /// /// Creates a connection string for this provider. /// diff --git a/src/Umbraco.Infrastructure/Runtime/RuntimeState.cs b/src/Umbraco.Infrastructure/Runtime/RuntimeState.cs index 74b00d3644..ec1cfc5d6e 100644 --- a/src/Umbraco.Infrastructure/Runtime/RuntimeState.cs +++ b/src/Umbraco.Infrastructure/Runtime/RuntimeState.cs @@ -210,7 +210,7 @@ public class RuntimeState : IRuntimeState // cannot connect to configured database, this is bad, fail _logger.LogDebug("Could not connect to database."); - if (_globalSettings.Value.InstallMissingDatabase || _databaseProviderMetadata.CanForceCreateDatabase(_databaseFactory.ProviderName)) + if (_globalSettings.Value.InstallMissingDatabase || _databaseProviderMetadata.CanForceCreateDatabase(_databaseFactory)) { // ok to install on a configured but missing database Level = RuntimeLevel.Install; diff --git a/tests/Umbraco.Tests.UnitTests/Umbraco.Cms.Persistence.SqlServer/SqAzureDatabaseProviderMetadataTests.cs b/tests/Umbraco.Tests.UnitTests/Umbraco.Cms.Persistence.SqlServer/SqAzureDatabaseProviderMetadataTests.cs new file mode 100644 index 0000000000..e945eeae07 --- /dev/null +++ b/tests/Umbraco.Tests.UnitTests/Umbraco.Cms.Persistence.SqlServer/SqAzureDatabaseProviderMetadataTests.cs @@ -0,0 +1,37 @@ +using NUnit.Framework; +using Umbraco.Cms.Core.Install.Models; +using Umbraco.Cms.Persistence.SqlServer.Services; + +namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Cms.Persistence.SqlServer; + +[TestFixture] +public class SqlAzureDatabaseProviderMetadataTests +{ + [Test] + [TestCase("myServer", "myDatabase", "myLogin", "myPassword", true /*ignored*/, ExpectedResult = "Server=tcp:myServer.database.windows.net,1433;Database=myDatabase;User ID=myLogin@myServer;Password=myPassword")] + [TestCase("myServer", "myDatabase", "myLogin", "myPassword", false, ExpectedResult = "Server=tcp:myServer.database.windows.net,1433;Database=myDatabase;User ID=myLogin@myServer;Password=myPassword")] + public string GenerateConnectionString(string server, string databaseName, string login, string password, bool integratedAuth) + { + var sut = new SqlAzureDatabaseProviderMetadata(); + return sut.GenerateConnectionString(new DatabaseModel() + { + DatabaseName = databaseName, + Login = login, + Password = password, + Server = server, + IntegratedAuth = integratedAuth + }); + } + + [Test] + [TestCase("Server=myServer;Database=myDatabase;Integrated Security=true", ExpectedResult = false)] // SqlServer + [TestCase("Server=myServer;Database=myDatabase;User Id=myLogin;Password=myPassword", ExpectedResult = false)] // SqlServer + [TestCase("Server=tcp:cmstest27032000.database.windows.net,1433;Database=test_27032000;User ID=asdasdas@cmstest27032000;Password=123456879", ExpectedResult = true)] // Azure + [TestCase("Data Source=|DataDirectory|/Umbraco.sqlite.db;Cache=Shared;Foreign Keys=True;Pooling=True", ExpectedResult = false)] // Sqlite + [TestCase("Data Source=(LocalDb)\\MSSQLLocalDB;Initial Catalog=aspnet-MvcMovie;Integrated Security=SSPI;AttachDBFilename=|DataDirectory|\\umbraco.mdf", ExpectedResult = false)] // localDB + public bool CanRecognizeConnectionString(string connectionString) + { + var sut = new SqlAzureDatabaseProviderMetadata(); + return sut.CanRecognizeConnectionString(connectionString); + } +} diff --git a/tests/Umbraco.Tests.UnitTests/Umbraco.Cms.Persistence.SqlServer/SqlLocalDbDatabaseProviderMetadataTests.cs b/tests/Umbraco.Tests.UnitTests/Umbraco.Cms.Persistence.SqlServer/SqlLocalDbDatabaseProviderMetadataTests.cs new file mode 100644 index 0000000000..24728a6c3e --- /dev/null +++ b/tests/Umbraco.Tests.UnitTests/Umbraco.Cms.Persistence.SqlServer/SqlLocalDbDatabaseProviderMetadataTests.cs @@ -0,0 +1,37 @@ +using NUnit.Framework; +using Umbraco.Cms.Core.Install.Models; +using Umbraco.Cms.Persistence.SqlServer.Services; + +namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Cms.Persistence.SqlServer; + +[TestFixture] +public class SqlLocalDbDatabaseProviderMetadataTests +{ + [Test] + [TestCase("ignored", "myDatabase", "ignored", "ignored", true, ExpectedResult = "Data Source=(localdb)\\MSSQLLocalDB;AttachDbFilename=|DataDirectory|\\myDatabase.mdf;Integrated Security=True")] + [TestCase("ignored", "myDatabase2", "ignored", "ignored", false /*ignored*/, ExpectedResult = "Data Source=(localdb)\\MSSQLLocalDB;AttachDbFilename=|DataDirectory|\\myDatabase2.mdf;Integrated Security=True")] + public string GenerateConnectionString(string server, string databaseName, string login, string password, bool integratedAuth) + { + var sut = new SqlLocalDbDatabaseProviderMetadata(); + return sut.GenerateConnectionString(new DatabaseModel() + { + DatabaseName = databaseName, + Login = login, + Password = password, + Server = server, + IntegratedAuth = integratedAuth, + }); + } + + [Test] + [TestCase("Server=myServer;Database=myDatabase;Integrated Security=true", ExpectedResult = false)] // SqlServer + [TestCase("Server=myServer;Database=myDatabase;User Id=myLogin;Password=myPassword", ExpectedResult = false)] // SqlServer + [TestCase("Server=tcp:cmstest27032000.database.windows.net,1433;Database=test_27032000;User ID=asdasdas@cmstest27032000;Password=123456879", ExpectedResult = false)] // Azure + [TestCase("Data Source=|DataDirectory|/Umbraco.sqlite.db;Cache=Shared;Foreign Keys=True;Pooling=True", ExpectedResult = false)] // Sqlite + [TestCase("Data Source=(LocalDb)\\MSSQLLocalDB;Initial Catalog=aspnet-MvcMovie;Integrated Security=SSPI;AttachDBFilename=|DataDirectory|\\umbraco.mdf", ExpectedResult = true)] // localDB + public bool CanRecognizeConnectionString(string connectionString) + { + var sut = new SqlLocalDbDatabaseProviderMetadata(); + return sut.CanRecognizeConnectionString(connectionString); + } +} diff --git a/tests/Umbraco.Tests.UnitTests/Umbraco.Cms.Persistence.SqlServer/SqlServerDatabaseProviderMetadataTests.cs b/tests/Umbraco.Tests.UnitTests/Umbraco.Cms.Persistence.SqlServer/SqlServerDatabaseProviderMetadataTests.cs new file mode 100644 index 0000000000..4e96c375e1 --- /dev/null +++ b/tests/Umbraco.Tests.UnitTests/Umbraco.Cms.Persistence.SqlServer/SqlServerDatabaseProviderMetadataTests.cs @@ -0,0 +1,37 @@ +using NUnit.Framework; +using Umbraco.Cms.Core.Install.Models; +using Umbraco.Cms.Persistence.SqlServer.Services; + +namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Cms.Persistence.SqlServer; + +[TestFixture] +public class SqlServerDatabaseProviderMetadataTests +{ + [Test] + [TestCase("myServer", "myDatabase", "myLogin", "myPassword", true, ExpectedResult = "Server=myServer;Database=myDatabase;Integrated Security=true")] + [TestCase("myServer", "myDatabase", "myLogin", "myPassword", false, ExpectedResult = "Server=myServer;Database=myDatabase;User Id=myLogin;Password=myPassword")] + public string GenerateConnectionString(string server, string databaseName, string login, string password, bool integratedAuth) + { + var sut = new SqlServerDatabaseProviderMetadata(); + return sut.GenerateConnectionString(new DatabaseModel() + { + DatabaseName = databaseName, + Login = login, + Password = password, + Server = server, + IntegratedAuth = integratedAuth + }); + } + + [Test] + [TestCase("Server=myServer;Database=myDatabase;Integrated Security=true", ExpectedResult = true)] // SqlServer + [TestCase("Server=myServer;Database=myDatabase;User Id=myLogin;Password=myPassword", ExpectedResult = true)] // SqlServer + [TestCase("Server=tcp:cmstest27032000.database.windows.net,1433;Database=test_27032000;User ID=asdasdas@cmstest27032000;Password=123456879", ExpectedResult = true)] // Azure + [TestCase("Data Source=|DataDirectory|/Umbraco.sqlite.db;Cache=Shared;Foreign Keys=True;Pooling=True", ExpectedResult = false)] // Sqlite + [TestCase("Data Source=(LocalDb)\\MSSQLLocalDB;Initial Catalog=aspnet-MvcMovie;Integrated Security=SSPI;AttachDBFilename=|DataDirectory|\\umbraco.mdf", ExpectedResult = false)] // localDB + public bool CanRecognizeConnectionString(string connectionString) + { + var sut = new SqlServerDatabaseProviderMetadata(); + return sut.CanRecognizeConnectionString(connectionString); + } +} diff --git a/tests/Umbraco.Tests.UnitTests/Umbraco.Cms.Persistence.Sqlite/SqliteDatabaseProviderMetadataTests.cs b/tests/Umbraco.Tests.UnitTests/Umbraco.Cms.Persistence.Sqlite/SqliteDatabaseProviderMetadataTests.cs new file mode 100644 index 0000000000..63eb6c86fd --- /dev/null +++ b/tests/Umbraco.Tests.UnitTests/Umbraco.Cms.Persistence.Sqlite/SqliteDatabaseProviderMetadataTests.cs @@ -0,0 +1,37 @@ +using NUnit.Framework; +using Umbraco.Cms.Core.Install.Models; +using Umbraco.Cms.Persistence.Sqlite.Services; + +namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Cms.Persistence.Sqlite; + +[TestFixture] +public class SqliteDatabaseProviderMetadataTests +{ + [Test] + [TestCase("ignored", "myDatabase", "ignored", "ignored", true /*ignored*/, ExpectedResult = "Data Source=|DataDirectory|/myDatabase.sqlite.db;Cache=Shared;Foreign Keys=True;Pooling=True")] + [TestCase("ignored", "myDatabase2", "ignored", "ignored", false /*ignored*/, ExpectedResult = "Data Source=|DataDirectory|/myDatabase2.sqlite.db;Cache=Shared;Foreign Keys=True;Pooling=True")] + public string GenerateConnectionString(string server, string databaseName, string login, string password, bool integratedAuth) + { + var sut = new SqliteDatabaseProviderMetadata(); + return sut.GenerateConnectionString(new DatabaseModel() + { + DatabaseName = databaseName, + Login = login, + Password = password, + Server = server, + IntegratedAuth = integratedAuth + }); + } + + [Test] + [TestCase("Server=myServer;Database=myDatabase;Integrated Security=true", ExpectedResult = false)] // SqlServer + [TestCase("Server=myServer;Database=myDatabase;User Id=myLogin;Password=myPassword", ExpectedResult = false)] // SqlServer + [TestCase("Server=tcp:cmstest27032000.database.windows.net,1433;Database=test_27032000;User ID=asdasdas@cmstest27032000;Password=123456879", ExpectedResult = false)] // Azure + [TestCase("Data Source=|DataDirectory|/Umbraco.sqlite.db;Cache=Shared;Foreign Keys=True;Pooling=True", ExpectedResult = true)] // Sqlite + [TestCase("Data Source=(LocalDb)\\MSSQLLocalDB;Initial Catalog=aspnet-MvcMovie;Integrated Security=SSPI;AttachDBFilename=|DataDirectory|\\umbraco.mdf", ExpectedResult = false)] // localDB + public bool CanRecognizeConnectionString(string connectionString) + { + var sut = new SqliteDatabaseProviderMetadata(); + return sut.CanRecognizeConnectionString(connectionString); + } +} diff --git a/tests/Umbraco.Tests.UnitTests/Umbraco.New.Cms.Infrastructure/Factories/DatabaseSettingsFactoryTests.cs b/tests/Umbraco.Tests.UnitTests/Umbraco.New.Cms.Infrastructure/Factories/DatabaseSettingsFactoryTests.cs index fd2c7315b0..82beaeeab9 100644 --- a/tests/Umbraco.Tests.UnitTests/Umbraco.New.Cms.Infrastructure/Factories/DatabaseSettingsFactoryTests.cs +++ b/tests/Umbraco.Tests.UnitTests/Umbraco.New.Cms.Infrastructure/Factories/DatabaseSettingsFactoryTests.cs @@ -177,6 +177,8 @@ public class DatabaseSettingsFactoryTests public Func GenerateConnectionStringDelegate { get; set; } = _ => "ConnectionString"; + public bool CanRecognizeConnectionString(string? connectionString) => false; + public string? GenerateConnectionString(DatabaseModel databaseModel) => GenerateConnectionStringDelegate(databaseModel); } } diff --git a/tests/Umbraco.Tests.UnitTests/Umbraco.Tests.UnitTests.csproj b/tests/Umbraco.Tests.UnitTests/Umbraco.Tests.UnitTests.csproj index fcbb4d6908..8b6085bf6d 100644 --- a/tests/Umbraco.Tests.UnitTests/Umbraco.Tests.UnitTests.csproj +++ b/tests/Umbraco.Tests.UnitTests/Umbraco.Tests.UnitTests.csproj @@ -16,6 +16,7 @@ + From 92d92feb1541b0a76aaef5b8e744ef3e5e514ea9 Mon Sep 17 00:00:00 2001 From: Ronald Barendse Date: Wed, 5 Apr 2023 09:32:48 +0200 Subject: [PATCH 06/13] Add new 'Umbraco Package RCL' project template (#13776) * Add new 'Umbraco Package RCL' project template * Add --no-restore, hide --framework and remove conflicting -v parameter in Umbraco Package project template * Hide --framework and --PackageTestSiteName, remove conflicting -v parameter in Umbraco project template and persist selected parameters * Revert changes to Framework and UmbracoVersion parameter names --- templates/Umbraco.Templates.csproj | 1 + .../.template.config/dotnetcli.host.json | 7 +- .../.template.config/template.json | 23 +++++- .../.template.config/dotnetcli.host.json | 22 +++++ .../.template.config/ide.host.json | 20 +++++ .../.template.config/template.json | 82 +++++++++++++++++++ .../UmbracoPackageRcl/UmbracoPackage.csproj | 27 ++++++ .../wwwroot/package.manifest | 5 ++ .../.template.config/dotnetcli.host.json | 16 ++-- .../.template.config/ide.host.json | 20 ++--- .../.template.config/template.json | 2 +- 11 files changed, 203 insertions(+), 22 deletions(-) create mode 100644 templates/UmbracoPackageRcl/.template.config/dotnetcli.host.json create mode 100644 templates/UmbracoPackageRcl/.template.config/ide.host.json create mode 100644 templates/UmbracoPackageRcl/.template.config/template.json create mode 100644 templates/UmbracoPackageRcl/UmbracoPackage.csproj create mode 100644 templates/UmbracoPackageRcl/wwwroot/package.manifest diff --git a/templates/Umbraco.Templates.csproj b/templates/Umbraco.Templates.csproj index 10bbd666d1..3f9e1f0ce4 100644 --- a/templates/Umbraco.Templates.csproj +++ b/templates/Umbraco.Templates.csproj @@ -12,6 +12,7 @@ + UmbracoProject\Program.cs diff --git a/templates/UmbracoPackage/.template.config/dotnetcli.host.json b/templates/UmbracoPackage/.template.config/dotnetcli.host.json index 6bd79b7fd9..6473c5c643 100644 --- a/templates/UmbracoPackage/.template.config/dotnetcli.host.json +++ b/templates/UmbracoPackage/.template.config/dotnetcli.host.json @@ -3,11 +3,16 @@ "symbolInfo": { "Framework": { "longName": "Framework", - "shortName": "F" + "shortName": "F", + "isHidden": true }, "UmbracoVersion": { "longName": "version", "shortName": "v" + }, + "SkipRestore": { + "longName": "no-restore", + "shortName": "" } } } diff --git a/templates/UmbracoPackage/.template.config/template.json b/templates/UmbracoPackage/.template.config/template.json index 36c93da093..b1b4ef9425 100644 --- a/templates/UmbracoPackage/.template.config/template.json +++ b/templates/UmbracoPackage/.template.config/template.json @@ -41,9 +41,16 @@ "description": "The version of Umbraco.Cms to add as PackageReference.", "type": "parameter", "datatype": "string", - "defaultValue": "10.0.0-rc1", + "defaultValue": "11.0.0", "replaces": "UMBRACO_VERSION_FROM_TEMPLATE" }, + "SkipRestore": { + "displayName": "Skip restore", + "description": "If specified, skips the automatic restore of the project on create.", + "type": "parameter", + "datatype": "bool", + "defaultValue": "false" + }, "Namespace": { "type": "derived", "valueSource": "name", @@ -83,5 +90,19 @@ { "path": "UmbracoPackage.csproj" } + ], + "postActions": [ + { + "id": "restore", + "condition": "(!SkipRestore)", + "description": "Restore NuGet packages required by this project.", + "manualInstructions": [ + { + "text": "Run 'dotnet restore'" + } + ], + "actionId": "210D431B-A78B-4D2F-B762-4ED3E3EA9025", + "continueOnError": true + } ] } diff --git a/templates/UmbracoPackageRcl/.template.config/dotnetcli.host.json b/templates/UmbracoPackageRcl/.template.config/dotnetcli.host.json new file mode 100644 index 0000000000..9a960b348e --- /dev/null +++ b/templates/UmbracoPackageRcl/.template.config/dotnetcli.host.json @@ -0,0 +1,22 @@ +{ + "$schema": "https://json.schemastore.org/dotnetcli.host.json", + "symbolInfo": { + "Framework": { + "longName": "Framework", + "shortName": "F", + "isHidden": true + }, + "UmbracoVersion": { + "longName": "version", + "shortName": "" + }, + "SkipRestore": { + "longName": "no-restore", + "shortName": "" + }, + "SupportPagesAndViews": { + "longName": "support-pages-and-views", + "shortName": "s" + } + } +} diff --git a/templates/UmbracoPackageRcl/.template.config/ide.host.json b/templates/UmbracoPackageRcl/.template.config/ide.host.json new file mode 100644 index 0000000000..8e630f1e99 --- /dev/null +++ b/templates/UmbracoPackageRcl/.template.config/ide.host.json @@ -0,0 +1,20 @@ +{ + "$schema": "https://json.schemastore.org/ide.host.json", + "order": 0, + "icon": "../../icon.png", + "description": { + "id": "UmbracoPackageRcl", + "text": "Umbraco Package RCL - An empty Umbraco package/plugin (Razor Class Library)." + }, + "symbolInfo": [ + { + "id": "UmbracoVersion", + "isVisible": true + }, + { + "id": "SupportPagesAndViews", + "isVisible": true, + "persistenceScope": "templateGroup" + } + ] +} diff --git a/templates/UmbracoPackageRcl/.template.config/template.json b/templates/UmbracoPackageRcl/.template.config/template.json new file mode 100644 index 0000000000..c61289f6c2 --- /dev/null +++ b/templates/UmbracoPackageRcl/.template.config/template.json @@ -0,0 +1,82 @@ +{ + "$schema": "https://json.schemastore.org/template.json", + "author": "Umbraco HQ", + "classifications": [ + "Web", + "CMS", + "Umbraco", + "Package", + "Plugin", + "Razor Class Library" + ], + "name": "Umbraco Package RCL", + "description": "An empty Umbraco package/plugin (Razor Class Library).", + "groupIdentity": "Umbraco.Templates.UmbracoPackageRcl", + "identity": "Umbraco.Templates.UmbracoPackageRcl.CSharp", + "shortName": "umbracopackage-rcl", + "tags": { + "language": "C#", + "type": "project" + }, + "sourceName": "UmbracoPackage", + "defaultName": "UmbracoPackage1", + "preferNameDirectory": true, + "symbols": { + "Framework": { + "displayName": "Framework", + "description": "The target framework for the project.", + "type": "parameter", + "datatype": "choice", + "choices": [ + { + "displayName": ".NET 7.0", + "description": "Target net7.0", + "choice": "net7.0" + } + ], + "defaultValue": "net7.0", + "replaces": "net7.0" + }, + "UmbracoVersion": { + "displayName": "Umbraco version", + "description": "The version of Umbraco.Cms to add as PackageReference.", + "type": "parameter", + "datatype": "string", + "defaultValue": "11.0.0", + "replaces": "UMBRACO_VERSION_FROM_TEMPLATE" + }, + "SkipRestore": { + "displayName": "Skip restore", + "description": "If specified, skips the automatic restore of the project on create.", + "type": "parameter", + "datatype": "bool", + "defaultValue": "false" + }, + "SupportPagesAndViews": { + "type": "parameter", + "datatype": "bool", + "defaultValue": "false", + "displayName": "Support pages and views", + "description": "Whether to support adding traditional Razor pages and Views to this library." + } + }, + "primaryOutputs": [ + { + "path": "UmbracoPackage.csproj" + } + ], + "postActions": [ + { + "id": "restore", + "condition": "(!SkipRestore)", + "description": "Restore NuGet packages required by this project.", + "manualInstructions": [ + { + "text": "Run 'dotnet restore'" + } + ], + "actionId": "210D431B-A78B-4D2F-B762-4ED3E3EA9025", + "continueOnError": true + } + ] +} diff --git a/templates/UmbracoPackageRcl/UmbracoPackage.csproj b/templates/UmbracoPackageRcl/UmbracoPackage.csproj new file mode 100644 index 0000000000..5c980684ce --- /dev/null +++ b/templates/UmbracoPackageRcl/UmbracoPackage.csproj @@ -0,0 +1,27 @@ + + + net7.0 + enable + enable + true + UmbracoPackage + App_Plugins/UmbracoPackage + + + + UmbracoPackage + UmbracoPackage + UmbracoPackage + ... + umbraco plugin package + + + + + + + + + + + diff --git a/templates/UmbracoPackageRcl/wwwroot/package.manifest b/templates/UmbracoPackageRcl/wwwroot/package.manifest new file mode 100644 index 0000000000..6aadd0cee6 --- /dev/null +++ b/templates/UmbracoPackageRcl/wwwroot/package.manifest @@ -0,0 +1,5 @@ +{ + "name": "UmbracoPackage", + "version": "", + "allowPackageTelemetry": true +} diff --git a/templates/UmbracoProject/.template.config/dotnetcli.host.json b/templates/UmbracoProject/.template.config/dotnetcli.host.json index 7f5479eab0..dfd6f80184 100644 --- a/templates/UmbracoProject/.template.config/dotnetcli.host.json +++ b/templates/UmbracoProject/.template.config/dotnetcli.host.json @@ -3,7 +3,8 @@ "symbolInfo": { "Framework": { "longName": "Framework", - "shortName": "F" + "shortName": "F", + "isHidden": true }, "UmbracoVersion": { "longName": "version", @@ -55,14 +56,15 @@ }, "PackageProjectName": { "longName": "PackageTestSiteName", - "shortName": "p" + "shortName": "p", + "isHidden": true } }, "usageExamples": [ - "dotnet new umbraco -n MyNewProject", - "dotnet new umbraco -n MyNewProject --no-restore", - "dotnet new umbraco -n MyNewProject --development-database-type SQLite", - "dotnet new umbraco -n MyNewProject --development-database-type LocalDB", - "dotnet new umbraco -n MyNewProject --friendly-name \"Friendly Admin User\" --email admin@example.com --password password1234 --connection-string \"Server=ConnectionStringHere\"" + "dotnet new umbraco --name MyNewProject", + "dotnet new umbraco --name MyNewProject --no-restore", + "dotnet new umbraco --name MyNewProject --development-database-type SQLite", + "dotnet new umbraco --name MyNewProject --development-database-type LocalDB", + "dotnet new umbraco --name MyNewProject --friendly-name \"Administrator\" --email admin@example.com --password 1234567890 --connection-string \"Server=(local);Database=MyNewProject;Trusted_Connection=True;\"" ] } diff --git a/templates/UmbracoProject/.template.config/ide.host.json b/templates/UmbracoProject/.template.config/ide.host.json index 617f924f97..1a302779cc 100644 --- a/templates/UmbracoProject/.template.config/ide.host.json +++ b/templates/UmbracoProject/.template.config/ide.host.json @@ -13,19 +13,18 @@ }, { "id": "UseHttpsRedirect", - "isVisible": true - }, - { - "id": "SkipRestore", - "isVisible": true + "isVisible": true, + "persistenceScope": "templateGroup" }, { "id": "ExcludeGitignore", - "isVisible": true + "isVisible": true, + "persistenceScope": "templateGroup" }, { "id": "MinimalGitignore", - "isVisible": true + "isVisible": true, + "persistenceScope": "templateGroup" }, { "id": "ConnectionString", @@ -37,7 +36,8 @@ }, { "id": "DevelopmentDatabaseType", - "isVisible": true + "isVisible": true, + "persistenceScope": "templateGroup" }, { "id": "UnattendedUserName", @@ -54,10 +54,6 @@ { "id": "NoNodesViewPath", "isVisible": true - }, - { - "id": "PackageProjectName", - "isVisible": true } ] } diff --git a/templates/UmbracoProject/.template.config/template.json b/templates/UmbracoProject/.template.config/template.json index befe6d7e5a..049db86bf1 100644 --- a/templates/UmbracoProject/.template.config/template.json +++ b/templates/UmbracoProject/.template.config/template.json @@ -51,7 +51,7 @@ "description": "The version of Umbraco.Cms to add as PackageReference.", "type": "parameter", "datatype": "string", - "defaultValue": "10.0.0-rc1", + "defaultValue": "11.0.0", "replaces": "UMBRACO_VERSION_FROM_TEMPLATE" }, "UseHttpsRedirect": { From 4cb46f06ae300cbe9792f6c9bce95b9cab04bd60 Mon Sep 17 00:00:00 2001 From: Ronald Barendse Date: Wed, 5 Apr 2023 11:16:43 +0200 Subject: [PATCH 07/13] Update default UmbracoVersion template value using MSBuild target (#13481) * Update default UmbracoVersion template value using MSBuild target * Fix target order when using pack --no-build * Use JsonPathUpdateValue MSBuild task to update default UmbracoVersion template value * Update UmbracoVersion in Umbraco Package RCL --- build/azure-pipelines.yml | 19 ++-------------- templates/Umbraco.Templates.csproj | 22 +++++++++++++++++++ .../.template.config/template.json | 2 +- .../.template.config/template.json | 2 +- .../.template.config/template.json | 2 +- 5 files changed, 27 insertions(+), 20 deletions(-) diff --git a/build/azure-pipelines.yml b/build/azure-pipelines.yml index 97e0a10f9c..310477fa4c 100644 --- a/build/azure-pipelines.yml +++ b/build/azure-pipelines.yml @@ -94,23 +94,8 @@ stages: echo "##vso[task.setvariable variable=majorVersion;isOutput=true]$major" displayName: Set major version name: determineMajorVersion - - task: PowerShell@2 - displayName: Prepare nupkg - inputs: - targetType: inline - script: | - $umbracoVersion = "$(Build.BuildNumber)" -replace "\+",".g" - $templatePaths = Get-ChildItem 'templates/**/.template.config/template.json' - - foreach ($templatePath in $templatePaths) { - $a = Get-Content $templatePath -Raw | ConvertFrom-Json - if ($a.symbols -and $a.symbols.UmbracoVersion) { - $a.symbols.UmbracoVersion.defaultValue = $umbracoVersion - $a | ConvertTo-Json -Depth 32 | Set-Content $templatePath - } - } - - dotnet pack $(solution) --configuration $(buildConfiguration) --no-build --property:PackageOutputPath=$(Build.ArtifactStagingDirectory)/nupkg + - script: dotnet pack $(solution) --configuration $(buildConfiguration) --no-build --property:PackageOutputPath=$(Build.ArtifactStagingDirectory)/nupkg + displayName: Run dotnet pack - script: | sha="$(Build.SourceVersion)" sha=${sha:0:7} diff --git a/templates/Umbraco.Templates.csproj b/templates/Umbraco.Templates.csproj index 3f9e1f0ce4..38848d398a 100644 --- a/templates/Umbraco.Templates.csproj +++ b/templates/Umbraco.Templates.csproj @@ -8,6 +8,7 @@ true true . + NU5128 @@ -43,4 +44,25 @@ UmbracoProject\wwwroot + + + + + + + + <_TemplateJsonFiles Include="**\.template.config\template.json" Exclude="bin\**;obj\**" /> + <_TemplateJsonFiles> + $(IntermediateOutputPath)%(RelativeDir)%(Filename)%(Extension) + + + + + + <_PackageFiles Remove="@(_TemplateJsonFiles)" /> + <_PackageFiles Include="%(_TemplateJsonFiles.DestinationFile)"> + %(RelativeDir) + + + diff --git a/templates/UmbracoPackage/.template.config/template.json b/templates/UmbracoPackage/.template.config/template.json index b1b4ef9425..768a7a4bee 100644 --- a/templates/UmbracoPackage/.template.config/template.json +++ b/templates/UmbracoPackage/.template.config/template.json @@ -41,7 +41,7 @@ "description": "The version of Umbraco.Cms to add as PackageReference.", "type": "parameter", "datatype": "string", - "defaultValue": "11.0.0", + "defaultValue": "*", "replaces": "UMBRACO_VERSION_FROM_TEMPLATE" }, "SkipRestore": { diff --git a/templates/UmbracoPackageRcl/.template.config/template.json b/templates/UmbracoPackageRcl/.template.config/template.json index c61289f6c2..be7b1c04e8 100644 --- a/templates/UmbracoPackageRcl/.template.config/template.json +++ b/templates/UmbracoPackageRcl/.template.config/template.json @@ -42,7 +42,7 @@ "description": "The version of Umbraco.Cms to add as PackageReference.", "type": "parameter", "datatype": "string", - "defaultValue": "11.0.0", + "defaultValue": "*", "replaces": "UMBRACO_VERSION_FROM_TEMPLATE" }, "SkipRestore": { diff --git a/templates/UmbracoProject/.template.config/template.json b/templates/UmbracoProject/.template.config/template.json index 049db86bf1..d88b23c07d 100644 --- a/templates/UmbracoProject/.template.config/template.json +++ b/templates/UmbracoProject/.template.config/template.json @@ -51,7 +51,7 @@ "description": "The version of Umbraco.Cms to add as PackageReference.", "type": "parameter", "datatype": "string", - "defaultValue": "11.0.0", + "defaultValue": "*", "replaces": "UMBRACO_VERSION_FROM_TEMPLATE" }, "UseHttpsRedirect": { From 9223b5737ea5c7e4e4f0918b4484502d9b8b340c Mon Sep 17 00:00:00 2001 From: Ronald Barendse Date: Wed, 5 Apr 2023 12:59:01 +0200 Subject: [PATCH 08/13] Update target to execute during packaging (#13521) Co-authored-by: Nikolaj Geisle <70372949+Zeegaan@users.noreply.github.com> --- src/Umbraco.Cms.Targets/Umbraco.Cms.Targets.csproj | 4 ++-- src/Umbraco.Cms/Umbraco.Cms.csproj | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Umbraco.Cms.Targets/Umbraco.Cms.Targets.csproj b/src/Umbraco.Cms.Targets/Umbraco.Cms.Targets.csproj index d537b116c0..18f9beea96 100644 --- a/src/Umbraco.Cms.Targets/Umbraco.Cms.Targets.csproj +++ b/src/Umbraco.Cms.Targets/Umbraco.Cms.Targets.csproj @@ -50,10 +50,10 @@ - + - + <_PackageFiles Include="$(IntermediateOutputPath)_._" PackagePath="lib\$(TargetFramework)" /> diff --git a/src/Umbraco.Cms/Umbraco.Cms.csproj b/src/Umbraco.Cms/Umbraco.Cms.csproj index 1ff6e848ad..da6be4c30c 100644 --- a/src/Umbraco.Cms/Umbraco.Cms.csproj +++ b/src/Umbraco.Cms/Umbraco.Cms.csproj @@ -14,10 +14,10 @@ - + - + <_PackageFiles Include="$(IntermediateOutputPath)_._" PackagePath="lib\$(TargetFramework)" /> From 22328598dbbb22b36fb395e52507eeba9c3c3000 Mon Sep 17 00:00:00 2001 From: Elitsa Marinovska <21998037+elit0451@users.noreply.github.com> Date: Tue, 11 Apr 2023 15:41:55 +0200 Subject: [PATCH 09/13] Adding dedicated Forbidden and Unauthorized handling for members (#14036) --- .../Filters/UmbracoMemberAuthorizeFilter.cs | 15 ++++++++++++--- .../Security/ConfigureMemberCookieOptions.cs | 7 +++++++ 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/src/Umbraco.Web.Common/Filters/UmbracoMemberAuthorizeFilter.cs b/src/Umbraco.Web.Common/Filters/UmbracoMemberAuthorizeFilter.cs index 351ea6e1bf..95c4ae5cec 100644 --- a/src/Umbraco.Web.Common/Filters/UmbracoMemberAuthorizeFilter.cs +++ b/src/Umbraco.Web.Common/Filters/UmbracoMemberAuthorizeFilter.cs @@ -54,11 +54,20 @@ public class UmbracoMemberAuthorizeFilter : IAsyncAuthorizationFilter IMemberManager memberManager = context.HttpContext.RequestServices.GetRequiredService(); - if (!await IsAuthorizedAsync(memberManager)) + if (memberManager.IsLoggedIn()) + { + if (!await IsAuthorizedAsync(memberManager)) + { + context.HttpContext.SetReasonPhrase( + "Resource restricted: the member is not of a permitted type or group."); + context.Result = new ForbidResult(); + } + } + else { context.HttpContext.SetReasonPhrase( - "Resource restricted: either member is not logged on or is not of a permitted type or group."); - context.Result = new ForbidResult(); + "Resource restricted: the member is not logged in."); + context.Result = new UnauthorizedResult(); } } diff --git a/src/Umbraco.Web.Common/Security/ConfigureMemberCookieOptions.cs b/src/Umbraco.Web.Common/Security/ConfigureMemberCookieOptions.cs index 1e0960fbc7..9aa073483a 100644 --- a/src/Umbraco.Web.Common/Security/ConfigureMemberCookieOptions.cs +++ b/src/Umbraco.Web.Common/Security/ConfigureMemberCookieOptions.cs @@ -1,4 +1,5 @@ using Microsoft.AspNetCore.Authentication.Cookies; +using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Identity; using Microsoft.Extensions.Options; using Umbraco.Cms.Core.Routing; @@ -44,6 +45,12 @@ public sealed class ConfigureMemberCookieOptions : IConfigureNamedOptions + { + ctx.Response.StatusCode = StatusCodes.Status403Forbidden; + return Task.CompletedTask; }, }; From 8e32ac3e20312c7f8317d1b026b7367366685470 Mon Sep 17 00:00:00 2001 From: Nikolaj Date: Wed, 12 Apr 2023 09:35:23 +0200 Subject: [PATCH 10/13] Bump to non-rc --- version.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.json b/version.json index 8fc9e69f4e..4c30184f1a 100644 --- a/version.json +++ b/version.json @@ -1,6 +1,6 @@ { "$schema": "https://raw.githubusercontent.com/dotnet/Nerdbank.GitVersioning/master/src/NerdBank.GitVersioning/version.schema.json", - "version": "10.5.0-rc", + "version": "10.5.0", "assemblyVersion": { "precision": "build" }, From a1d6f65cff68d35e99dcc123771218f6d80ad984 Mon Sep 17 00:00:00 2001 From: Nikolaj Date: Wed, 12 Apr 2023 09:36:49 +0200 Subject: [PATCH 11/13] Bump to non-rc --- version.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.json b/version.json index 06b868d719..90dd35cd59 100644 --- a/version.json +++ b/version.json @@ -1,6 +1,6 @@ { "$schema": "https://raw.githubusercontent.com/dotnet/Nerdbank.GitVersioning/master/src/NerdBank.GitVersioning/version.schema.json", - "version": "11.3.0-rc", + "version": "11.3.0", "assemblyVersion": { "precision": "build" }, From c636c7a7d285af0d96a75f0692a28141bc30d721 Mon Sep 17 00:00:00 2001 From: Nikolaj Date: Thu, 13 Apr 2023 08:52:50 +0200 Subject: [PATCH 12/13] Bump version --- version.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.json b/version.json index 90dd35cd59..4ea57b6f8c 100644 --- a/version.json +++ b/version.json @@ -1,6 +1,6 @@ { "$schema": "https://raw.githubusercontent.com/dotnet/Nerdbank.GitVersioning/master/src/NerdBank.GitVersioning/version.schema.json", - "version": "11.3.0", + "version": "11.4.0-rc", "assemblyVersion": { "precision": "build" }, From 5d3546e1b59fe57eb32e9d086f5cc7c02426d1ac Mon Sep 17 00:00:00 2001 From: Nikolaj Date: Thu, 13 Apr 2023 08:53:47 +0200 Subject: [PATCH 13/13] Bump version --- version.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.json b/version.json index 4c30184f1a..0c594e5b7e 100644 --- a/version.json +++ b/version.json @@ -1,6 +1,6 @@ { "$schema": "https://raw.githubusercontent.com/dotnet/Nerdbank.GitVersioning/master/src/NerdBank.GitVersioning/version.schema.json", - "version": "10.5.0", + "version": "10.6.0-rc", "assemblyVersion": { "precision": "build" },