diff --git a/Directory.Build.props b/Directory.Build.props
index b0b655f4b0..0364d4e086 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -30,8 +30,8 @@
false
- true
- 12.0.0
+ false
+ 13.0.0truetrue
diff --git a/src/Umbraco.Cms.Api.Common/CompatibilitySuppressions.xml b/src/Umbraco.Cms.Api.Common/CompatibilitySuppressions.xml
deleted file mode 100644
index d864a9d227..0000000000
--- a/src/Umbraco.Cms.Api.Common/CompatibilitySuppressions.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-
-
- PKV006
- net7.0
-
-
\ No newline at end of file
diff --git a/src/Umbraco.Cms.Api.Delivery/CompatibilitySuppressions.xml b/src/Umbraco.Cms.Api.Delivery/CompatibilitySuppressions.xml
deleted file mode 100644
index d864a9d227..0000000000
--- a/src/Umbraco.Cms.Api.Delivery/CompatibilitySuppressions.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-
-
- PKV006
- net7.0
-
-
\ No newline at end of file
diff --git a/src/Umbraco.Cms.Imaging.ImageSharp/CompatibilitySuppressions.xml b/src/Umbraco.Cms.Imaging.ImageSharp/CompatibilitySuppressions.xml
deleted file mode 100644
index d864a9d227..0000000000
--- a/src/Umbraco.Cms.Imaging.ImageSharp/CompatibilitySuppressions.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-
-
- PKV006
- net7.0
-
-
\ No newline at end of file
diff --git a/src/Umbraco.Cms.Imaging.ImageSharp2/CompatibilitySuppressions.xml b/src/Umbraco.Cms.Imaging.ImageSharp2/CompatibilitySuppressions.xml
deleted file mode 100644
index d864a9d227..0000000000
--- a/src/Umbraco.Cms.Imaging.ImageSharp2/CompatibilitySuppressions.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-
-
- PKV006
- net7.0
-
-
\ No newline at end of file
diff --git a/src/Umbraco.Cms.Persistence.EFCore.SqlServer/SqlServerMigrationProvider.cs b/src/Umbraco.Cms.Persistence.EFCore.SqlServer/SqlServerMigrationProvider.cs
index bac08556a3..823a9e737f 100644
--- a/src/Umbraco.Cms.Persistence.EFCore.SqlServer/SqlServerMigrationProvider.cs
+++ b/src/Umbraco.Cms.Persistence.EFCore.SqlServer/SqlServerMigrationProvider.cs
@@ -1,4 +1,5 @@
using Microsoft.EntityFrameworkCore;
+using Umbraco.Cms.Core;
using Umbraco.Cms.Persistence.EFCore.Migrations;
using Umbraco.Extensions;
@@ -10,7 +11,7 @@ public class SqlServerMigrationProvider : IMigrationProvider
public SqlServerMigrationProvider(IDbContextFactory dbContextFactory) => _dbContextFactory = dbContextFactory;
- public string ProviderName => "Microsoft.Data.SqlClient";
+ public string ProviderName => Constants.ProviderNames.SQLServer;
public async Task MigrateAsync(EFCoreMigration migration)
{
diff --git a/src/Umbraco.Cms.Persistence.EFCore.SqlServer/SqlServerMigrationProviderSetup.cs b/src/Umbraco.Cms.Persistence.EFCore.SqlServer/SqlServerMigrationProviderSetup.cs
index 6b161fc47f..2d561e9f5a 100644
--- a/src/Umbraco.Cms.Persistence.EFCore.SqlServer/SqlServerMigrationProviderSetup.cs
+++ b/src/Umbraco.Cms.Persistence.EFCore.SqlServer/SqlServerMigrationProviderSetup.cs
@@ -1,11 +1,12 @@
using Microsoft.EntityFrameworkCore;
+using Umbraco.Cms.Core;
using Umbraco.Cms.Persistence.EFCore.Migrations;
namespace Umbraco.Cms.Persistence.EFCore.SqlServer;
public class SqlServerMigrationProviderSetup : IMigrationProviderSetup
{
- public string ProviderName => "Microsoft.Data.SqlClient";
+ public string ProviderName => Constants.ProviderNames.SQLServer;
public void Setup(DbContextOptionsBuilder builder, string? connectionString)
{
diff --git a/src/Umbraco.Cms.Persistence.EFCore.SqlServer/Umbraco.Cms.Persistence.EFCore.SqlServer.csproj b/src/Umbraco.Cms.Persistence.EFCore.SqlServer/Umbraco.Cms.Persistence.EFCore.SqlServer.csproj
index a75d681949..04e711f8d9 100644
--- a/src/Umbraco.Cms.Persistence.EFCore.SqlServer/Umbraco.Cms.Persistence.EFCore.SqlServer.csproj
+++ b/src/Umbraco.Cms.Persistence.EFCore.SqlServer/Umbraco.Cms.Persistence.EFCore.SqlServer.csproj
@@ -2,8 +2,6 @@
Umbraco CMS - Persistence - Entity Framework Core - SQL Server migrationsAdds support for Entity Framework Core SQL Server migrations to Umbraco CMS.
-
- false
diff --git a/src/Umbraco.Cms.Persistence.EFCore.Sqlite/SqliteMigrationProvider.cs b/src/Umbraco.Cms.Persistence.EFCore.Sqlite/SqliteMigrationProvider.cs
index 05d4024bb3..468f52021f 100644
--- a/src/Umbraco.Cms.Persistence.EFCore.Sqlite/SqliteMigrationProvider.cs
+++ b/src/Umbraco.Cms.Persistence.EFCore.Sqlite/SqliteMigrationProvider.cs
@@ -1,4 +1,5 @@
using Microsoft.EntityFrameworkCore;
+using Umbraco.Cms.Core;
using Umbraco.Cms.Persistence.EFCore.Migrations;
using Umbraco.Extensions;
@@ -11,7 +12,7 @@ public class SqliteMigrationProvider : IMigrationProvider
public SqliteMigrationProvider(IDbContextFactory dbContextFactory)
=> _dbContextFactory = dbContextFactory;
- public string ProviderName => "Microsoft.Data.Sqlite";
+ public string ProviderName => Constants.ProviderNames.SQLLite;
public async Task MigrateAsync(EFCoreMigration migration)
{
diff --git a/src/Umbraco.Cms.Persistence.EFCore.Sqlite/SqliteMigrationProviderSetup.cs b/src/Umbraco.Cms.Persistence.EFCore.Sqlite/SqliteMigrationProviderSetup.cs
index 4cba457768..3a1b97e76c 100644
--- a/src/Umbraco.Cms.Persistence.EFCore.Sqlite/SqliteMigrationProviderSetup.cs
+++ b/src/Umbraco.Cms.Persistence.EFCore.Sqlite/SqliteMigrationProviderSetup.cs
@@ -1,11 +1,12 @@
using Microsoft.EntityFrameworkCore;
+using Umbraco.Cms.Core;
using Umbraco.Cms.Persistence.EFCore.Migrations;
namespace Umbraco.Cms.Persistence.EFCore.Sqlite;
public class SqliteMigrationProviderSetup : IMigrationProviderSetup
{
- public string ProviderName => "Microsoft.Data.Sqlite";
+ public string ProviderName => Constants.ProviderNames.SQLLite;
public void Setup(DbContextOptionsBuilder builder, string? connectionString)
{
diff --git a/src/Umbraco.Cms.Persistence.EFCore.Sqlite/Umbraco.Cms.Persistence.EFCore.Sqlite.csproj b/src/Umbraco.Cms.Persistence.EFCore.Sqlite/Umbraco.Cms.Persistence.EFCore.Sqlite.csproj
index d6559a35ea..5cb9949c04 100644
--- a/src/Umbraco.Cms.Persistence.EFCore.Sqlite/Umbraco.Cms.Persistence.EFCore.Sqlite.csproj
+++ b/src/Umbraco.Cms.Persistence.EFCore.Sqlite/Umbraco.Cms.Persistence.EFCore.Sqlite.csproj
@@ -2,8 +2,6 @@
Umbraco CMS - Persistence - Entity Framework Core - SQLite migrationsAdds support for Entity Framework Core SQLite migrations to Umbraco CMS.
-
- false
diff --git a/src/Umbraco.Cms.Persistence.EFCore/CompatibilitySuppressions.xml b/src/Umbraco.Cms.Persistence.EFCore/CompatibilitySuppressions.xml
deleted file mode 100644
index d864a9d227..0000000000
--- a/src/Umbraco.Cms.Persistence.EFCore/CompatibilitySuppressions.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-
-
- PKV006
- net7.0
-
-
\ No newline at end of file
diff --git a/src/Umbraco.Cms.Persistence.EFCore/Composition/UmbracoEFCoreComposer.cs b/src/Umbraco.Cms.Persistence.EFCore/Composition/UmbracoEFCoreComposer.cs
index 8b8627df47..1b751c558b 100644
--- a/src/Umbraco.Cms.Persistence.EFCore/Composition/UmbracoEFCoreComposer.cs
+++ b/src/Umbraco.Cms.Persistence.EFCore/Composition/UmbracoEFCoreComposer.cs
@@ -20,7 +20,7 @@ public class UmbracoEFCoreComposer : IComposer
builder.AddNotificationAsyncHandler();
builder.AddNotificationAsyncHandler();
- builder.Services.AddUmbracoEFCoreContext((options, connectionString, providerName) =>
+ builder.Services.AddUmbracoDbContext((options) =>
{
// Register the entity sets needed by OpenIddict.
options.UseOpenIddict();
diff --git a/src/Umbraco.Cms.Persistence.EFCore/Extensions/UmbracoEFCoreServiceCollectionExtensions.cs b/src/Umbraco.Cms.Persistence.EFCore/Extensions/UmbracoEFCoreServiceCollectionExtensions.cs
index ded5be40fd..d901088064 100644
--- a/src/Umbraco.Cms.Persistence.EFCore/Extensions/UmbracoEFCoreServiceCollectionExtensions.cs
+++ b/src/Umbraco.Cms.Persistence.EFCore/Extensions/UmbracoEFCoreServiceCollectionExtensions.cs
@@ -1,7 +1,9 @@
+using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Options;
+using Serilog;
using Umbraco.Cms.Core;
using Umbraco.Cms.Core.Configuration.Models;
using Umbraco.Cms.Core.DistributedLocking;
@@ -16,6 +18,7 @@ public static class UmbracoEFCoreServiceCollectionExtensions
{
public delegate void DefaultEFCoreOptionsAction(DbContextOptionsBuilder options, string? providerName, string? connectionString);
+ [Obsolete("Use AddUmbracoDbContext(this IServiceCollection services, Action? optionsAction = null) instead.")]
public static IServiceCollection AddUmbracoEFCoreContext(this IServiceCollection services, DefaultEFCoreOptionsAction? defaultEFCoreOptionsAction = null)
where T : DbContext
{
@@ -24,7 +27,7 @@ public static class UmbracoEFCoreServiceCollectionExtensions
sp =>
{
SetupDbContext(defaultEFCoreOptionsAction, sp, optionsBuilder);
- return new UmbracoPooledDbContextFactory(sp.GetRequiredService(),optionsBuilder.Options);
+ return new UmbracoPooledDbContextFactory(sp.GetRequiredService(), optionsBuilder.Options);
});
services.AddPooledDbContextFactory((provider, builder) => SetupDbContext(defaultEFCoreOptionsAction, provider, builder));
services.AddTransient(services => services.GetRequiredService>().CreateDbContext());
@@ -38,6 +41,7 @@ public static class UmbracoEFCoreServiceCollectionExtensions
return services;
}
+ [Obsolete("Use AddUmbracoDbContext(this IServiceCollection services, Action? optionsAction = null) instead.")]
public static IServiceCollection AddUmbracoEFCoreContext(this IServiceCollection services, string connectionString, string providerName, DefaultEFCoreOptionsAction? defaultEFCoreOptionsAction = null)
where T : DbContext
{
@@ -52,8 +56,8 @@ public static class UmbracoEFCoreServiceCollectionExtensions
services.TryAddSingleton>(
sp =>
{
- SetupDbContext(defaultEFCoreOptionsAction, sp, optionsBuilder);
- return new UmbracoPooledDbContextFactory(sp.GetRequiredService(),optionsBuilder.Options);
+ defaultEFCoreOptionsAction?.Invoke(optionsBuilder, providerName, connectionString);
+ return new UmbracoPooledDbContextFactory(sp.GetRequiredService(), optionsBuilder.Options);
});
services.AddPooledDbContextFactory(options => defaultEFCoreOptionsAction?.Invoke(options, providerName, connectionString));
services.AddTransient(services => services.GetRequiredService>().CreateDbContext());
@@ -67,12 +71,117 @@ public static class UmbracoEFCoreServiceCollectionExtensions
return services;
}
+ ///
+ /// Adds a EFCore DbContext with all the services needed to integrate with Umbraco scopes.
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static IServiceCollection AddUmbracoDbContext(this IServiceCollection services, Action? optionsAction = null)
+ where T : DbContext
+ {
+ return AddUmbracoDbContext(services, (IServiceProvider _, DbContextOptionsBuilder options) =>
+ {
+ optionsAction?.Invoke(options);
+ });
+ }
+
+ ///
+ /// Adds a EFCore DbContext with all the services needed to integrate with Umbraco scopes.
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static IServiceCollection AddUmbracoDbContext(this IServiceCollection services, Action? optionsAction = null)
+ where T : DbContext
+ {
+ optionsAction ??= (sp, options) => { };
+
+ var optionsBuilder = new DbContextOptionsBuilder();
+
+ services.TryAddSingleton>(sp =>
+ {
+ optionsAction.Invoke(sp, optionsBuilder);
+ return new UmbracoPooledDbContextFactory(sp.GetRequiredService(), optionsBuilder.Options);
+ });
+ services.AddPooledDbContextFactory(optionsAction);
+ services.AddTransient(services => services.GetRequiredService>().CreateDbContext());
+
+ services.AddUnique, AmbientEFCoreScopeStack>();
+ services.AddUnique, EFCoreScopeAccessor>();
+ services.AddUnique, EFCoreScopeProvider>();
+ services.AddSingleton>();
+ services.AddSingleton>();
+
+ return services;
+ }
+
+ ///
+ /// Sets the database provider. I.E UseSqlite or UseSqlServer based on the provider name.
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ /// Only supports the databases normally supported in Umbraco.
+ ///
+ public static void UseDatabaseProvider(this DbContextOptionsBuilder builder, string providerName, string connectionString)
+ {
+ switch (providerName)
+ {
+ case Constants.ProviderNames.SQLServer:
+ builder.UseSqlServer(connectionString);
+ break;
+ case Constants.ProviderNames.SQLLite:
+ builder.UseSqlite(connectionString);
+ break;
+ default:
+ throw new InvalidDataException($"The provider {providerName} is not supported. Manually add the add the UseXXX statement to the options. I.E UseNpgsql()");
+ }
+ }
+
+ ///
+ /// Sets the database provider to use based on the Umbraco connection string.
+ ///
+ ///
+ ///
+ public static void UseUmbracoDatabaseProvider(this DbContextOptionsBuilder builder, IServiceProvider serviceProvider)
+ {
+ ConnectionStrings connectionStrings = serviceProvider.GetRequiredService>().CurrentValue;
+
+ // Replace data directory
+ string? dataDirectory = AppDomain.CurrentDomain.GetData(Constants.System.DataDirectoryName)?.ToString();
+ if (string.IsNullOrEmpty(dataDirectory) is false)
+ {
+ connectionStrings.ConnectionString = connectionStrings.ConnectionString?.Replace(Constants.System.DataDirectoryPlaceholder, dataDirectory);
+ }
+
+ if (string.IsNullOrEmpty(connectionStrings.ProviderName))
+ {
+ Log.Warning("No database provider was set. ProviderName is null");
+ return;
+ }
+
+ if (string.IsNullOrEmpty(connectionStrings.ConnectionString))
+ {
+ Log.Warning("No database provider was set. Connection string is null");
+ return;
+ }
+
+ builder.UseDatabaseProvider(connectionStrings.ProviderName, connectionStrings.ConnectionString);
+ }
+
+ [Obsolete]
private static void SetupDbContext(DefaultEFCoreOptionsAction? defaultEFCoreOptionsAction, IServiceProvider provider, DbContextOptionsBuilder builder)
{
ConnectionStrings connectionStrings = GetConnectionStringAndProviderName(provider);
defaultEFCoreOptionsAction?.Invoke(builder, connectionStrings.ConnectionString, connectionStrings.ProviderName);
}
+ [Obsolete]
private static ConnectionStrings GetConnectionStringAndProviderName(IServiceProvider serviceProvider)
{
ConnectionStrings connectionStrings = serviceProvider.GetRequiredService>().CurrentValue;
diff --git a/src/Umbraco.Cms.Persistence.EFCore/UmbracoDbContext.cs b/src/Umbraco.Cms.Persistence.EFCore/UmbracoDbContext.cs
index 042cf2a52f..60e519de4c 100644
--- a/src/Umbraco.Cms.Persistence.EFCore/UmbracoDbContext.cs
+++ b/src/Umbraco.Cms.Persistence.EFCore/UmbracoDbContext.cs
@@ -3,7 +3,6 @@ using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
-using Umbraco.Cms.Core;
using Umbraco.Cms.Core.Configuration.Models;
using Umbraco.Cms.Core.DependencyInjection;
using Umbraco.Cms.Persistence.EFCore.Migrations;
@@ -77,7 +76,7 @@ public class UmbracoDbContext : DbContext
foreach (IMutableEntityType entity in modelBuilder.Model.GetEntityTypes())
{
- entity.SetTableName(Constants.DatabaseSchema.TableNamePrefix + entity.GetTableName());
+ entity.SetTableName(Core.Constants.DatabaseSchema.TableNamePrefix + entity.GetTableName());
}
}
}
diff --git a/src/Umbraco.Cms.Persistence.SqlServer/CompatibilitySuppressions.xml b/src/Umbraco.Cms.Persistence.SqlServer/CompatibilitySuppressions.xml
deleted file mode 100644
index d864a9d227..0000000000
--- a/src/Umbraco.Cms.Persistence.SqlServer/CompatibilitySuppressions.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-
-
- PKV006
- net7.0
-
-
\ No newline at end of file
diff --git a/src/Umbraco.Cms.Persistence.Sqlite/CompatibilitySuppressions.xml b/src/Umbraco.Cms.Persistence.Sqlite/CompatibilitySuppressions.xml
deleted file mode 100644
index d864a9d227..0000000000
--- a/src/Umbraco.Cms.Persistence.Sqlite/CompatibilitySuppressions.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-
-
- PKV006
- net7.0
-
-
\ No newline at end of file
diff --git a/src/Umbraco.Cms.StaticAssets/CompatibilitySuppressions.xml b/src/Umbraco.Cms.StaticAssets/CompatibilitySuppressions.xml
deleted file mode 100644
index d864a9d227..0000000000
--- a/src/Umbraco.Cms.StaticAssets/CompatibilitySuppressions.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-
-
- PKV006
- net7.0
-
-
\ No newline at end of file
diff --git a/src/Umbraco.Cms.StaticAssets/wwwroot/App_Plugins/Umbraco.BlockGridEditor.DefaultCustomViews/umbBlockGridDemoRichTextBlock.html b/src/Umbraco.Cms.StaticAssets/wwwroot/App_Plugins/Umbraco.BlockGridEditor.DefaultCustomViews/umbBlockGridDemoRichTextBlock.html
index b3362fcda9..adda418723 100644
--- a/src/Umbraco.Cms.StaticAssets/wwwroot/App_Plugins/Umbraco.BlockGridEditor.DefaultCustomViews/umbBlockGridDemoRichTextBlock.html
+++ b/src/Umbraco.Cms.StaticAssets/wwwroot/App_Plugins/Umbraco.BlockGridEditor.DefaultCustomViews/umbBlockGridDemoRichTextBlock.html
@@ -21,5 +21,5 @@
-
-
\ No newline at end of file
+
+
diff --git a/src/Umbraco.Core/CompatibilitySuppressions.xml b/src/Umbraco.Core/CompatibilitySuppressions.xml
deleted file mode 100644
index d864a9d227..0000000000
--- a/src/Umbraco.Core/CompatibilitySuppressions.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-
-
- PKV006
- net7.0
-
-
\ No newline at end of file
diff --git a/src/Umbraco.Core/Constants-ProviderNames.cs b/src/Umbraco.Core/Constants-ProviderNames.cs
new file mode 100644
index 0000000000..67f376612c
--- /dev/null
+++ b/src/Umbraco.Core/Constants-ProviderNames.cs
@@ -0,0 +1,11 @@
+namespace Umbraco.Cms.Core;
+
+public static partial class Constants
+{
+ public static class ProviderNames
+ {
+ public const string SQLLite = "Microsoft.Data.Sqlite";
+
+ public const string SQLServer = "Microsoft.Data.SqlClient";
+ }
+}
diff --git a/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.Collections.cs b/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.Collections.cs
index 3ec37df7f2..cd009600ed 100644
--- a/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.Collections.cs
+++ b/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.Collections.cs
@@ -36,9 +36,9 @@ public static partial class UmbracoBuilderExtensions
///
internal static void AddAllCoreCollectionBuilders(this IUmbracoBuilder builder)
{
- builder.CacheRefreshers().Add(() => builder.TypeLoader.GetCacheRefreshers());
- builder.DataEditors().Add(() => builder.TypeLoader.GetDataEditors());
- builder.Actions().Add(() => builder .TypeLoader.GetActions());
+ builder.CacheRefreshers().Add(builder.TypeLoader.GetCacheRefreshers);
+ builder.DataEditors().Add(builder.TypeLoader.GetDataEditors);
+ builder.Actions().Add(builder.TypeLoader.GetActions);
// register known content apps
builder.ContentApps()
@@ -242,14 +242,14 @@ public static partial class UmbracoBuilderExtensions
/// Gets the partial view snippets collection builder.
///
/// The builder.
- public static PartialViewSnippetCollectionBuilder? PartialViewSnippets(this IUmbracoBuilder builder)
+ public static PartialViewSnippetCollectionBuilder PartialViewSnippets(this IUmbracoBuilder builder)
=> builder.WithCollectionBuilder();
///
/// Gets the partial view macro snippets collection builder.
///
/// The builder.
- public static PartialViewMacroSnippetCollectionBuilder? PartialViewMacroSnippets(this IUmbracoBuilder builder)
+ public static PartialViewMacroSnippetCollectionBuilder PartialViewMacroSnippets(this IUmbracoBuilder builder)
=> builder.WithCollectionBuilder();
///
diff --git a/src/Umbraco.Core/Deploy/ArtifactDependency.cs b/src/Umbraco.Core/Deploy/ArtifactDependency.cs
index 07ba917dc2..31c8025ddb 100644
--- a/src/Umbraco.Core/Deploy/ArtifactDependency.cs
+++ b/src/Umbraco.Core/Deploy/ArtifactDependency.cs
@@ -1,42 +1,64 @@
+using System.Text.Json.Serialization;
+
namespace Umbraco.Cms.Core.Deploy;
///
-/// Represents an artifact dependency.
+/// Represents an artifact dependency.
///
///
-/// Dependencies have an order property which indicates whether it must be respected when ordering artifacts.
-///
-/// Dependencies have a mode which can be Match or Exist depending on whether the checksum should
-/// match.
-///
+///
+/// Dependencies have an order property which indicates whether it must be respected when ordering artifacts.
+///
+///
+/// Dependencies have a mode which can be or depending on whether the checksum should match.
+///
///
public class ArtifactDependency
{
///
- /// Initializes a new instance of the ArtifactDependency class with an entity identifier and a mode.
+ /// Initializes a new instance of the class.
///
- /// The entity identifier of the artifact that is a dependency.
+ /// The entity identifier of the artifact dependency.
/// A value indicating whether the dependency is ordering.
/// The dependency mode.
- public ArtifactDependency(Udi udi, bool ordering, ArtifactDependencyMode mode)
+ /// The checksum.
+ public ArtifactDependency(Udi udi, bool ordering, ArtifactDependencyMode mode, string? checksum = null)
{
Udi = udi;
Ordering = ordering;
Mode = mode;
+ Checksum = checksum;
}
///
- /// Gets the entity id of the artifact that is a dependency.
+ /// Gets the entity identifier of the artifact dependency.
///
+ ///
+ /// The entity identifier of the artifact dependency.
+ ///
public Udi Udi { get; }
///
- /// Gets a value indicating whether the dependency is ordering.
+ /// Gets a value indicating whether the dependency is ordering.
///
+ ///
+ /// true if the dependency is ordering; otherwise, false.
+ ///
public bool Ordering { get; }
///
- /// Gets the dependency mode.
+ /// Gets the dependency mode.
///
+ ///
+ /// The dependency mode.
+ ///
public ArtifactDependencyMode Mode { get; }
+
+ ///
+ /// Gets the checksum.
+ ///
+ ///
+ /// The checksum.
+ ///
+ public string? Checksum { get; }
}
diff --git a/src/Umbraco.Core/Deploy/DataTypeConfigurationConnectorExtensions.cs b/src/Umbraco.Core/Deploy/DataTypeConfigurationConnectorExtensions.cs
deleted file mode 100644
index dbd501d277..0000000000
--- a/src/Umbraco.Core/Deploy/DataTypeConfigurationConnectorExtensions.cs
+++ /dev/null
@@ -1,48 +0,0 @@
-using Umbraco.Cms.Core.Models;
-
-namespace Umbraco.Cms.Core.Deploy;
-
-///
-/// Extension methods adding backwards-compatability between and .
-///
-///
-/// These extension methods will be removed in Umbraco 13.
-///
-public static class DataTypeConfigurationConnectorExtensions
-{
- ///
- /// Gets the artifact configuration value corresponding to a data type configuration and gather dependencies.
- ///
- /// The connector.
- /// The data type.
- /// The dependencies.
- /// The context cache.
- ///
- /// The artifact configuration value.
- ///
- ///
- /// This extension method tries to make use of the on types also implementing .
- ///
- public static string? ToArtifact(this IDataTypeConfigurationConnector connector, IDataType dataType, ICollection dependencies, IContextCache contextCache)
- => connector is IDataTypeConfigurationConnector2 connector2
- ? connector2.ToArtifact(dataType, dependencies, contextCache)
- : connector.ToArtifact(dataType, dependencies);
-
- ///
- /// Gets the data type configuration corresponding to an artifact configuration value.
- ///
- /// The connector.
- /// The data type.
- /// The artifact configuration value.
- /// The context cache.
- ///
- /// The data type configuration.
- ///
- ///
- /// This extension method tries to make use of the on types also implementing .
- ///
- public static object? FromArtifact(this IDataTypeConfigurationConnector connector, IDataType dataType, string? configuration, IContextCache contextCache)
- => connector is IDataTypeConfigurationConnector2 connector2
- ? connector2.FromArtifact(dataType, configuration, contextCache)
- : connector.FromArtifact(dataType, configuration);
-}
diff --git a/src/Umbraco.Core/Deploy/IDataTypeConfigurationConnector.cs b/src/Umbraco.Core/Deploy/IDataTypeConfigurationConnector.cs
index 36302efd07..4cb0690d1f 100644
--- a/src/Umbraco.Core/Deploy/IDataTypeConfigurationConnector.cs
+++ b/src/Umbraco.Core/Deploy/IDataTypeConfigurationConnector.cs
@@ -24,20 +24,20 @@ public interface IDataTypeConfigurationConnector
///
/// The data type.
/// The dependencies.
+ /// The context cache.
///
/// The artifact configuration value.
///
- [Obsolete($"Implement {nameof(IDataTypeConfigurationConnector2)} and use the overload accepting {nameof(IContextCache)} instead. This overload will be removed in Umbraco 13.")]
- string? ToArtifact(IDataType dataType, ICollection dependencies);
+ string? ToArtifact(IDataType dataType, ICollection dependencies, IContextCache contextCache);
///
/// Gets the data type configuration corresponding to an artifact configuration value.
///
/// The data type.
/// The artifact configuration value.
+ /// The context cache.
///
/// The data type configuration.
///
- [Obsolete($"Implement {nameof(IDataTypeConfigurationConnector2)} and use the overload accepting {nameof(IContextCache)} instead. This overload will be removed in Umbraco 13.")]
- object? FromArtifact(IDataType dataType, string? configuration);
+ object? FromArtifact(IDataType dataType, string? configuration, IContextCache contextCache);
}
diff --git a/src/Umbraco.Core/Deploy/IDataTypeConfigurationConnector2.cs b/src/Umbraco.Core/Deploy/IDataTypeConfigurationConnector2.cs
deleted file mode 100644
index 772bc35dc4..0000000000
--- a/src/Umbraco.Core/Deploy/IDataTypeConfigurationConnector2.cs
+++ /dev/null
@@ -1,56 +0,0 @@
-using Umbraco.Cms.Core.Models;
-
-namespace Umbraco.Cms.Core.Deploy;
-
-///
-///
-/// This interface will be merged back into and removed in Umbraco 13.
-///
-public interface IDataTypeConfigurationConnector2 : IDataTypeConfigurationConnector
-{
- ///
- /// Gets the artifact configuration value corresponding to a data type configuration and gather dependencies.
- ///
- /// The data type.
- /// The dependencies.
- ///
- /// The artifact configuration value.
- ///
- [Obsolete($"Use the overload accepting {nameof(IContextCache)} instead. This overload will be removed in Umbraco 13.")]
- string? IDataTypeConfigurationConnector.ToArtifact(IDataType dataType, ICollection dependencies)
- => ToArtifact(dataType, dependencies, PassThroughCache.Instance);
-
- ///
- /// Gets the artifact configuration value corresponding to a data type configuration and gather dependencies.
- ///
- /// The data type.
- /// The dependencies.
- /// The context cache.
- ///
- /// The artifact configuration value.
- ///
- string? ToArtifact(IDataType dataType, ICollection dependencies, IContextCache contextCache);
-
- ///
- /// Gets the data type configuration corresponding to an artifact configuration value.
- ///
- /// The data type.
- /// The artifact configuration value.
- ///
- /// The data type configuration.
- ///
- [Obsolete($"Use the overload accepting {nameof(IContextCache)} instead. This overload will be removed in Umbraco 13.")]
- object? IDataTypeConfigurationConnector.FromArtifact(IDataType dataType, string? configuration)
- => FromArtifact(dataType, configuration, PassThroughCache.Instance);
-
- ///
- /// Gets the data type configuration corresponding to an artifact configuration value.
- ///
- /// The data type.
- /// The artifact configuration value.
- /// The context cache.
- ///
- /// The data type configuration.
- ///
- object? FromArtifact(IDataType dataType, string? configuration, IContextCache contextCache);
-}
diff --git a/src/Umbraco.Core/Deploy/IServiceConnector.cs b/src/Umbraco.Core/Deploy/IServiceConnector.cs
index adf4c57502..84617943c6 100644
--- a/src/Umbraco.Core/Deploy/IServiceConnector.cs
+++ b/src/Umbraco.Core/Deploy/IServiceConnector.cs
@@ -12,21 +12,21 @@ public interface IServiceConnector : IDiscoverable
/// Gets an artifact.
///
/// The entity identifier of the artifact.
+ /// The context cache.
///
/// The corresponding artifact, or null.
///
- [Obsolete($"Implement {nameof(IServiceConnector2)} and use the overload accepting {nameof(IContextCache)} instead. This overload will be removed in Umbraco 13.")]
- IArtifact? GetArtifact(Udi udi);
+ IArtifact? GetArtifact(Udi udi, IContextCache contextCache);
///
/// Gets an artifact.
///
/// The entity.
+ /// The context cache.
///
/// The corresponding artifact.
///
- [Obsolete($"Implement {nameof(IServiceConnector2)} and use the overload accepting {nameof(IContextCache)} instead. This overload will be removed in Umbraco 13.")]
- IArtifact GetArtifact(object entity);
+ IArtifact GetArtifact(object entity, IContextCache contextCache);
///
/// Initializes processing for an artifact.
@@ -47,10 +47,10 @@ public interface IServiceConnector : IDiscoverable
void Process(ArtifactDeployState dart, IDeployContext context, int pass);
///
- /// Explodes a range into udis.
+ /// Explodes a range into UDIs.
///
/// The range.
- /// The list of udis where to add the new udis.
+ /// The list of UDIs where to add the new UDIs.
///
/// Also, it's cool to have a method named Explode. Kaboom!
///
@@ -78,9 +78,9 @@ public interface IServiceConnector : IDiscoverable
///
/// This is temporary. At least we thought it would be, in sept. 2016. What day is it now?
///
- /// At the moment our UI has a hard time returning proper udis, mainly because Core's tree do
- /// not manage guids but only ints... so we have to provide a way to support it. The string id here
- /// can be either a real string (for string udis) or an "integer as a string", using the value "-1" to
+ /// At the moment our UI has a hard time returning proper UDIs, mainly because Core's tree do
+ /// not manage GUIDs but only integers... so we have to provide a way to support it. The string id here
+ /// can be either a real string (for string UDIs) or an "integer as a string", using the value "-1" to
/// indicate the "root" i.e. an open udi.
///
///
diff --git a/src/Umbraco.Core/Deploy/IServiceConnector2.cs b/src/Umbraco.Core/Deploy/IServiceConnector2.cs
deleted file mode 100644
index 6c1558a956..0000000000
--- a/src/Umbraco.Core/Deploy/IServiceConnector2.cs
+++ /dev/null
@@ -1,38 +0,0 @@
-namespace Umbraco.Cms.Core.Deploy;
-
-///
-///
-/// This interface will be merged back into and removed in Umbraco 13.
-///
-public interface IServiceConnector2 : IServiceConnector
-{
- ///
- [Obsolete($"Use the overload accepting {nameof(IContextCache)} instead. This overload will be removed in Umbraco 13.")]
- IArtifact? IServiceConnector.GetArtifact(Udi udi)
- => GetArtifact(udi, PassThroughCache.Instance);
-
- ///
- /// Gets an artifact.
- ///
- /// The entity identifier of the artifact.
- /// The context cache.
- ///
- /// The corresponding artifact, or null.
- ///
- IArtifact? GetArtifact(Udi udi, IContextCache contextCache);
-
- ///
- [Obsolete($"Use the overload accepting {nameof(IContextCache)} instead. This overload will be removed in Umbraco 13.")]
- IArtifact IServiceConnector.GetArtifact(object entity)
- => GetArtifact(entity, PassThroughCache.Instance);
-
- ///
- /// Gets an artifact.
- ///
- /// The entity.
- /// The context cache.
- ///
- /// The corresponding artifact.
- ///
- IArtifact GetArtifact(object entity, IContextCache contextCache);
-}
diff --git a/src/Umbraco.Core/Deploy/IValueConnector.cs b/src/Umbraco.Core/Deploy/IValueConnector.cs
index fe28e41017..5e5e2da1a4 100644
--- a/src/Umbraco.Core/Deploy/IValueConnector.cs
+++ b/src/Umbraco.Core/Deploy/IValueConnector.cs
@@ -26,11 +26,11 @@ public interface IValueConnector
/// The content property value.
/// The value property type
/// The content dependencies.
+ /// The context cache.
///
/// The deploy property value.
///
- [Obsolete($"Implement {nameof(IValueConnector2)} and use the overload accepting {nameof(IContextCache)} instead. This overload will be removed in Umbraco 13.")]
- string? ToArtifact(object? value, IPropertyType propertyType, ICollection dependencies);
+ string? ToArtifact(object? value, IPropertyType propertyType, ICollection dependencies, IContextCache contextCache);
///
/// Gets the content property value corresponding to a deploy property value.
@@ -38,9 +38,9 @@ public interface IValueConnector
/// The deploy property value.
/// The value property type
/// The current content property value.
+ /// The context cache.
///
/// The content property value.
///
- [Obsolete($"Implement {nameof(IValueConnector2)} and use the overload accepting {nameof(IContextCache)} instead. This overload will be removed in Umbraco 13.")]
- object? FromArtifact(string? value, IPropertyType propertyType, object? currentValue);
+ object? FromArtifact(string? value, IPropertyType propertyType, object? currentValue, IContextCache contextCache);
}
diff --git a/src/Umbraco.Core/Deploy/IValueConnector2.cs b/src/Umbraco.Core/Deploy/IValueConnector2.cs
deleted file mode 100644
index a0c99dca06..0000000000
--- a/src/Umbraco.Core/Deploy/IValueConnector2.cs
+++ /dev/null
@@ -1,44 +0,0 @@
-using Umbraco.Cms.Core.Models;
-
-namespace Umbraco.Cms.Core.Deploy;
-
-///
-///
-/// This interface will be merged back into and removed in Umbraco 13.
-///
-public interface IValueConnector2 : IValueConnector
-{
- ///
- [Obsolete($"Use the overload accepting {nameof(IContextCache)} instead. This overload will be removed in Umbraco 13.")]
- string? IValueConnector.ToArtifact(object? value, IPropertyType propertyType, ICollection dependencies)
- => ToArtifact(value, propertyType, dependencies, PassThroughCache.Instance);
-
- ///
- /// Gets the deploy property value corresponding to a content property value, and gather dependencies.
- ///
- /// The content property value.
- /// The value property type
- /// The content dependencies.
- /// The context cache.
- ///
- /// The deploy property value.
- ///
- string? ToArtifact(object? value, IPropertyType propertyType, ICollection dependencies, IContextCache contextCache);
-
- ///
- [Obsolete($"Use the overload accepting {nameof(IContextCache)} instead. This overload will be removed in Umbraco 13.")]
- object? IValueConnector.FromArtifact(string? value, IPropertyType propertyType, object? currentValue)
- => FromArtifact(value, propertyType, currentValue, PassThroughCache.Instance);
-
- ///
- /// Gets the content property value corresponding to a deploy property value.
- ///
- /// The deploy property value.
- /// The value property type
- /// The current content property value.
- /// The context cache.
- ///
- /// The content property value.
- ///
- object? FromArtifact(string? value, IPropertyType propertyType, object? currentValue, IContextCache contextCache);
-}
diff --git a/src/Umbraco.Core/Deploy/ServiceConnectorExtensions.cs b/src/Umbraco.Core/Deploy/ServiceConnectorExtensions.cs
deleted file mode 100644
index 0d0000f97c..0000000000
--- a/src/Umbraco.Core/Deploy/ServiceConnectorExtensions.cs
+++ /dev/null
@@ -1,44 +0,0 @@
-namespace Umbraco.Cms.Core.Deploy;
-
-///
-/// Extension methods adding backwards-compatability between and .
-///
-///
-/// These extension methods will be removed in Umbraco 13.
-///
-public static class ServiceConnectorExtensions
-{
- ///
- /// Gets an artifact.
- ///
- /// The connector.
- /// The entity identifier of the artifact.
- /// The context cache.
- ///
- /// The corresponding artifact, or null.
- ///
- ///
- /// This extension method tries to make use of the on types also implementing .
- ///
- public static IArtifact? GetArtifact(this IServiceConnector connector, Udi udi, IContextCache contextCache)
- => connector is IServiceConnector2 connector2
- ? connector2.GetArtifact(udi, contextCache)
- : connector.GetArtifact(udi);
-
- ///
- /// Gets an artifact.
- ///
- /// The connector.
- /// The entity.
- /// The context cache.
- ///
- /// The corresponding artifact.
- ///
- ///
- /// This extension method tries to make use of the on types also implementing .
- ///
- public static IArtifact GetArtifact(this IServiceConnector connector, object entity, IContextCache contextCache)
- => connector is IServiceConnector2 connector2
- ? connector2.GetArtifact(entity, contextCache)
- : connector.GetArtifact(entity);
-}
diff --git a/src/Umbraco.Core/Deploy/ValueConnectorExtensions.cs b/src/Umbraco.Core/Deploy/ValueConnectorExtensions.cs
deleted file mode 100644
index eadcee55e0..0000000000
--- a/src/Umbraco.Core/Deploy/ValueConnectorExtensions.cs
+++ /dev/null
@@ -1,50 +0,0 @@
-using Umbraco.Cms.Core.Models;
-
-namespace Umbraco.Cms.Core.Deploy;
-
-///
-/// Extension methods adding backwards-compatability between and .
-///
-///
-/// These extension methods will be removed in Umbraco 13.
-///
-public static class ValueConnectorExtensions
-{
- ///
- /// Gets the artifact value corresponding to a property value and gather dependencies.
- ///
- /// The connector.
- /// The property value.
- /// The property type.
- /// The dependencies.
- /// The context cache.
- ///
- /// The artifact value.
- ///
- ///
- /// This extension method tries to make use of the on types also implementing .
- ///
- public static string? ToArtifact(this IValueConnector connector, object? value, IPropertyType propertyType, ICollection dependencies, IContextCache contextCache)
- => connector is IValueConnector2 connector2
- ? connector2.ToArtifact(value, propertyType, dependencies, contextCache)
- : connector.ToArtifact(value, propertyType, dependencies);
-
- ///
- /// Gets the property value corresponding to an artifact value.
- ///
- /// The connector.
- /// The artifact value.
- /// The property type.
- /// The current property value.
- /// The context cache.
- ///
- /// The property value.
- ///
- ///
- /// This extension method tries to make use of the on types also implementing .
- ///
- public static object? FromArtifact(this IValueConnector connector, string? value, IPropertyType propertyType, object? currentValue, IContextCache contextCache)
- => connector is IValueConnector2 connector2
- ? connector2.FromArtifact(value, propertyType, currentValue, contextCache)
- : connector.FromArtifact(value, propertyType, currentValue);
-}
diff --git a/src/Umbraco.Core/PropertyEditors/DataValueReferenceFactoryCollection.cs b/src/Umbraco.Core/PropertyEditors/DataValueReferenceFactoryCollection.cs
index 24d6f17eb0..c605d45a9a 100644
--- a/src/Umbraco.Core/PropertyEditors/DataValueReferenceFactoryCollection.cs
+++ b/src/Umbraco.Core/PropertyEditors/DataValueReferenceFactoryCollection.cs
@@ -8,60 +8,119 @@ public class DataValueReferenceFactoryCollection : BuilderCollectionBase> items)
: base(items)
- {
- }
+ { }
// TODO: We could further reduce circular dependencies with PropertyEditorCollection by not having IDataValueReference implemented
// by property editors and instead just use the already built in IDataValueReferenceFactory and/or refactor that into a more normal collection
- public IEnumerable GetAllReferences(
- IPropertyCollection properties,
- PropertyEditorCollection propertyEditors)
+ public ISet GetAllReferences(IPropertyCollection properties, PropertyEditorCollection propertyEditors)
{
- var trackedRelations = new HashSet();
+ var references = new HashSet();
- foreach (IProperty p in properties)
+ foreach (IProperty property in properties)
{
- if (!propertyEditors.TryGet(p.PropertyType.PropertyEditorAlias, out IDataEditor? editor))
+ if (!propertyEditors.TryGet(property.PropertyType.PropertyEditorAlias, out IDataEditor? dataEditor))
{
continue;
}
// TODO: We will need to change this once we support tracking via variants/segments
// for now, we are tracking values from ALL variants
- foreach (IPropertyValue propertyVal in p.Values)
+ foreach (IPropertyValue propertyValue in property.Values)
{
- var val = propertyVal.EditedValue;
+ object? value = propertyValue.EditedValue;
- IDataValueEditor? valueEditor = editor?.GetValueEditor();
- if (valueEditor is IDataValueReference reference)
+ if (dataEditor.GetValueEditor() is IDataValueReference dataValueReference)
{
- IEnumerable refs = reference.GetReferences(val);
- foreach (UmbracoEntityReference r in refs)
- {
- trackedRelations.Add(r);
- }
+ references.UnionWith(dataValueReference.GetReferences(value));
}
// Loop over collection that may be add to existing property editors
// implementation of GetReferences in IDataValueReference.
// Allows developers to add support for references by a
// package /property editor that did not implement IDataValueReference themselves
- foreach (IDataValueReferenceFactory item in this)
+ foreach (IDataValueReferenceFactory dataValueReferenceFactory in this)
{
// Check if this value reference is for this datatype/editor
// Then call it's GetReferences method - to see if the value stored
- // in the dataeditor/property has referecnes to media/content items
- if (item.IsForEditor(editor))
+ // in the dataeditor/property has references to media/content items
+ if (dataValueReferenceFactory.IsForEditor(dataEditor))
{
- foreach (UmbracoEntityReference r in item.GetDataValueReference().GetReferences(val))
- {
- trackedRelations.Add(r);
- }
+ references.UnionWith(dataValueReferenceFactory.GetDataValueReference().GetReferences(value));
}
}
}
}
- return trackedRelations;
+ return references;
+ }
+
+ ///
+ /// Gets all relation type aliases that are automatically tracked.
+ ///
+ /// The property editors.
+ ///
+ /// All relation type aliases that are automatically tracked.
+ ///
+ public ISet GetAutomaticRelationTypesAliases(PropertyEditorCollection propertyEditors)
+ {
+ // Always add default automatic relation types
+ var automaticRelationTypeAliases = new HashSet(Constants.Conventions.RelationTypes.AutomaticRelationTypes);
+
+ // Add relation types for all property editors
+ foreach (IDataEditor dataEditor in propertyEditors)
+ {
+ automaticRelationTypeAliases.UnionWith(GetAutomaticRelationTypesAliases(dataEditor));
+ }
+
+ return automaticRelationTypeAliases;
+ }
+
+ ///
+ /// Gets the relation type aliases that are automatically tracked for all properties.
+ ///
+ /// The properties.
+ /// The property editors.
+ ///
+ /// The relation type aliases that are automatically tracked for all properties.
+ ///
+ public ISet GetAutomaticRelationTypesAliases(IPropertyCollection properties, PropertyEditorCollection propertyEditors)
+ {
+ // Always add default automatic relation types
+ var automaticRelationTypeAliases = new HashSet(Constants.Conventions.RelationTypes.AutomaticRelationTypes);
+
+ // Only add relation types that are used in the properties
+ foreach (IProperty property in properties)
+ {
+ if (propertyEditors.TryGet(property.PropertyType.PropertyEditorAlias, out IDataEditor? dataEditor))
+ {
+ automaticRelationTypeAliases.UnionWith(GetAutomaticRelationTypesAliases(dataEditor));
+ }
+ }
+
+ return automaticRelationTypeAliases;
+ }
+
+ private IEnumerable GetAutomaticRelationTypesAliases(IDataEditor dataEditor)
+ {
+ if (dataEditor.GetValueEditor() is IDataValueReference dataValueReference)
+ {
+ // Return custom relation types from value editor implementation
+ foreach (var alias in dataValueReference.GetAutomaticRelationTypesAliases())
+ {
+ yield return alias;
+ }
+ }
+
+ foreach (IDataValueReferenceFactory dataValueReferenceFactory in this)
+ {
+ if (dataValueReferenceFactory.IsForEditor(dataEditor))
+ {
+ // Return custom relation types from factory
+ foreach (var alias in dataValueReferenceFactory.GetDataValueReference().GetAutomaticRelationTypesAliases())
+ {
+ yield return alias;
+ }
+ }
+ }
}
}
diff --git a/src/Umbraco.Core/PublishedCache/IPublishedSnapshotService.cs b/src/Umbraco.Core/PublishedCache/IPublishedSnapshotService.cs
index 5bd5ff23cc..8e661aa758 100644
--- a/src/Umbraco.Core/PublishedCache/IPublishedSnapshotService.cs
+++ b/src/Umbraco.Core/PublishedCache/IPublishedSnapshotService.cs
@@ -125,4 +125,8 @@ public interface IPublishedSnapshotService : IDisposable
/// Cleans up unused snapshots
///
Task CollectAsync();
+
+ void ResetLocalDb()
+ {
+ }
}
diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj
index 8cdb0d2b82..4f4dd097b1 100644
--- a/src/Umbraco.Core/Umbraco.Core.csproj
+++ b/src/Umbraco.Core/Umbraco.Core.csproj
@@ -16,18 +16,9 @@
-
-
-
-
-
-
-
-
-
<_Parameter1>Umbraco.Tests
diff --git a/src/Umbraco.Core/Webhooks/IWebhookEvent.cs b/src/Umbraco.Core/Webhooks/IWebhookEvent.cs
index 85857c1aec..954055d104 100644
--- a/src/Umbraco.Core/Webhooks/IWebhookEvent.cs
+++ b/src/Umbraco.Core/Webhooks/IWebhookEvent.cs
@@ -2,5 +2,5 @@
public interface IWebhookEvent
{
- string EventName { get; set; }
+ string EventName { get; }
}
diff --git a/src/Umbraco.Examine.Lucene/CompatibilitySuppressions.xml b/src/Umbraco.Examine.Lucene/CompatibilitySuppressions.xml
deleted file mode 100644
index d864a9d227..0000000000
--- a/src/Umbraco.Examine.Lucene/CompatibilitySuppressions.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-
-
- PKV006
- net7.0
-
-
\ No newline at end of file
diff --git a/src/Umbraco.Infrastructure/CompatibilitySuppressions.xml b/src/Umbraco.Infrastructure/CompatibilitySuppressions.xml
deleted file mode 100644
index d864a9d227..0000000000
--- a/src/Umbraco.Infrastructure/CompatibilitySuppressions.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-
-
- PKV006
- net7.0
-
-
\ No newline at end of file
diff --git a/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.Collections.cs b/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.Collections.cs
index 609c5305dc..0dd42485a2 100644
--- a/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.Collections.cs
+++ b/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.Collections.cs
@@ -15,21 +15,21 @@ public static partial class UmbracoBuilderExtensions
/// Gets the mappers collection builder.
///
/// The builder.
- public static MapperCollectionBuilder? Mappers(this IUmbracoBuilder builder)
+ public static MapperCollectionBuilder Mappers(this IUmbracoBuilder builder)
=> builder.WithCollectionBuilder();
///
/// Gets the NPoco mappers collection builder.
///
/// The builder.
- public static NPocoMapperCollectionBuilder? NPocoMappers(this IUmbracoBuilder builder)
+ public static NPocoMapperCollectionBuilder NPocoMappers(this IUmbracoBuilder builder)
=> builder.WithCollectionBuilder();
///
/// Gets the package migration plans collection builder.
///
/// The builder.
- public static PackageMigrationPlanCollectionBuilder? PackageMigrationPlans(this IUmbracoBuilder builder)
+ public static PackageMigrationPlanCollectionBuilder PackageMigrationPlans(this IUmbracoBuilder builder)
=> builder.WithCollectionBuilder();
///
diff --git a/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.CoreServices.cs b/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.CoreServices.cs
index 373c4a2008..1dff6e7eeb 100644
--- a/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.CoreServices.cs
+++ b/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.CoreServices.cs
@@ -78,8 +78,8 @@ public static partial class UmbracoBuilderExtensions
builder.Services.AddSingleton();
builder.Services.AddSingleton();
builder.Services.AddSingleton(factory => factory.GetRequiredService().SqlContext);
- builder.NPocoMappers()?.Add();
- builder.PackageMigrationPlans()?.Add(() => builder.TypeLoader.GetPackageMigrationPlans());
+ builder.NPocoMappers().Add();
+ builder.PackageMigrationPlans().Add(builder.TypeLoader.GetPackageMigrationPlans());
builder.Services.AddSingleton();
builder.Services.AddSingleton();
@@ -107,7 +107,7 @@ public static partial class UmbracoBuilderExtensions
// register persistence mappers - required by database factory so needs to be done here
// means the only place the collection can be modified is in a runtime - afterwards it
// has been frozen and it is too late
- builder.Mappers()?.AddCoreMappers();
+ builder.Mappers().AddCoreMappers();
// register the scope provider
builder.Services.AddSingleton(sp => ActivatorUtilities.CreateInstance(sp, sp.GetRequiredService())); // implements IScopeProvider, IScopeAccessor
diff --git a/src/Umbraco.Infrastructure/Migrations/Upgrade/V_12_0_0/ResetCache.cs b/src/Umbraco.Infrastructure/Migrations/Upgrade/V_12_0_0/ResetCache.cs
index b55b4c4ca7..0e41ad89ca 100644
--- a/src/Umbraco.Infrastructure/Migrations/Upgrade/V_12_0_0/ResetCache.cs
+++ b/src/Umbraco.Infrastructure/Migrations/Upgrade/V_12_0_0/ResetCache.cs
@@ -1,22 +1,34 @@
-using IHostingEnvironment = Umbraco.Cms.Core.Hosting.IHostingEnvironment;
+using Microsoft.Extensions.DependencyInjection;
+using Umbraco.Cms.Core.DependencyInjection;
+using Umbraco.Cms.Core.PublishedCache;
+using IHostingEnvironment = Umbraco.Cms.Core.Hosting.IHostingEnvironment;
namespace Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_12_0_0;
public class ResetCache : MigrationBase
{
private readonly IHostingEnvironment _hostingEnvironment;
+ private readonly IPublishedSnapshotService _publishedSnapshotService;
+ [Obsolete("Use ctor with all params - This will be removed in Umbraco 14.")]
public ResetCache(IMigrationContext context, IHostingEnvironment hostingEnvironment)
- : base(context) =>
+ : this(context, hostingEnvironment, StaticServiceProvider.Instance.GetRequiredService())
+ {
+ }
+
+ public ResetCache(IMigrationContext context, IHostingEnvironment hostingEnvironment, IPublishedSnapshotService publishedSnapshotService)
+ : base(context)
+ {
_hostingEnvironment = hostingEnvironment;
+ _publishedSnapshotService = publishedSnapshotService;
+ }
protected override void Migrate()
{
RebuildCache = true;
var distCacheFolderAbsolutePath = Path.Combine(_hostingEnvironment.LocalTempPath, "DistCache");
- var nuCacheFolderAbsolutePath = Path.Combine(_hostingEnvironment.LocalTempPath, "NuCache");
DeleteAllFilesInFolder(distCacheFolderAbsolutePath);
- DeleteAllFilesInFolder(nuCacheFolderAbsolutePath);
+ _publishedSnapshotService.ResetLocalDb();
}
private void DeleteAllFilesInFolder(string path)
diff --git a/src/Umbraco.Infrastructure/Packaging/PackageMigrationPlanCollectionBuilder.cs b/src/Umbraco.Infrastructure/Packaging/PackageMigrationPlanCollectionBuilder.cs
index 91b1364139..324257286e 100644
--- a/src/Umbraco.Infrastructure/Packaging/PackageMigrationPlanCollectionBuilder.cs
+++ b/src/Umbraco.Infrastructure/Packaging/PackageMigrationPlanCollectionBuilder.cs
@@ -2,7 +2,7 @@ using Umbraco.Cms.Core.Composing;
namespace Umbraco.Cms.Core.Packaging;
-public class PackageMigrationPlanCollectionBuilder : LazyCollectionBuilderBase
{
protected override PackageMigrationPlanCollectionBuilder This => this;
diff --git a/src/Umbraco.Infrastructure/Persistence/Dtos/AccessDto.cs b/src/Umbraco.Infrastructure/Persistence/Dtos/AccessDto.cs
index 354083dfa8..0821232826 100644
--- a/src/Umbraco.Infrastructure/Persistence/Dtos/AccessDto.cs
+++ b/src/Umbraco.Infrastructure/Persistence/Dtos/AccessDto.cs
@@ -37,5 +37,5 @@ internal class AccessDto
[ResultColumn]
[Reference(ReferenceType.Many, ReferenceMemberName = "AccessId")]
- public List Rules { get; set; } = null!;
+ public List Rules { get; set; } = new();
}
diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ContentRepositoryBase.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ContentRepositoryBase.cs
index de247a6120..fde1c6ca05 100644
--- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ContentRepositoryBase.cs
+++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ContentRepositoryBase.cs
@@ -1083,13 +1083,11 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement
protected void PersistRelations(TEntity entity)
{
// Get all references from our core built in DataEditors/Property Editors
- // Along with seeing if deverlopers want to collect additional references from the DataValueReferenceFactories collection
- var trackedRelations = new List();
- trackedRelations.AddRange(_dataValueReferenceFactories.GetAllReferences(entity.Properties, PropertyEditors));
-
- var relationTypeAliases = GetAutomaticRelationTypesAliases(entity.Properties, PropertyEditors).ToArray();
+ // Along with seeing if developers want to collect additional references from the DataValueReferenceFactories collection
+ var trackedRelations = _dataValueReferenceFactories.GetAllReferences(entity.Properties, PropertyEditors);
// First delete all auto-relations for this entity
+ var relationTypeAliases = _dataValueReferenceFactories.GetAutomaticRelationTypesAliases(entity.Properties, PropertyEditors).ToArray();
RelationRepository.DeleteByParent(entity.Id, relationTypeAliases);
if (trackedRelations.Count == 0)
@@ -1097,23 +1095,20 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement
return;
}
- trackedRelations = trackedRelations.Distinct().ToList();
- var udiToGuids = trackedRelations.Select(x => x.Udi as GuidUdi)
- .ToDictionary(x => (Udi)x!, x => x!.Guid);
+ var udiToGuids = trackedRelations.Select(x => x.Udi as GuidUdi).WhereNotNull().ToDictionary(x => (Udi)x, x => x.Guid);
// lookup in the DB all INT ids for the GUIDs and chuck into a dictionary
- var keyToIds = Database.Fetch(Sql()
+ var keyToIds = Database.FetchByGroups(udiToGuids.Values, Constants.Sql.MaxParameterCount, guids => Sql()
.Select(x => x.NodeId, x => x.UniqueId)
.From()
- .WhereIn(x => x.UniqueId, udiToGuids.Values))
+ .WhereIn(x => x.UniqueId, guids))
.ToDictionary(x => x.UniqueId, x => x.NodeId);
- var allRelationTypes = RelationTypeRepository.GetMany(Array.Empty())?
- .ToDictionary(x => x.Alias, x => x);
+ var allRelationTypes = RelationTypeRepository.GetMany(Array.Empty()).ToDictionary(x => x.Alias, x => x);
IEnumerable toSave = trackedRelations.Select(rel =>
{
- if (allRelationTypes is null || !allRelationTypes.TryGetValue(rel.RelationTypeAlias, out IRelationType? relationType))
+ if (!allRelationTypes.TryGetValue(rel.RelationTypeAlias, out IRelationType? relationType))
{
throw new InvalidOperationException($"The relation type {rel.RelationTypeAlias} does not exist");
}
@@ -1135,31 +1130,6 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement
RelationRepository.SaveBulk(toSave);
}
- private IEnumerable GetAutomaticRelationTypesAliases(
- IPropertyCollection properties,
- PropertyEditorCollection propertyEditors)
- {
- var automaticRelationTypesAliases = new HashSet(Constants.Conventions.RelationTypes.AutomaticRelationTypes);
-
- foreach (IProperty property in properties)
- {
- if (propertyEditors.TryGet(property.PropertyType.PropertyEditorAlias, out IDataEditor? editor) is false )
- {
- continue;
- }
-
- if (editor.GetValueEditor() is IDataValueReference reference)
- {
- foreach (var alias in reference.GetAutomaticRelationTypesAliases())
- {
- automaticRelationTypesAliases.Add(alias);
- }
- }
- }
-
- return automaticRelationTypesAliases;
- }
-
///
/// Inserts property values for the content entity
///
diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ContentTypeRepositoryBase.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ContentTypeRepositoryBase.cs
index 3e92a4ae7f..59aa92bb82 100644
--- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ContentTypeRepositoryBase.cs
+++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ContentTypeRepositoryBase.cs
@@ -1385,10 +1385,15 @@ AND umbracoNode.id <> @id",
}
// Now bulk update the umbracoDocument table
- foreach (IGrouping> editValue in editedDocument.GroupBy(x => x.Value))
+ // we need to do this in batches as the WhereIn Npoco method translates to all the nodeIds being passed in as parameters when using the SqlClient provider
+ // this results in to many parameters (>2100) being passed to the client when there are a lot of documents being normalized
+ foreach (IGrouping> groupByValue in editedDocument.GroupBy(x => x.Value))
{
- Database.Execute(Sql().Update(u => u.Set(x => x.Edited, editValue.Key))
- .WhereIn(x => x.NodeId, editValue.Select(x => x.Key)));
+ foreach (IEnumerable> batch in groupByValue.InGroupsOf(2000))
+ {
+ Database.Execute(Sql().Update(u => u.Set(x => x.Edited, groupByValue.Key))
+ .WhereIn(x => x.NodeId, batch.Select(x => x.Key)));
+ }
}
}
diff --git a/src/Umbraco.Infrastructure/Umbraco.Infrastructure.csproj b/src/Umbraco.Infrastructure/Umbraco.Infrastructure.csproj
index 80d19e7a94..1c2e897ebc 100644
--- a/src/Umbraco.Infrastructure/Umbraco.Infrastructure.csproj
+++ b/src/Umbraco.Infrastructure/Umbraco.Infrastructure.csproj
@@ -37,9 +37,6 @@
-
-
-
diff --git a/src/Umbraco.PublishedCache.NuCache/CompatibilitySuppressions.xml b/src/Umbraco.PublishedCache.NuCache/CompatibilitySuppressions.xml
deleted file mode 100644
index d864a9d227..0000000000
--- a/src/Umbraco.PublishedCache.NuCache/CompatibilitySuppressions.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-
-
- PKV006
- net7.0
-
-
\ No newline at end of file
diff --git a/src/Umbraco.PublishedCache.NuCache/Property.cs b/src/Umbraco.PublishedCache.NuCache/Property.cs
index d921eb3f7c..6a9e1a982c 100644
--- a/src/Umbraco.PublishedCache.NuCache/Property.cs
+++ b/src/Umbraco.PublishedCache.NuCache/Property.cs
@@ -25,6 +25,7 @@ internal class Property : PublishedPropertyBase
// the invariant-neutral source and inter values
private readonly object? _sourceValue;
private readonly ContentVariation _variations;
+ private bool _sourceValueIsInvariant;
// the variant and non-variant object values
private CacheValues? _cacheValues;
@@ -89,6 +90,7 @@ internal class Property : PublishedPropertyBase
// this variable is used for contextualizing the variation level when calculating property values.
// it must be set to the union of variance (the combination of content type and property type variance).
_variations = propertyType.Variations | content.ContentType.Variations;
+ _sourceValueIsInvariant = propertyType.Variations is ContentVariation.Nothing;
}
// clone for previewing as draft a published content that is published and has no draft
@@ -104,6 +106,7 @@ internal class Property : PublishedPropertyBase
_isMember = origin._isMember;
_publishedSnapshotAccessor = origin._publishedSnapshotAccessor;
_variations = origin._variations;
+ _sourceValueIsInvariant = origin._sourceValueIsInvariant;
}
// used to cache the CacheValues of this property
@@ -152,7 +155,7 @@ internal class Property : PublishedPropertyBase
{
_content.VariationContextAccessor.ContextualizeVariation(_variations, _content.Id, ref culture, ref segment);
- if (culture == string.Empty && segment == string.Empty)
+ if (_sourceValueIsInvariant || (culture == string.Empty && segment == string.Empty))
{
return _sourceValue;
}
diff --git a/src/Umbraco.PublishedCache.NuCache/PublishedSnapshotService.cs b/src/Umbraco.PublishedCache.NuCache/PublishedSnapshotService.cs
index 68b50cfd91..a7f8c42823 100644
--- a/src/Umbraco.PublishedCache.NuCache/PublishedSnapshotService.cs
+++ b/src/Umbraco.PublishedCache.NuCache/PublishedSnapshotService.cs
@@ -70,6 +70,8 @@ internal class PublishedSnapshotService : IPublishedSnapshotService
private long _mediaGen;
private ContentStore _mediaStore = null!;
+ private string LocalFilePath => Path.Combine(_hostingEnvironment.LocalTempPath, "NuCache");
+
public PublishedSnapshotService(
PublishedSnapshotServiceOptions options,
ISyncBootStateAccessor syncBootStateAccessor,
@@ -475,6 +477,22 @@ internal class PublishedSnapshotService : IPublishedSnapshotService
return GetUid(_mediaStore, id);
}
+
+ public void ResetLocalDb()
+ {
+ _logger.LogInformation(
+ "Resetting NuCache local db");
+ var path = LocalFilePath;
+ if (Directory.Exists(path) is false)
+ {
+ return;
+ }
+
+ MainDomRelease();
+ Directory.Delete(path, true);
+ MainDomRegister();
+ }
+
///
/// Lazily populates the stores only when they are first requested
///
@@ -603,7 +621,7 @@ internal class PublishedSnapshotService : IPublishedSnapshotService
///
private void MainDomRegister()
{
- var path = GetLocalFilesPath();
+ var path = GetAndEnsureLocalFilesPathExists();
var localContentDbPath = Path.Combine(path, "NuCache.Content.db");
var localMediaDbPath = Path.Combine(path, "NuCache.Media.db");
@@ -652,9 +670,9 @@ internal class PublishedSnapshotService : IPublishedSnapshotService
}
}
- private string GetLocalFilesPath()
+ private string GetAndEnsureLocalFilesPathExists()
{
- var path = Path.Combine(_hostingEnvironment.LocalTempPath, "NuCache");
+ var path = LocalFilePath;
if (!Directory.Exists(path))
{
diff --git a/src/Umbraco.Web.BackOffice/CompatibilitySuppressions.xml b/src/Umbraco.Web.BackOffice/CompatibilitySuppressions.xml
deleted file mode 100644
index d864a9d227..0000000000
--- a/src/Umbraco.Web.BackOffice/CompatibilitySuppressions.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-
-
- PKV006
- net7.0
-
-
\ No newline at end of file
diff --git a/src/Umbraco.Web.BackOffice/Filters/ContentSaveValidationAttribute.cs b/src/Umbraco.Web.BackOffice/Filters/ContentSaveValidationAttribute.cs
index 5c9a96b71c..100d089451 100644
--- a/src/Umbraco.Web.BackOffice/Filters/ContentSaveValidationAttribute.cs
+++ b/src/Umbraco.Web.BackOffice/Filters/ContentSaveValidationAttribute.cs
@@ -188,7 +188,7 @@ internal sealed class ContentSaveValidationAttribute : TypeFilterAttribute
break;
case ContentSaveAction.Schedule:
permissionToCheck.Add(ActionUpdate.ActionLetter);
- permissionToCheck.Add(ActionToPublish.ActionLetter);
+ permissionToCheck.Add(ActionPublish.ActionLetter);
contentToCheck = contentItem.PersistedContent;
contentIdToCheck = contentToCheck?.Id ?? default;
break;
diff --git a/src/Umbraco.Web.BackOffice/Umbraco.Web.BackOffice.csproj b/src/Umbraco.Web.BackOffice/Umbraco.Web.BackOffice.csproj
index 12364baaf1..a64d0d2408 100644
--- a/src/Umbraco.Web.BackOffice/Umbraco.Web.BackOffice.csproj
+++ b/src/Umbraco.Web.BackOffice/Umbraco.Web.BackOffice.csproj
@@ -7,7 +7,6 @@
-
diff --git a/src/Umbraco.Web.Common/CompatibilitySuppressions.xml b/src/Umbraco.Web.Common/CompatibilitySuppressions.xml
deleted file mode 100644
index d864a9d227..0000000000
--- a/src/Umbraco.Web.Common/CompatibilitySuppressions.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-
-
- PKV006
- net7.0
-
-
\ No newline at end of file
diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/content/edit.controller.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/content/edit.controller.js
index 3099bc561c..1e455aea5f 100644
--- a/src/Umbraco.Web.UI.Client/src/common/directives/components/content/edit.controller.js
+++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/content/edit.controller.js
@@ -35,15 +35,18 @@
$scope.activeApp = null;
//initializes any watches
- function startWatches(content) {
+ var watchers = [];
- $scope.$watchGroup(['culture', 'segment'],
+ function startWatches(content) {
+ clearWatchers();
+
+ watchers.push($scope.$watchGroup(['culture', 'segment'],
function (value, oldValue) {
createPreviewButton($scope.content, value[0], value[1]);
- });
+ }));
//watch for changes to isNew, set the page.isNew accordingly and load the breadcrumb if we can
- $scope.$watch('isNew', function (newVal, oldVal) {
+ watchers.push($scope.$watch('isNew', function (newVal, oldVal) {
$scope.page.isNew = Object.toBoolean(newVal);
@@ -59,8 +62,12 @@
});
}
}
- });
+ }));
+ }
+ function clearWatchers () {
+ watchers.forEach(w => w());
+ watchers = [];
}
//this initializes the editor with the data which will be called more than once if the data is re-loaded
@@ -109,6 +116,7 @@
bindEvents();
resetVariantFlags();
+ startWatches($scope.content);
}
function loadBreadcrumb() {
@@ -241,7 +249,6 @@
appendRuntimeData();
init();
- startWatches($scope.content);
syncTreeNode($scope.content, $scope.content.path, true);
@@ -265,7 +272,6 @@
appendRuntimeData();
init();
- startWatches($scope.content);
resetLastListPageNumber($scope.content);
@@ -346,7 +352,10 @@
labelKey: "buttons_saveAndPreview"
};
- const activeVariant = content.variants?.find((variant) => content.documentType?.variations === "Nothing" || variant.compositeId === compositeId);
+ let activeVariant = content.variants?.find((variant) => content.documentType?.variations === "Nothing" || variant.compositeId === compositeId);
+ /* if we can't find the active variant and there is only one variant available, we will use that.
+ this happens if we have a node that can vary by culture but there is only one language available. */
+ activeVariant = !activeVariant && content.variants.length === 1 ? content.variants[0] : activeVariant;
$scope.previewSubButtons = activeVariant?.additionalPreviewUrls?.map((additionalPreviewUrl) => {
return {
diff --git a/src/Umbraco.Web.UI.Client/src/common/filters/nestedcontent.filter.js b/src/Umbraco.Web.UI.Client/src/common/filters/nestedcontent.filter.js
index 2d09b521e3..4fc10dbfa3 100644
--- a/src/Umbraco.Web.UI.Client/src/common/filters/nestedcontent.filter.js
+++ b/src/Umbraco.Web.UI.Client/src/common/filters/nestedcontent.filter.js
@@ -1,4 +1,4 @@
-// Filter to take a node id and grab it's name instead
+// Filter to take a node id and grab it's name instead
// Usage: {{ pickerAlias | ncNodeName }}
// Cache for node names so we don't make a ton of requests
@@ -78,6 +78,9 @@ angular.module("umbraco.filters").filter("ncNodeName", function (editorState, en
}).filter("ncRichText", function () {
return function (input) {
- return $("").html(input).text();
+ // Get markup from RTE object or assume HTML
+ var html = input && Object.hasOwn(input, 'markup') ? input.markup : input;
+
+ return $("").html(html).text();
};
});
diff --git a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj
index 9c90527608..c7258061d5 100644
--- a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj
+++ b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj
@@ -9,6 +9,8 @@
+
+
@@ -17,12 +19,6 @@
-
-
- all
-
-
-
true
diff --git a/src/Umbraco.Web.Website/CompatibilitySuppressions.xml b/src/Umbraco.Web.Website/CompatibilitySuppressions.xml
deleted file mode 100644
index d864a9d227..0000000000
--- a/src/Umbraco.Web.Website/CompatibilitySuppressions.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-
-
- PKV006
- net7.0
-
-
\ No newline at end of file
diff --git a/tests/Directory.Build.props b/tests/Directory.Build.props
index ec220ec3a8..1d532e6664 100644
--- a/tests/Directory.Build.props
+++ b/tests/Directory.Build.props
@@ -5,6 +5,7 @@
false
+ $(EnablePackageValidation)false
diff --git a/tests/Umbraco.Tests.Benchmarks/Umbraco.Tests.Benchmarks.csproj b/tests/Umbraco.Tests.Benchmarks/Umbraco.Tests.Benchmarks.csproj
index 3884fec209..342622c094 100644
--- a/tests/Umbraco.Tests.Benchmarks/Umbraco.Tests.Benchmarks.csproj
+++ b/tests/Umbraco.Tests.Benchmarks/Umbraco.Tests.Benchmarks.csproj
@@ -7,8 +7,6 @@
-
-
diff --git a/tests/Umbraco.Tests.Common/CompatibilitySuppressions.xml b/tests/Umbraco.Tests.Common/CompatibilitySuppressions.xml
deleted file mode 100644
index d864a9d227..0000000000
--- a/tests/Umbraco.Tests.Common/CompatibilitySuppressions.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-
-
- PKV006
- net7.0
-
-
\ No newline at end of file
diff --git a/tests/Umbraco.Tests.Common/Umbraco.Tests.Common.csproj b/tests/Umbraco.Tests.Common/Umbraco.Tests.Common.csproj
index ae194a9f77..c84c8fad6e 100644
--- a/tests/Umbraco.Tests.Common/Umbraco.Tests.Common.csproj
+++ b/tests/Umbraco.Tests.Common/Umbraco.Tests.Common.csproj
@@ -5,7 +5,7 @@
Contains commonly used tools to write tests for Umbraco CMS, such as various builders for content etc.Umbraco.Cms.Tests.Commontrue
- true
+ $(BaseEnablePackageValidation)
diff --git a/tests/Umbraco.Tests.Integration/CompatibilitySuppressions.xml b/tests/Umbraco.Tests.Integration/CompatibilitySuppressions.xml
deleted file mode 100644
index 0abc4e0e3a..0000000000
--- a/tests/Umbraco.Tests.Integration/CompatibilitySuppressions.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-
-
- PKV006
- net7.0
-
-
diff --git a/tests/Umbraco.Tests.Integration/Umbraco.Persistence.EFCore/DbContext/CustomDbContextTests.cs b/tests/Umbraco.Tests.Integration/Umbraco.Persistence.EFCore/DbContext/CustomDbContextTests.cs
new file mode 100644
index 0000000000..bfa3adb92b
--- /dev/null
+++ b/tests/Umbraco.Tests.Integration/Umbraco.Persistence.EFCore/DbContext/CustomDbContextTests.cs
@@ -0,0 +1,101 @@
+using Microsoft.EntityFrameworkCore;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
+using NUnit.Framework;
+using Umbraco.Cms.Tests.Common.Testing;
+using Umbraco.Cms.Tests.Integration.Testing;
+
+namespace Umbraco.Cms.Tests.Integration.Umbraco.Persistence.EFCore.DbContext;
+
+[TestFixture]
+[UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest, Logger = UmbracoTestOptions.Logger.Console)]
+public class CustomDbContextUmbracoProviderTests : UmbracoIntegrationTest
+{
+ [Test]
+ public void Can_Register_Custom_DbContext_And_Resolve()
+ {
+ var dbContext = Services.GetRequiredService();
+
+ Assert.IsNotNull(dbContext);
+ Assert.IsNotEmpty(dbContext.Database.GetConnectionString());
+ }
+
+ protected override void CustomTestSetup(IUmbracoBuilder builder)
+ {
+ builder.Services.AddUmbracoDbContext((serviceProvider, options) =>
+ {
+ options.UseUmbracoDatabaseProvider(serviceProvider);
+ });
+ }
+
+ internal class CustomDbContext : Microsoft.EntityFrameworkCore.DbContext
+ {
+ public CustomDbContext(DbContextOptions options)
+ : base(options)
+ {
+ }
+ }
+}
+
+
+[TestFixture]
+[UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest, Logger = UmbracoTestOptions.Logger.Console)]
+public class CustomDbContextCustomSqliteProviderTests : UmbracoIntegrationTest
+{
+ [Test]
+ public void Can_Register_Custom_DbContext_And_Resolve()
+ {
+ var dbContext = Services.GetRequiredService();
+
+ Assert.IsNotNull(dbContext);
+ Assert.IsNotEmpty(dbContext.Database.GetConnectionString());
+ }
+
+ protected override void CustomTestSetup(IUmbracoBuilder builder)
+ {
+ builder.Services.AddUmbracoDbContext((serviceProvider, options) =>
+ {
+ options.UseSqlite("Data Source=:memory:;Version=3;New=True;");
+ });
+ }
+
+ internal class CustomDbContext : Microsoft.EntityFrameworkCore.DbContext
+ {
+ public CustomDbContext(DbContextOptions options)
+ : base(options)
+ {
+ }
+ }
+}
+
+[Obsolete]
+[TestFixture]
+[UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest, Logger = UmbracoTestOptions.Logger.Console)]
+public class CustomDbContextLegacyExtensionProviderTests : UmbracoIntegrationTest
+{
+ [Test]
+ public void Can_Register_Custom_DbContext_And_Resolve()
+ {
+ var dbContext = Services.GetRequiredService();
+
+ Assert.IsNotNull(dbContext);
+ Assert.IsNotEmpty(dbContext.Database.GetConnectionString());
+ }
+
+ protected override void CustomTestSetup(IUmbracoBuilder builder)
+ {
+ builder.Services.AddUmbracoEFCoreContext("Data Source=:memory:;Version=3;New=True;", "Microsoft.Data.Sqlite", (options, connectionString, providerName) =>
+ {
+ options.UseSqlite(connectionString);
+ });
+ }
+
+ internal class CustomDbContext : Microsoft.EntityFrameworkCore.DbContext
+ {
+ public CustomDbContext(DbContextOptions options)
+ : base(options)
+ {
+ }
+ }
+}
+
diff --git a/tests/Umbraco.Tests.Integration/Umbraco.Tests.Integration.csproj b/tests/Umbraco.Tests.Integration/Umbraco.Tests.Integration.csproj
index 74f8d64b4a..e706538a02 100644
--- a/tests/Umbraco.Tests.Integration/Umbraco.Tests.Integration.csproj
+++ b/tests/Umbraco.Tests.Integration/Umbraco.Tests.Integration.csproj
@@ -6,8 +6,7 @@
Contains helper classes for integration tests with Umbraco CMS, including all internal integration tests.Umbraco.Cms.Tests.Integrationtrue
- true
- true
+ $(BaseEnablePackageValidation)
diff --git a/tests/Umbraco.Tests.UnitTests/Umbraco.Core/CoreThings/UdiTests.cs b/tests/Umbraco.Tests.UnitTests/Umbraco.Core/CoreThings/UdiTests.cs
index ccca8f9f3c..30a8d6a1fa 100644
--- a/tests/Umbraco.Tests.UnitTests/Umbraco.Core/CoreThings/UdiTests.cs
+++ b/tests/Umbraco.Tests.UnitTests/Umbraco.Core/CoreThings/UdiTests.cs
@@ -326,7 +326,7 @@ public class UdiTests
}
[UdiDefinition("foo", UdiType.GuidUdi)]
- public class FooConnector : IServiceConnector2
+ public class FooConnector : IServiceConnector
{
public IArtifact GetArtifact(Udi udi, IContextCache contextCache) => throw new NotImplementedException();
diff --git a/tests/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/DataValueReferenceFactoryCollectionTests.cs b/tests/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/DataValueReferenceFactoryCollectionTests.cs
index 6108f59e2e..cff072873f 100644
--- a/tests/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/DataValueReferenceFactoryCollectionTests.cs
+++ b/tests/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/DataValueReferenceFactoryCollectionTests.cs
@@ -1,8 +1,6 @@
// Copyright (c) Umbraco.
// See LICENSE for more details.
-using System.Collections.Generic;
-using System.Linq;
using Moq;
using NUnit.Framework;
using Umbraco.Cms.Core;
@@ -173,6 +171,40 @@ public class DataValueReferenceFactoryCollectionTests
Assert.AreEqual(trackedUdi4, result.ElementAt(1).Udi.ToString());
}
+ [Test]
+ public void GetAutomaticRelationTypesAliases_ContainsDefault()
+ {
+ var collection = new DataValueReferenceFactoryCollection(Enumerable.Empty);
+ var propertyEditors = new PropertyEditorCollection(new DataEditorCollection(Enumerable.Empty));
+ var properties = new PropertyCollection();
+
+ var resultA = collection.GetAutomaticRelationTypesAliases(propertyEditors).ToArray();
+ var resultB = collection.GetAutomaticRelationTypesAliases(properties, propertyEditors).ToArray();
+
+ var expected = Constants.Conventions.RelationTypes.AutomaticRelationTypes;
+ CollectionAssert.AreEquivalent(expected, resultA, "Result A does not contain the expected relation type aliases.");
+ CollectionAssert.AreEquivalent(expected, resultB, "Result B does not contain the expected relation type aliases.");
+ }
+
+ [Test]
+ public void GetAutomaticRelationTypesAliases_ContainsCustom()
+ {
+ var collection = new DataValueReferenceFactoryCollection(() => new TestDataValueReferenceFactory().Yield());
+
+ var labelPropertyEditor = new LabelPropertyEditor(DataValueEditorFactory, IOHelper, EditorConfigurationParser);
+ var propertyEditors = new PropertyEditorCollection(new DataEditorCollection(() => labelPropertyEditor.Yield()));
+ var serializer = new ConfigurationEditorJsonSerializer();
+ var property = new Property(new PropertyType(ShortStringHelper, new DataType(labelPropertyEditor, serializer)));
+ var properties = new PropertyCollection { property, property }; // Duplicate on purpose to test distinct aliases
+
+ var resultA = collection.GetAutomaticRelationTypesAliases(propertyEditors).ToArray();
+ var resultB = collection.GetAutomaticRelationTypesAliases(properties, propertyEditors).ToArray();
+
+ var expected = Constants.Conventions.RelationTypes.AutomaticRelationTypes.Append("umbTest");
+ CollectionAssert.AreEquivalent(expected, resultA, "Result A does not contain the expected relation type aliases.");
+ CollectionAssert.AreEquivalent(expected, resultB, "Result B does not contain the expected relation type aliases.");
+ }
+
private class TestDataValueReferenceFactory : IDataValueReferenceFactory
{
public IDataValueReference GetDataValueReference() => new TestMediaDataValueReference();
@@ -196,6 +228,12 @@ public class DataValueReferenceFactoryCollectionTests
yield return new UmbracoEntityReference(udi);
}
}
+
+ public IEnumerable GetAutomaticRelationTypesAliases() => new[]
+ {
+ "umbTest",
+ "umbTest", // Duplicate on purpose to test distinct aliases
+ };
}
}
}
diff --git a/tests/Umbraco.Tests.UnitTests/Umbraco.Core/Published/PublishedContentVarianceTests.cs b/tests/Umbraco.Tests.UnitTests/Umbraco.Core/Published/PublishedContentVarianceTests.cs
new file mode 100644
index 0000000000..7d117b96c5
--- /dev/null
+++ b/tests/Umbraco.Tests.UnitTests/Umbraco.Core/Published/PublishedContentVarianceTests.cs
@@ -0,0 +1,152 @@
+using Moq;
+using NUnit.Framework;
+using Umbraco.Cms.Core.Cache;
+using Umbraco.Cms.Core.Models;
+using Umbraco.Cms.Core.Models.PublishedContent;
+using Umbraco.Cms.Core.PropertyEditors;
+using Umbraco.Cms.Core.PublishedCache;
+using Umbraco.Cms.Infrastructure.PublishedCache;
+using Umbraco.Cms.Infrastructure.PublishedCache.DataSource;
+
+namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Core.Published;
+
+[TestFixture]
+public class PublishedContentVarianceTests
+{
+ private const string PropertyTypeAlias = "theProperty";
+ private const string DaCulture = "da-DK";
+ private const string EnCulture = "en-US";
+ private const string Segment1 = "segment1";
+ private const string Segment2 = "segment2";
+
+ [Test]
+ public void No_Content_Variation_Can_Get_Invariant_Property()
+ {
+ var content = CreatePublishedContent(ContentVariation.Nothing, ContentVariation.Nothing);
+ var value = GetPropertyValue(content);
+ Assert.AreEqual("Invariant property value", value);
+ }
+
+ [TestCase(DaCulture)]
+ [TestCase(EnCulture)]
+ [TestCase("")]
+ public void Content_Culture_Variation_Can_Get_Invariant_Property(string culture)
+ {
+ var content = CreatePublishedContent(ContentVariation.Culture, ContentVariation.Nothing, variationContextCulture: culture);
+ var value = GetPropertyValue(content);
+ Assert.AreEqual("Invariant property value", value);
+ }
+
+ [TestCase(Segment1)]
+ [TestCase(Segment2)]
+ [TestCase("")]
+ public void Content_Segment_Variation_Can_Get_Invariant_Property(string segment)
+ {
+ var content = CreatePublishedContent(ContentVariation.Culture, ContentVariation.Nothing, variationContextSegment: segment);
+ var value = GetPropertyValue(content);
+ Assert.AreEqual("Invariant property value", value);
+ }
+
+ [TestCase(DaCulture, "DaDk property value")]
+ [TestCase(EnCulture, "EnUs property value")]
+ public void Content_Culture_Variation_Can_Get_Culture_Variant_Property(string culture, string expectedValue)
+ {
+ var content = CreatePublishedContent(ContentVariation.Culture, ContentVariation.Culture, variationContextCulture: culture);
+ var value = GetPropertyValue(content);
+ Assert.AreEqual(expectedValue, value);
+ }
+
+ [TestCase(Segment1, "Segment1 property value")]
+ [TestCase(Segment2, "Segment2 property value")]
+ public void Content_Segment_Variation_Can_Get_Segment_Variant_Property(string segment, string expectedValue)
+ {
+ var content = CreatePublishedContent(ContentVariation.Segment, ContentVariation.Segment, variationContextSegment: segment);
+ var value = GetPropertyValue(content);
+ Assert.AreEqual(expectedValue, value);
+ }
+
+ [TestCase(DaCulture, Segment1, "DaDk Segment1 property value")]
+ [TestCase(DaCulture, Segment2, "DaDk Segment2 property value")]
+ [TestCase(EnCulture, Segment1, "EnUs Segment1 property value")]
+ [TestCase(EnCulture, Segment2, "EnUs Segment2 property value")]
+ public void Content_Culture_And_Segment_Variation_Can_Get_Culture_And_Segment_Variant_Property(string culture, string segment, string expectedValue)
+ {
+ var content = CreatePublishedContent(ContentVariation.CultureAndSegment, ContentVariation.CultureAndSegment, variationContextCulture: culture, variationContextSegment: segment);
+ var value = GetPropertyValue(content);
+ Assert.AreEqual(expectedValue, value);
+ }
+
+ private object? GetPropertyValue(IPublishedContent content) => content.GetProperty(PropertyTypeAlias)!.GetValue();
+
+ private IPublishedContent CreatePublishedContent(ContentVariation contentTypeVariation, ContentVariation propertyTypeVariation, string? variationContextCulture = null, string? variationContextSegment = null)
+ {
+ var propertyType = new Mock();
+ propertyType.SetupGet(p => p.Alias).Returns(PropertyTypeAlias);
+ propertyType.SetupGet(p => p.CacheLevel).Returns(PropertyCacheLevel.None);
+ propertyType.SetupGet(p => p.DeliveryApiCacheLevel).Returns(PropertyCacheLevel.None);
+ propertyType.SetupGet(p => p.Variations).Returns(propertyTypeVariation);
+ propertyType
+ .Setup(p => p.ConvertSourceToInter(It.IsAny(), It.IsAny