diff --git a/.gitignore b/.gitignore index 57b4e18aaa..0825d81b78 100644 --- a/.gitignore +++ b/.gitignore @@ -1,160 +1,162 @@ -# -# Umbraco Cms Git Ignore -# - -# common files -*.obj -*.pdb -*.user -*.aps -*.pch -*.vspscc -*.orig -*.suo -*.vs10x -*.ndproj +# +# Umbraco Cms Git Ignore +# + +# common files +*.obj +*.pdb +*.user +*.aps +*.pch +*.vspscc +*.orig +*.suo +*.vs10x +*.ndproj *.ignorer.* - -# common directories -.DS_Store -._.DS_Store -.vs/ -/local/ - -# build directories -[Bb]in/ -[Db]ebug*/ -[Rr]elease*/ -obj/ - -# tools -_ReSharper*/ -_NCrunch_*/ -*.ncrunchsolution -*.ncrunchsolution.user -*.ncrunchproject -*.crunchsolution.cache -tools/NDepend/ - - - - -[Tt]est[Rr]esult* -[Bb]uild[Ll]og.* -*.[Pp]ublish.xml -[sS]ource -[sS]andbox -umbraco.config -App_Data/TEMP/* -[Uu]mbraco/[Pp]resentation/[Uu]mbraco/[Pp]lugins/* -[Uu]mbraco/[Pp]resentation/[Uu]ser[Cc]ontrols/* -[Uu]mbraco/[Pp]resentation/[Ss]cripts/* -[Uu]mbraco/[Pp]resentation/[Ff]onts/* -[Uu]mbraco/[Pp]resentation/[Cc]ss/* - -src/Umbraco.Web.UI/[Cc]ss/* -src/Umbraco.Web.UI/App_Code/* -src/Umbraco.Web.UI/App_Data/* -src/Umbraco.Tests/App_Data/* -src/Umbraco.Web.UI/[Mm]edia/* -src/Umbraco.Web.UI/[Mm]aster[Pp]ages/* -src/Umbraco.Web.UI/[Mm]acro[Ss]cripts/* -!src/Umbraco.Web.UI/[Mm]acro[Ss]cripts/[Ww]eb.[Cc]onfig -src/Umbraco.Web.UI/[Xx]slt/* -src/Umbraco.Web.UI/[Ii]mages/* -src/Umbraco.Web.UI/[Ss]cripts/* -src/Umbraco.Web.UI/Web.*.config.transformed - -umbraco/presentation/umbraco/plugins/uComponents/uComponentsInstaller.ascx -umbraco/presentation/packages/uComponents/MultiNodePicker/CustomTreeService.asmx - -src/Umbraco.Tests/config/applications.config -src/Umbraco.Tests/config/trees.config -src/Umbraco.Web.UI/web.config -src/Umbraco.Web.UI/[Cc]onfig/ClientDependency.config -src/Umbraco.Tests/config/404handlers.config -src/Umbraco.Web.UI/[Vv]iews/*.cshtml -src/Umbraco.Web.UI/[Vv]iews/*.vbhtml -src/Umbraco.Tests/[Cc]onfig/umbracoSettings.config -src/Umbraco.Web.UI/[Vv]iews/* -src/packages/ -src/packages/repositories.config - -src/Umbraco.Web.UI/[Ww]eb.config -*.transformed - -node_modules -lib-bower - -src/Umbraco.Web.UI/[Uu]mbraco/[Ll]ib/* -src/Umbraco.Web.UI/[Uu]mbraco/[Jj]s/umbraco.* -src/Umbraco.Web.UI/[Uu]mbraco/[Jj]s/*.loader.js -src/Umbraco.Web.UI/[Uu]mbraco/[Jj]s/init.js -src/Umbraco.Web.UI/[Uu]mbraco/[Jj]s/routes.js -src/Umbraco.Web.UI/[Uu]mbraco/[Jj]s/app.dev.js -src/Umbraco.Web.UI/[Uu]mbraco/[Jj]s/loader.js -src/Umbraco.Web.UI/[Uu]mbraco/[Jj]s/loader.dev.js -src/Umbraco.Web.UI/[Uu]mbraco/[Jj]s/main.js -src/Umbraco.Web.UI/[Uu]mbraco/[Jj]s/app.js -src/Umbraco.Web.UI/[Uu]mbraco/[Jj]s/canvasdesigner.*.js - -src/Umbraco.Web.UI/[Uu]mbraco/[Vv]iews/ -src/Umbraco.Web.UI/[Uu]mbraco/[Vv]iews/**/*.js -src/Umbraco.Web.UI/[Uu]mbraco/[Vv]iews/**/*.css -src/Umbraco.Web.UI/[Uu]mbraco/[Vv]iews/**/*.html -src/Umbraco.Web.UI/[Uu]mbraco/[Aa]ssets/* -src/Umbraco.Web.UI.Client/[Bb]uild/* -src/Umbraco.Web.UI.Client/[Bb]uild/[Bb]elle/ -src/Umbraco.Web.UI/[Uu]ser[Cc]ontrols/ - -src/Umbraco.Web.UI.Client/src/[Ll]ess/*.css -src/Umbraco.Web.UI.Client/vwd.webinfo - -src/Umbraco.Web.UI/App_Plugins/* -src/*.psess -src/*.vspx - -NDependOut/* -QueryResult.htm - -src/Umbraco.Web.UI/[Cc]onfig/appSettings.config -src/Umbraco.Web.UI/[Cc]onfig/connectionStrings.config -src/Umbraco.Web.UI/[Uu]mbraco/plugins/* -build/ApiDocs/* -build/ApiDocs/Output/* -src/Umbraco.Web.UI.Client/bower_components/* -/src/Umbraco.Web.UI/[Uu]mbraco/preview -/src/Umbraco.Web.UI/[Uu]mbraco/preview.old - -# ignore rule for clearing out Belle (avoid rebuilding all the time) -preserve.belle - -#Ignore Rule for output of generated documentation files from Grunt docserve -src/Umbraco.Web.UI.Client/docs/api -src/*.boltdata/ -src/umbraco.sln.ide/* -src/.vs/ - -src/Umbraco.Web.UI/[Jj]s/* -src/Umbraco.Tests/[Mm]edia -tools/docfx/* -apidocs/_site/* -src/*/project.lock.json -src/.idea/* - -apidocs/api/* -build/docs.zip -build/ui-docs.zip -build/csharp-docs.zip -src/packages/ -src/PrecompiledWeb/* - -# build -build.out/ -build.tmp/ -build/hooks/ -build/temp/ - - - + +# common directories +.DS_Store +._.DS_Store +.vs/ +/local/ + +# build directories +[Bb]in/ +[Db]ebug*/ +[Rr]elease*/ +obj/ + +# tools +_ReSharper*/ +_NCrunch_*/ +*.ncrunchsolution +*.ncrunchsolution.user +*.ncrunchproject +*.crunchsolution.cache +tools/NDepend/ + + + + +[Tt]est[Rr]esult* +[Bb]uild[Ll]og.* +*.[Pp]ublish.xml +[sS]ource +[sS]andbox +umbraco.config +App_Data/TEMP/* +[Uu]mbraco/[Pp]resentation/[Uu]mbraco/[Pp]lugins/* +[Uu]mbraco/[Pp]resentation/[Uu]ser[Cc]ontrols/* +[Uu]mbraco/[Pp]resentation/[Ss]cripts/* +[Uu]mbraco/[Pp]resentation/[Ff]onts/* +[Uu]mbraco/[Pp]resentation/[Cc]ss/* + +src/Umbraco.Web.UI/[Cc]ss/* +src/Umbraco.Web.UI/App_Code/* +src/Umbraco.Web.UI/App_Data/* +src/Umbraco.Tests/App_Data/* +src/Umbraco.Web.UI/[Mm]edia/* +src/Umbraco.Web.UI/[Mm]aster[Pp]ages/* +src/Umbraco.Web.UI/[Mm]acro[Ss]cripts/* +!src/Umbraco.Web.UI/[Mm]acro[Ss]cripts/[Ww]eb.[Cc]onfig +src/Umbraco.Web.UI/[Xx]slt/* +src/Umbraco.Web.UI/[Ii]mages/* +src/Umbraco.Web.UI/[Ss]cripts/* +src/Umbraco.Web.UI/Web.*.config.transformed + +umbraco/presentation/umbraco/plugins/uComponents/uComponentsInstaller.ascx +umbraco/presentation/packages/uComponents/MultiNodePicker/CustomTreeService.asmx + +src/Umbraco.Tests/config/applications.config +src/Umbraco.Tests/config/trees.config +src/Umbraco.Web.UI/web.config +src/Umbraco.Web.UI/[Cc]onfig/ClientDependency.config +src/Umbraco.Web.UI/[Cc]onfig/serilog.config +src/Umbraco.Web.UI/[Cc]onfig/serilog.user.config +src/Umbraco.Tests/config/404handlers.config +src/Umbraco.Web.UI/[Vv]iews/*.cshtml +src/Umbraco.Web.UI/[Vv]iews/*.vbhtml +src/Umbraco.Tests/[Cc]onfig/umbracoSettings.config +src/Umbraco.Web.UI/[Vv]iews/* +src/packages/ +src/packages/repositories.config + +src/Umbraco.Web.UI/[Ww]eb.config +*.transformed + +node_modules +lib-bower + +src/Umbraco.Web.UI/[Uu]mbraco/[Ll]ib/* +src/Umbraco.Web.UI/[Uu]mbraco/[Jj]s/umbraco.* +src/Umbraco.Web.UI/[Uu]mbraco/[Jj]s/*.loader.js +src/Umbraco.Web.UI/[Uu]mbraco/[Jj]s/init.js +src/Umbraco.Web.UI/[Uu]mbraco/[Jj]s/routes.js +src/Umbraco.Web.UI/[Uu]mbraco/[Jj]s/app.dev.js +src/Umbraco.Web.UI/[Uu]mbraco/[Jj]s/loader.js +src/Umbraco.Web.UI/[Uu]mbraco/[Jj]s/loader.dev.js +src/Umbraco.Web.UI/[Uu]mbraco/[Jj]s/main.js +src/Umbraco.Web.UI/[Uu]mbraco/[Jj]s/app.js +src/Umbraco.Web.UI/[Uu]mbraco/[Jj]s/canvasdesigner.*.js + +src/Umbraco.Web.UI/[Uu]mbraco/[Vv]iews/ +src/Umbraco.Web.UI/[Uu]mbraco/[Vv]iews/**/*.js +src/Umbraco.Web.UI/[Uu]mbraco/[Vv]iews/**/*.css +src/Umbraco.Web.UI/[Uu]mbraco/[Vv]iews/**/*.html +src/Umbraco.Web.UI/[Uu]mbraco/[Aa]ssets/* +src/Umbraco.Web.UI.Client/[Bb]uild/* +src/Umbraco.Web.UI.Client/[Bb]uild/[Bb]elle/ +src/Umbraco.Web.UI/[Uu]ser[Cc]ontrols/ + +src/Umbraco.Web.UI.Client/src/[Ll]ess/*.css +src/Umbraco.Web.UI.Client/vwd.webinfo + +src/Umbraco.Web.UI/App_Plugins/* +src/*.psess +src/*.vspx + +NDependOut/* +QueryResult.htm + +src/Umbraco.Web.UI/[Cc]onfig/appSettings.config +src/Umbraco.Web.UI/[Cc]onfig/connectionStrings.config +src/Umbraco.Web.UI/[Uu]mbraco/plugins/* +build/ApiDocs/* +build/ApiDocs/Output/* +src/Umbraco.Web.UI.Client/bower_components/* +/src/Umbraco.Web.UI/[Uu]mbraco/preview +/src/Umbraco.Web.UI/[Uu]mbraco/preview.old + +# ignore rule for clearing out Belle (avoid rebuilding all the time) +preserve.belle + +#Ignore Rule for output of generated documentation files from Grunt docserve +src/Umbraco.Web.UI.Client/docs/api +src/*.boltdata/ +src/umbraco.sln.ide/* +src/.vs/ + +src/Umbraco.Web.UI/[Jj]s/* +src/Umbraco.Tests/[Mm]edia +tools/docfx/* +apidocs/_site/* +src/*/project.lock.json +src/.idea/* + +apidocs/api/* +build/docs.zip +build/ui-docs.zip +build/csharp-docs.zip +src/packages/ +src/PrecompiledWeb/* + +# build +build.out/ +build.tmp/ +build/hooks/ +build/temp/ + + + # eof diff --git a/src/Umbraco.Core/Components/CompositionExtensions.cs b/src/Umbraco.Core/Components/CompositionExtensions.cs index 8810213421..96d7e7d5c7 100644 --- a/src/Umbraco.Core/Components/CompositionExtensions.cs +++ b/src/Umbraco.Core/Components/CompositionExtensions.cs @@ -110,13 +110,6 @@ namespace Umbraco.Core.Components internal static ManifestValueValidatorCollectionBuilder Validators(this Composition composition) => composition.WithCollectionBuilder(); - /// - /// Gets the post-migrations collection builder. - /// - /// The composition. - internal static PostMigrationCollectionBuilder PostMigrations(this Composition composition) - => composition.WithCollectionBuilder(); - /// /// Gets the components collection builder. /// diff --git a/src/Umbraco.Core/Migrations/IMigrationContext.cs b/src/Umbraco.Core/Migrations/IMigrationContext.cs index 80ba78b6de..2baadc79eb 100644 --- a/src/Umbraco.Core/Migrations/IMigrationContext.cs +++ b/src/Umbraco.Core/Migrations/IMigrationContext.cs @@ -1,4 +1,6 @@ -using Umbraco.Core.Logging; +using System; +using System.Collections.Generic; +using Umbraco.Core.Logging; using Umbraco.Core.Persistence; namespace Umbraco.Core.Migrations @@ -32,5 +34,11 @@ namespace Umbraco.Core.Migrations /// Gets or sets a value indicating whether an expression is being built. /// bool BuildingExpression { get; set; } + + /// + /// Adds a post-migrations. + /// + void AddPostMigration() + where TMigration : IMigration; } } diff --git a/src/Umbraco.Core/Migrations/IPostMigration.cs b/src/Umbraco.Core/Migrations/IPostMigration.cs deleted file mode 100644 index 15daf0fc74..0000000000 --- a/src/Umbraco.Core/Migrations/IPostMigration.cs +++ /dev/null @@ -1,12 +0,0 @@ -using Semver; -using Umbraco.Core.Composing; -using Umbraco.Core.Logging; -using Umbraco.Core.Scoping; - -namespace Umbraco.Core.Migrations -{ - public interface IPostMigration : IDiscoverable - { - void Execute(string name, IScope scope, SemVersion originVersion, SemVersion targetVersion, ILogger logger); - } -} diff --git a/src/Umbraco.Core/Migrations/Install/DatabaseBuilder.cs b/src/Umbraco.Core/Migrations/Install/DatabaseBuilder.cs index 9c6ff208f8..5c4defab0c 100644 --- a/src/Umbraco.Core/Migrations/Install/DatabaseBuilder.cs +++ b/src/Umbraco.Core/Migrations/Install/DatabaseBuilder.cs @@ -27,7 +27,6 @@ namespace Umbraco.Core.Migrations.Install private readonly IRuntimeState _runtime; private readonly IMigrationBuilder _migrationBuilder; private readonly IKeyValueService _keyValueService; - private readonly PostMigrationCollection _postMigrations; private readonly ILogger _logger; private DatabaseSchemaResult _databaseSchemaValidationResult; @@ -35,7 +34,7 @@ namespace Umbraco.Core.Migrations.Install /// /// Initializes a new instance of the class. /// - public DatabaseBuilder(IScopeProvider scopeProvider, IGlobalSettings globalSettings, IUmbracoDatabaseFactory databaseFactory, IRuntimeState runtime, ILogger logger, IMigrationBuilder migrationBuilder, IKeyValueService keyValueService, PostMigrationCollection postMigrations) + public DatabaseBuilder(IScopeProvider scopeProvider, IGlobalSettings globalSettings, IUmbracoDatabaseFactory databaseFactory, IRuntimeState runtime, ILogger logger, IMigrationBuilder migrationBuilder, IKeyValueService keyValueService) { _scopeProvider = scopeProvider; _globalSettings = globalSettings; @@ -44,7 +43,6 @@ namespace Umbraco.Core.Migrations.Install _logger = logger; _migrationBuilder = migrationBuilder; _keyValueService = keyValueService; - _postMigrations = postMigrations; } #region Status @@ -483,7 +481,7 @@ namespace Umbraco.Core.Migrations.Install /// configured and it is possible to connect to the database. /// Runs whichever migrations need to run. /// - public Result UpgradeSchemaAndData() + public Result UpgradeSchemaAndData(MigrationPlan plan) { try { @@ -496,8 +494,8 @@ namespace Umbraco.Core.Migrations.Install _logger.Info("Database upgrade started"); // upgrade - var upgrader = new UmbracoUpgrader(); - upgrader.Execute(_scopeProvider, _migrationBuilder, _keyValueService, _logger, _postMigrations); + var upgrader = new Upgrader(plan); + upgrader.Execute(_scopeProvider, _migrationBuilder, _keyValueService, _logger); var message = "

Upgrade completed!

"; diff --git a/src/Umbraco.Core/Migrations/Install/DatabaseDataCreator.cs b/src/Umbraco.Core/Migrations/Install/DatabaseDataCreator.cs index 7f7229ccd6..1fefcf85d9 100644 --- a/src/Umbraco.Core/Migrations/Install/DatabaseDataCreator.cs +++ b/src/Umbraco.Core/Migrations/Install/DatabaseDataCreator.cs @@ -321,7 +321,7 @@ namespace Umbraco.Core.Migrations.Install { // on install, initialize the umbraco migration plan with the final state - var upgrader = new UmbracoUpgrader(); + var upgrader = new Upgrader(new UmbracoPlan()); var stateValueKey = upgrader.StateValueKey; var finalState = upgrader.Plan.FinalState; diff --git a/src/Umbraco.Core/Migrations/MigrationContext.cs b/src/Umbraco.Core/Migrations/MigrationContext.cs index da454fab03..a8d052036c 100644 --- a/src/Umbraco.Core/Migrations/MigrationContext.cs +++ b/src/Umbraco.Core/Migrations/MigrationContext.cs @@ -1,11 +1,12 @@ using System; +using System.Collections.Generic; using Umbraco.Core.Logging; using Umbraco.Core.Persistence; namespace Umbraco.Core.Migrations { /// - /// Represents a migration context. + /// Implements . /// internal class MigrationContext : IMigrationContext { @@ -32,5 +33,15 @@ namespace Umbraco.Core.Migrations /// public bool BuildingExpression { get; set; } + + // this is only internally exposed + public List PostMigrations { get; } = new List(); + + /// + public void AddPostMigration() + where TMigration : IMigration + { + PostMigrations.Add(typeof(TMigration)); + } } } diff --git a/src/Umbraco.Core/Migrations/MigrationPlan.cs b/src/Umbraco.Core/Migrations/MigrationPlan.cs index 9ede9f04f2..4be4ae7d30 100644 --- a/src/Umbraco.Core/Migrations/MigrationPlan.cs +++ b/src/Umbraco.Core/Migrations/MigrationPlan.cs @@ -14,6 +14,7 @@ namespace Umbraco.Core.Migrations public class MigrationPlan { private readonly Dictionary _transitions = new Dictionary(); + private readonly List _postMigrationTypes = new List(); private string _prevState; private string _finalState; @@ -166,6 +167,25 @@ namespace Umbraco.Core.Migrations return this; } + /// + /// Prepares post-migrations. + /// + /// + /// This can be overriden to filter, complement, and/or re-order post-migrations. + /// + protected virtual IEnumerable PreparePostMigrations(IEnumerable types) + => types; + + /// + /// Adds a post-migration to the plan. + /// + public virtual MigrationPlan AddPostMigration() + where TMigration : IMigration + { + _postMigrationTypes.Add(typeof(TMigration)); + return this; + } + /// /// Creates a random, unique state. /// @@ -270,6 +290,7 @@ namespace Umbraco.Core.Migrations throw new Exception($"Unknown state \"{origState}\"."); var context = new MigrationContext(scope.Database, logger); + context.PostMigrations.AddRange(_postMigrationTypes); while (transition != null) { @@ -285,6 +306,20 @@ namespace Umbraco.Core.Migrations throw new Exception($"Unknown state \"{origState}\"."); } + // prepare and de-duplicate post-migrations, only keeping the 1st occurence + var temp = new HashSet(); + var postMigrationTypes = PreparePostMigrations(context.PostMigrations) + .Where(x => !temp.Contains(x)) + .Select(x => { temp.Add(x); return x; }); + + // run post-migrations + foreach (var postMigrationType in postMigrationTypes) + { + logger.Info($"PostMigration: {postMigrationType.FullName}."); + var postMigration = migrationBuilder.Build(postMigrationType, context); + postMigration.Migrate(); + } + logger.Info("Done (pending scope completion)."); // safety check diff --git a/src/Umbraco.Core/Migrations/PostMigrationCollection.cs b/src/Umbraco.Core/Migrations/PostMigrationCollection.cs deleted file mode 100644 index 488bdfd72d..0000000000 --- a/src/Umbraco.Core/Migrations/PostMigrationCollection.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System.Collections.Generic; -using Umbraco.Core.Composing; - -namespace Umbraco.Core.Migrations -{ - public class PostMigrationCollection : BuilderCollectionBase - { - public PostMigrationCollection(IEnumerable items) - : base(items) - { } - } -} diff --git a/src/Umbraco.Core/Migrations/PostMigrationCollectionBuilder.cs b/src/Umbraco.Core/Migrations/PostMigrationCollectionBuilder.cs deleted file mode 100644 index b23d4f1c9c..0000000000 --- a/src/Umbraco.Core/Migrations/PostMigrationCollectionBuilder.cs +++ /dev/null @@ -1,11 +0,0 @@ -using Umbraco.Core.Composing; - -namespace Umbraco.Core.Migrations -{ - public class PostMigrationCollectionBuilder : LazyCollectionBuilderBase - { - protected override PostMigrationCollectionBuilder This => this; - - protected override Lifetime CollectionLifetime => Lifetime.Transient; - } -} diff --git a/src/Umbraco.Core/Migrations/PostMigrations/IPublishedSnapshotRebuilder.cs b/src/Umbraco.Core/Migrations/PostMigrations/IPublishedSnapshotRebuilder.cs new file mode 100644 index 0000000000..1b0549827e --- /dev/null +++ b/src/Umbraco.Core/Migrations/PostMigrations/IPublishedSnapshotRebuilder.cs @@ -0,0 +1,18 @@ +namespace Umbraco.Core.Migrations.PostMigrations +{ + /// + /// Rebuilds the published snapshot. + /// + /// + /// This interface exists because the entire published snapshot lives in Umbraco.Web + /// but we may want to trigger rebuilds from Umbraco.Core. These two assemblies should + /// be refactored, really. + /// + public interface IPublishedSnapshotRebuilder + { + /// + /// Rebuilds. + /// + void Rebuild(); + } +} diff --git a/src/Umbraco.Core/Migrations/PostMigrations/PublishedSnapshotRebuilder.cs b/src/Umbraco.Core/Migrations/PostMigrations/PublishedSnapshotRebuilder.cs new file mode 100644 index 0000000000..acc943b297 --- /dev/null +++ b/src/Umbraco.Core/Migrations/PostMigrations/PublishedSnapshotRebuilder.cs @@ -0,0 +1,12 @@ +namespace Umbraco.Core.Migrations.PostMigrations +{ + /// + /// Implements in Umbraco.Core (doing nothing). + /// + public class PublishedSnapshotRebuilder : IPublishedSnapshotRebuilder + { + /// + public void Rebuild() + { } + } +} diff --git a/src/Umbraco.Core/Migrations/PostMigrations/RebuildPublishedSnapshot.cs b/src/Umbraco.Core/Migrations/PostMigrations/RebuildPublishedSnapshot.cs new file mode 100644 index 0000000000..4905699fd4 --- /dev/null +++ b/src/Umbraco.Core/Migrations/PostMigrations/RebuildPublishedSnapshot.cs @@ -0,0 +1,24 @@ +namespace Umbraco.Core.Migrations.PostMigrations +{ + /// + /// Rebuilds the published snapshot. + /// + public class RebuildPublishedSnapshot : IMigration + { + private readonly IPublishedSnapshotRebuilder _rebuilder; + + /// + /// Initializes a new instance of the class. + /// + public RebuildPublishedSnapshot(IPublishedSnapshotRebuilder rebuilder) + { + _rebuilder = rebuilder; + } + + /// + public void Migrate() + { + _rebuilder.Rebuild(); + } + } +} diff --git a/src/Umbraco.Core/Migrations/Upgrade/UmbracoPlan.cs b/src/Umbraco.Core/Migrations/Upgrade/UmbracoPlan.cs index 0cd6ac8b16..4fa687fa5d 100644 --- a/src/Umbraco.Core/Migrations/Upgrade/UmbracoPlan.cs +++ b/src/Umbraco.Core/Migrations/Upgrade/UmbracoPlan.cs @@ -56,7 +56,7 @@ namespace Umbraco.Core.Migrations.Upgrade } } - // define the plan + // define the plan protected void DefinePlan() { // MODIFYING THE PLAN @@ -128,7 +128,7 @@ namespace Umbraco.Core.Migrations.Upgrade To("{38C809D5-6C34-426B-9BEA-EFD39162595C}"); To("{6017F044-8E70-4E10-B2A3-336949692ADD}"); To("{98339BEF-E4B2-48A8-B9D1-D173DC842BBE}"); - + Merge() .To("{CDBEDEE4-9496-4903-9CF2-4104E00FF960}") .With() diff --git a/src/Umbraco.Core/Migrations/Upgrade/UmbracoUpgrader.cs b/src/Umbraco.Core/Migrations/Upgrade/UmbracoUpgrader.cs deleted file mode 100644 index ac87b8c94d..0000000000 --- a/src/Umbraco.Core/Migrations/Upgrade/UmbracoUpgrader.cs +++ /dev/null @@ -1,48 +0,0 @@ -using System; -using System.Configuration; -using Semver; -using Umbraco.Core.Configuration; -using Umbraco.Core.Logging; -using Umbraco.Core.Scoping; -using Umbraco.Core.Services; - -namespace Umbraco.Core.Migrations.Upgrade -{ - /// - /// Represents the Umbraco upgrader. - /// - public class UmbracoUpgrader : Upgrader - { - private PostMigrationCollection _postMigrations; - - /// - /// Initializes a new instance of the class. - /// - public UmbracoUpgrader() - : base(new UmbracoPlan()) - { } - - /// - /// Executes. - /// - public void Execute(IScopeProvider scopeProvider, IMigrationBuilder migrationBuilder, IKeyValueService keyValueService, ILogger logger, PostMigrationCollection postMigrations) - { - _postMigrations = postMigrations; - Execute(scopeProvider, migrationBuilder, keyValueService, logger); - } - - /// - public override void AfterMigrations(IScope scope, ILogger logger) - { - // assume we have something in web.config that makes some sense = the origin version - if (!SemVersion.TryParse(ConfigurationManager.AppSettings[Constants.AppSettings.ConfigurationStatus], out var originVersion)) - throw new InvalidOperationException($"Could not get current version from web.config {Constants.AppSettings.ConfigurationStatus} appSetting."); - - // target version is the code version - var targetVersion = UmbracoVersion.SemanticVersion; - - foreach (var postMigration in _postMigrations) - postMigration.Execute(Name, scope, originVersion, targetVersion, logger); - } - } -} diff --git a/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/RadioAndCheckboxAndDropdownPropertyEditorsMigration.cs b/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/RadioAndCheckboxAndDropdownPropertyEditorsMigration.cs index 0da9d3b8ec..1944c8079f 100644 --- a/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/RadioAndCheckboxAndDropdownPropertyEditorsMigration.cs +++ b/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/RadioAndCheckboxAndDropdownPropertyEditorsMigration.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using Newtonsoft.Json; using Umbraco.Core.Logging; +using Umbraco.Core.Migrations.PostMigrations; using Umbraco.Core.Models; using Umbraco.Core.Persistence; using Umbraco.Core.Persistence.Dtos; @@ -27,7 +28,7 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0 if (refreshCache) { - //FIXME: trigger cache rebuild. Currently the data in the database tables is wrong. + Context.AddPostMigration(); } } diff --git a/src/Umbraco.Core/Runtime/CoreRuntimeComposer.cs b/src/Umbraco.Core/Runtime/CoreRuntimeComposer.cs index 2d1a4c1650..b4faddb5d0 100644 --- a/src/Umbraco.Core/Runtime/CoreRuntimeComposer.cs +++ b/src/Umbraco.Core/Runtime/CoreRuntimeComposer.cs @@ -10,6 +10,7 @@ using Umbraco.Core.Logging; using Umbraco.Core.Manifest; using Umbraco.Core.Migrations; using Umbraco.Core.Migrations.Install; +using Umbraco.Core.Migrations.PostMigrations; using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.PackageActions; using Umbraco.Core.Persistence; @@ -113,13 +114,13 @@ namespace Umbraco.Core.Runtime composition.WithCollectionBuilder() .Append(); - composition.WithCollectionBuilder() - .Add(() => composition.TypeLoader.GetTypes()); - composition.RegisterUnique(factory => new MigrationBuilder(factory)); // by default, register a noop factory composition.RegisterUnique(); + + // by default, register a noop rebuilder + composition.RegisterUnique(); } } } diff --git a/src/Umbraco.Core/RuntimeState.cs b/src/Umbraco.Core/RuntimeState.cs index 9ddbb09748..55255b418d 100644 --- a/src/Umbraco.Core/RuntimeState.cs +++ b/src/Umbraco.Core/RuntimeState.cs @@ -242,7 +242,7 @@ namespace Umbraco.Core protected virtual bool EnsureUmbracoUpgradeState(IUmbracoDatabaseFactory databaseFactory, ILogger logger) { - var upgrader = new UmbracoUpgrader(); + var upgrader = new Upgrader(new UmbracoPlan()); var stateValueKey = upgrader.StateValueKey; // no scope, no service - just directly accessing the database diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index f6e8a9c9de..08a2c552cb 100755 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -351,6 +351,9 @@ + + + @@ -666,15 +669,11 @@ - - - - diff --git a/src/Umbraco.Tests/Migrations/MigrationTests.cs b/src/Umbraco.Tests/Migrations/MigrationTests.cs index 8e84f88265..6b2d21e4a5 100644 --- a/src/Umbraco.Tests/Migrations/MigrationTests.cs +++ b/src/Umbraco.Tests/Migrations/MigrationTests.cs @@ -16,32 +16,6 @@ namespace Umbraco.Tests.Migrations [TestFixture] public class MigrationTests { - public class TestUpgraderWithPostMigrations : Upgrader - { - private PostMigrationCollection _postMigrations; - - public TestUpgraderWithPostMigrations(MigrationPlan plan) - : base(plan) - { } - - public void Execute(IScopeProvider scopeProvider, IMigrationBuilder migrationBuilder, IKeyValueService keyValueService, ILogger logger, PostMigrationCollection postMigrations) - { - _postMigrations = postMigrations; - Execute(scopeProvider, migrationBuilder, keyValueService, logger); - } - - public override void AfterMigrations(IScope scope, ILogger logger) - { - // run post-migrations - var originVersion = new SemVersion(0); - var targetVersion = new SemVersion(0); - - // run post-migrations - foreach (var postMigration in _postMigrations) - postMigration.Execute(Name, scope, originVersion, targetVersion, logger); - } - } - public class TestScopeProvider : IScopeProvider { private readonly IScope _scope; diff --git a/src/Umbraco.Tests/Migrations/PostMigrationTests.cs b/src/Umbraco.Tests/Migrations/PostMigrationTests.cs index 95f1f8afac..3e96ddb435 100644 --- a/src/Umbraco.Tests/Migrations/PostMigrationTests.cs +++ b/src/Umbraco.Tests/Migrations/PostMigrationTests.cs @@ -2,10 +2,9 @@ using Moq; using NPoco; using NUnit.Framework; -using Semver; -using Umbraco.Core; using Umbraco.Core.Logging; using Umbraco.Core.Migrations; +using Umbraco.Core.Migrations.Upgrade; using Umbraco.Core.Persistence; using Umbraco.Core.Persistence.SqlSyntax; using Umbraco.Core.Scoping; @@ -18,15 +17,10 @@ namespace Umbraco.Tests.Migrations public class PostMigrationTests { [Test] - public void Executes_For_Any_Product_Name_When_Not_Specified() + public void ExecutesPlanPostMigration() { var logger = Mock.Of(); - var changed1 = new Args { CountExecuted = 0 }; - var post1 = new TestPostMigration(changed1); - - var posts = new PostMigrationCollection(new [] { post1 }); - var builder = Mock.Of(); Mock.Get(builder) .Setup(x => x.Build(It.IsAny(), It.IsAny())) @@ -34,8 +28,10 @@ namespace Umbraco.Tests.Migrations { switch (t.Name) { - case "NoopMigration": + case nameof(NoopMigration): return new NoopMigration(); + case nameof(TestPostMigration): + return new TestPostMigration(); default: throw new NotSupportedException(); } @@ -50,26 +46,23 @@ namespace Umbraco.Tests.Migrations var sqlContext = new SqlContext(new SqlCeSyntaxProvider(), DatabaseType.SQLCe, Mock.Of()); var scopeProvider = new MigrationTests.TestScopeProvider(scope) { SqlContext = sqlContext }; - var u1 = new MigrationTests.TestUpgraderWithPostMigrations( - new MigrationPlan("Test").From(string.Empty).To("done")); - u1.Execute(scopeProvider, builder, Mock.Of(), logger, posts); + var plan = new MigrationPlan("Test") + .From(string.Empty).To("done"); - Assert.AreEqual(1, changed1.CountExecuted); + plan.AddPostMigration(); + TestPostMigration.MigrateCount = 0; + + var upgrader = new Upgrader(plan); + upgrader.Execute(scopeProvider, builder, Mock.Of(), logger); + + Assert.AreEqual(1, TestPostMigration.MigrateCount); } [Test] - public void Executes_Only_For_Specified_Product_Name() + public void MigrationCanAddPostMigration() { var logger = Mock.Of(); - var changed1 = new Args { CountExecuted = 0}; - var post1 = new TestPostMigration("Test1", changed1); - - var changed2 = new Args { CountExecuted = 0 }; - var post2 = new TestPostMigration("Test2", changed2); - - var posts = new PostMigrationCollection(new [] { post1, post2 }); - var builder = Mock.Of(); Mock.Get(builder) .Setup(x => x.Build(It.IsAny(), It.IsAny())) @@ -77,8 +70,12 @@ namespace Umbraco.Tests.Migrations { switch (t.Name) { - case "NoopMigration": + case nameof(NoopMigration): return new NoopMigration(); + case nameof(TestMigration): + return new TestMigration(c); + case nameof(TestPostMigration): + return new TestPostMigration(); default: throw new NotSupportedException(); } @@ -93,52 +90,44 @@ namespace Umbraco.Tests.Migrations var sqlContext = new SqlContext(new SqlCeSyntaxProvider(), DatabaseType.SQLCe, Mock.Of()); var scopeProvider = new MigrationTests.TestScopeProvider(scope) { SqlContext = sqlContext }; - var u1 = new MigrationTests.TestUpgraderWithPostMigrations( - new MigrationPlan("Test1").From(string.Empty).To("done")); - u1.Execute(scopeProvider, builder, Mock.Of(), logger, posts); + var plan = new MigrationPlan("Test") + .From(string.Empty).To("done"); - Assert.AreEqual(1, changed1.CountExecuted); - Assert.AreEqual(0, changed2.CountExecuted); + TestMigration.MigrateCount = 0; + TestPostMigration.MigrateCount = 0; - var u2 = new MigrationTests.TestUpgraderWithPostMigrations( - new MigrationPlan("Test2").From(string.Empty).To("done")); - u2.Execute(scopeProvider, builder, Mock.Of(), logger, posts); + new MigrationContext(database, logger); - Assert.AreEqual(1, changed1.CountExecuted); - Assert.AreEqual(1, changed2.CountExecuted); + var upgrader = new Upgrader(plan); + upgrader.Execute(scopeProvider, builder, Mock.Of(), logger); + + Assert.AreEqual(1, TestMigration.MigrateCount); + Assert.AreEqual(1, TestPostMigration.MigrateCount); } - public class Args + public class TestMigration : MigrationBase { - public int CountExecuted { get; set; } + public TestMigration(IMigrationContext context) + : base(context) + { } + + public static int MigrateCount { get; set; } + + public override void Migrate() + { + MigrateCount++; + + Context.AddPostMigration(); + } } - public class TestPostMigration : IPostMigration + public class TestPostMigration : IMigration { - private readonly string _prodName; - private readonly Args _changed; + public static int MigrateCount { get; set; } - // need that one else it breaks IoC - public TestPostMigration() + public void Migrate() { - _changed = new Args(); - } - - public TestPostMigration(Args changed) - { - _changed = changed; - } - - public TestPostMigration(string prodName, Args changed) - { - _prodName = prodName; - _changed = changed; - } - - public void Execute(string name, IScope scope, SemVersion originVersion, SemVersion targetVersion, ILogger logger) - { - if (_prodName.IsNullOrWhiteSpace() == false && name != _prodName) return; - _changed.CountExecuted++; + MigrateCount++; } } } diff --git a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj index 922181bb89..d0e69435d0 100644 --- a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj +++ b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj @@ -21,13 +21,13 @@ - Web.config @@ -188,9 +188,17 @@ Designer + + serilog.user.config + Designer + Designer + + serilog.config + Designer + umbracoSettings.config @@ -364,6 +372,11 @@ + + + + + @@ -413,4 +426,4 @@ - \ No newline at end of file + diff --git a/src/Umbraco.Web.UI/config/serilog.config b/src/Umbraco.Web.UI/config/serilog.Release.config similarity index 100% rename from src/Umbraco.Web.UI/config/serilog.config rename to src/Umbraco.Web.UI/config/serilog.Release.config diff --git a/src/Umbraco.Web.UI/config/serilog.user.config b/src/Umbraco.Web.UI/config/serilog.user.Release.config similarity index 100% rename from src/Umbraco.Web.UI/config/serilog.user.config rename to src/Umbraco.Web.UI/config/serilog.user.Release.config diff --git a/src/Umbraco.Web/Composing/Composers/InstallerComposer.cs b/src/Umbraco.Web/Composing/Composers/InstallerComposer.cs index f73491f1fb..4051dc0306 100644 --- a/src/Umbraco.Web/Composing/Composers/InstallerComposer.cs +++ b/src/Umbraco.Web/Composing/Composers/InstallerComposer.cs @@ -20,10 +20,9 @@ namespace Umbraco.Web.Composing.Composers composition.Register(Lifetime.Scope); composition.Register(Lifetime.Scope); - // TODO: Add these back once we have a compatible starter kit - //container.Register(Lifetime.Scope); - //container.Register(Lifetime.Scope); - //container.Register(Lifetime.Scope); + composition.Register(Lifetime.Scope); + composition.Register(Lifetime.Scope); + composition.Register(Lifetime.Scope); composition.Register(Lifetime.Scope); diff --git a/src/Umbraco.Web/Editors/ContentController.cs b/src/Umbraco.Web/Editors/ContentController.cs index 27d63d9d7a..011c69c336 100644 --- a/src/Umbraco.Web/Editors/ContentController.cs +++ b/src/Umbraco.Web/Editors/ContentController.cs @@ -464,6 +464,16 @@ namespace Umbraco.Web.Editors { long totalChildren; List children; + + // Sets the culture to the only existing culture if we only have one culture. + if (string.IsNullOrWhiteSpace(cultureName)) + { + if (_allLangs.Value.Count == 1) + { + cultureName = _allLangs.Value.First().Key; + } + } + if (pageNumber > 0 && pageSize > 0) { IQuery queryFilter = null; @@ -1200,7 +1210,7 @@ namespace Umbraco.Web.Editors if (canPublish) { var culturesToPublish = cultureVariants.Where(x => x.Publish).Select(x => x.Culture).ToArray(); - + //proceed to publish if all validation still succeeds var publishStatus = Services.ContentService.SaveAndPublish(contentItem.PersistedContent, culturesToPublish, Security.CurrentUser.Id); wasCancelled = publishStatus.Result == PublishResultType.FailedPublishCancelledByEvent; diff --git a/src/Umbraco.Web/Editors/NuCacheStatusController.cs b/src/Umbraco.Web/Editors/NuCacheStatusController.cs index fb4b54c2b2..86dbdd4e01 100644 --- a/src/Umbraco.Web/Editors/NuCacheStatusController.cs +++ b/src/Umbraco.Web/Editors/NuCacheStatusController.cs @@ -14,8 +14,7 @@ namespace Umbraco.Web.Editors public NuCacheStatusController(IPublishedSnapshotService publishedSnapshotService) { - if (publishedSnapshotService == null) throw new ArgumentNullException(nameof(publishedSnapshotService)); - _publishedSnapshotService = publishedSnapshotService; + _publishedSnapshotService = publishedSnapshotService ?? throw new ArgumentNullException(nameof(publishedSnapshotService)); } private PublishedSnapshotService PublishedSnapshotService diff --git a/src/Umbraco.Web/Install/InstallStepCollection.cs b/src/Umbraco.Web/Install/InstallStepCollection.cs index fd8f248325..125572fef8 100644 --- a/src/Umbraco.Web/Install/InstallStepCollection.cs +++ b/src/Umbraco.Web/Install/InstallStepCollection.cs @@ -26,10 +26,9 @@ namespace Umbraco.Web.Install a.OfType().First(), a.OfType().First(), - // TODO: Add these back once we have a compatible starter kit - //orderedInstallerSteps.OfType().First(), - //orderedInstallerSteps.OfType().First(), - //orderedInstallerSteps.OfType().First(), + a.OfType().First(), + a.OfType().First(), + a.OfType().First(), a.OfType().First(), }; diff --git a/src/Umbraco.Web/Install/InstallSteps/DatabaseUpgradeStep.cs b/src/Umbraco.Web/Install/InstallSteps/DatabaseUpgradeStep.cs index e8046bd196..4e8068c4c5 100644 --- a/src/Umbraco.Web/Install/InstallSteps/DatabaseUpgradeStep.cs +++ b/src/Umbraco.Web/Install/InstallSteps/DatabaseUpgradeStep.cs @@ -5,7 +5,10 @@ using System.Threading.Tasks; using Umbraco.Core; using Umbraco.Core.Logging; using Umbraco.Core.Migrations.Install; +using Umbraco.Core.Migrations.Upgrade; using Umbraco.Web.Install.Models; +using Umbraco.Web.Migrations; +using Umbraco.Web.Migrations.PostMigrations; namespace Umbraco.Web.Install.InstallSteps { @@ -34,7 +37,10 @@ namespace Umbraco.Web.Install.InstallSteps { _logger.Info("Running 'Upgrade' service"); - var result = _databaseBuilder.UpgradeSchemaAndData(); + var plan = new UmbracoPlan(); + plan.AddPostMigration(); // needed when running installer (back-office) + + var result = _databaseBuilder.UpgradeSchemaAndData(plan); if (result.Success == false) { diff --git a/src/Umbraco.Web/Install/InstallSteps/SetUmbracoVersionStep.cs b/src/Umbraco.Web/Install/InstallSteps/SetUmbracoVersionStep.cs index 55d7d49ba9..c1268ca675 100644 --- a/src/Umbraco.Web/Install/InstallSteps/SetUmbracoVersionStep.cs +++ b/src/Umbraco.Web/Install/InstallSteps/SetUmbracoVersionStep.cs @@ -46,11 +46,6 @@ namespace Umbraco.Web.Install.InstallSteps security.PerformLogin(-1); } - // Some upgrade scripts "may modify the database (cmsContentXml...) tables directly" - not sure - // that is still true but the idea is that after an upgrade we want to reset the local published snapshot, on - // all LB nodes of course, so we need to use the distributed cache, and refresh everything. - _distributedCache.RefreshAllPublishedSnapshot(); - // Update configurationStatus _globalSettings.ConfigurationStatus = UmbracoVersion.SemanticVersion.ToSemanticString(); diff --git a/src/Umbraco.Web/Install/InstallSteps/StarterKitCleanupStep.cs b/src/Umbraco.Web/Install/InstallSteps/StarterKitCleanupStep.cs index 6b90ff0a78..d693b171db 100644 --- a/src/Umbraco.Web/Install/InstallSteps/StarterKitCleanupStep.cs +++ b/src/Umbraco.Web/Install/InstallSteps/StarterKitCleanupStep.cs @@ -1,7 +1,9 @@ using System; +using System.IO; using System.Linq; using System.Threading.Tasks; using System.Web; +using Umbraco.Core.IO; using Umbraco.Web.Install.Models; namespace Umbraco.Web.Install.InstallSteps @@ -24,9 +26,10 @@ namespace Umbraco.Web.Install.InstallSteps private void CleanupInstallation(int packageId, string packageFile) { - packageFile = HttpUtility.UrlDecode(packageFile); + var zipFile = new FileInfo(Path.Combine(IOHelper.MapPath(SystemDirectories.Packages), HttpUtility.UrlDecode(packageFile))); - // TODO: When does the zip file get deleted? + if (zipFile.Exists) + zipFile.Delete(); } public override bool RequiresExecution(object model) diff --git a/src/Umbraco.Web/Install/InstallSteps/StarterKitDownloadStep.cs b/src/Umbraco.Web/Install/InstallSteps/StarterKitDownloadStep.cs index 641146fb4a..82526904d2 100644 --- a/src/Umbraco.Web/Install/InstallSteps/StarterKitDownloadStep.cs +++ b/src/Umbraco.Web/Install/InstallSteps/StarterKitDownloadStep.cs @@ -70,20 +70,18 @@ namespace Umbraco.Web.Install.InstallSteps //add an entry to the installedPackages.config var compiledPackage = _packageService.GetCompiledPackageInfo(packageFile); var packageDefinition = PackageDefinition.FromCompiledPackage(compiledPackage); + packageDefinition.PackagePath = packageFile.FullName; + _packageService.SaveInstalledPackage(packageDefinition); - InstallPackageFiles(packageDefinition, compiledPackage.PackageFile); + _packageService.InstallCompiledPackageFiles(packageDefinition, packageFile, _umbracoContext.Security.GetUserId().ResultOr(-1)); return (compiledPackage.PackageFile.Name, packageDefinition.Id); } - private void InstallPackageFiles(PackageDefinition packageDefinition, FileInfo packageFile) - { - if (packageDefinition == null) throw new ArgumentNullException(nameof(packageDefinition)); - - _packageService.InstallCompiledPackageData(packageDefinition, packageFile, _umbracoContext.Security.GetUserId().ResultOr(0)); - } - + /// + /// Don't show the view if there's already packages installed + /// public override string View => _packageService.GetAllInstalledPackages().Any() ? string.Empty : base.View; public override bool RequiresExecution(Guid? model) @@ -94,6 +92,7 @@ namespace Umbraco.Web.Install.InstallSteps return false; } + //Don't continue if there's already packages installed if (_packageService.GetAllInstalledPackages().Any()) return false; diff --git a/src/Umbraco.Web/Install/InstallSteps/StarterKitInstallStep.cs b/src/Umbraco.Web/Install/InstallSteps/StarterKitInstallStep.cs index 8a61f9230c..62c2f87c08 100644 --- a/src/Umbraco.Web/Install/InstallSteps/StarterKitInstallStep.cs +++ b/src/Umbraco.Web/Install/InstallSteps/StarterKitInstallStep.cs @@ -46,7 +46,7 @@ namespace Umbraco.Web.Install.InstallSteps var packageFile = new FileInfo(definition.PackagePath); - _packagingService.InstallCompiledPackageData(definition, packageFile, _umbracoContext.Security.GetUserId().ResultOr(0)); + _packagingService.InstallCompiledPackageData(definition, packageFile, _umbracoContext.Security.GetUserId().ResultOr(-1)); } public override bool RequiresExecution(object model) diff --git a/src/Umbraco.Web/Migrations/ClearCsrfCookiesAfterUpgrade.cs b/src/Umbraco.Web/Migrations/PostMigrations/ClearCsrfCookies.cs similarity index 50% rename from src/Umbraco.Web/Migrations/ClearCsrfCookiesAfterUpgrade.cs rename to src/Umbraco.Web/Migrations/PostMigrations/ClearCsrfCookies.cs index 75ba97097b..2267f775be 100644 --- a/src/Umbraco.Web/Migrations/ClearCsrfCookiesAfterUpgrade.cs +++ b/src/Umbraco.Web/Migrations/PostMigrations/ClearCsrfCookies.cs @@ -1,21 +1,16 @@ using System.Web; -using Semver; -using Umbraco.Core; -using Umbraco.Core.Logging; using Umbraco.Core.Migrations; -using Umbraco.Core.Scoping; using Umbraco.Web.WebApi.Filters; -namespace Umbraco.Web.Migrations +namespace Umbraco.Web.Migrations.PostMigrations { /// - /// After upgrade we clear out the csrf tokens + /// Clears Csrf tokens. /// - public class ClearCsrfCookiesAfterUpgrade : IPostMigration + public class ClearCsrfCookies : IMigration { - public void Execute(string name, IScope scope, SemVersion originVersion, SemVersion targetVersion, ILogger logger) + public void Migrate() { - if (name != Constants.System.UmbracoUpgradePlanName) return; if (HttpContext.Current == null) return; var http = new HttpContextWrapper(HttpContext.Current); diff --git a/src/Umbraco.Web/Migrations/PostMigrations/PublishedSnapshotRebuilder.cs b/src/Umbraco.Web/Migrations/PostMigrations/PublishedSnapshotRebuilder.cs new file mode 100644 index 0000000000..764e46af5d --- /dev/null +++ b/src/Umbraco.Web/Migrations/PostMigrations/PublishedSnapshotRebuilder.cs @@ -0,0 +1,31 @@ +using Umbraco.Core.Migrations.PostMigrations; +using Umbraco.Web.Cache; +using Umbraco.Web.PublishedCache; + +namespace Umbraco.Web.Migrations.PostMigrations +{ + /// + /// Implements in Umbraco.Web (rebuilding). + /// + public class PublishedSnapshotRebuilder : IPublishedSnapshotRebuilder + { + private readonly IPublishedSnapshotService _publishedSnapshotService; + private readonly DistributedCache _distributedCache; + + /// + /// Initializes a new instance of the class. + /// + public PublishedSnapshotRebuilder(IPublishedSnapshotService publishedSnapshotService, DistributedCache distributedCache) + { + _publishedSnapshotService = publishedSnapshotService; + _distributedCache = distributedCache; + } + + /// + public void Rebuild() + { + _publishedSnapshotService.Rebuild(); + _distributedCache.RefreshAllPublishedSnapshot(); + } + } +} diff --git a/src/Umbraco.Web/Models/Mapping/PropertyTypeGroupResolver.cs b/src/Umbraco.Web/Models/Mapping/PropertyTypeGroupResolver.cs index fbd7be4ecd..89d731efa2 100644 --- a/src/Umbraco.Web/Models/Mapping/PropertyTypeGroupResolver.cs +++ b/src/Umbraco.Web/Models/Mapping/PropertyTypeGroupResolver.cs @@ -198,12 +198,15 @@ namespace Umbraco.Web.Models.Mapping foreach (var p in properties.Where(x => x.DataTypeId != 0).OrderBy(x => x.SortOrder)) { + var propertyEditor = _propertyEditors[p.PropertyEditorAlias]; - var configuration = _dataTypeService.GetDataType(p.DataTypeId).Configuration; + var dataType = _dataTypeService.GetDataType(p.DataTypeId); if (propertyEditor == null) throw new InvalidOperationException("No property editor could be resolved with the alias: " + p.PropertyEditorAlias + ", ensure all packages are installed correctly."); + var config = dataType.Editor.GetConfigurationEditor().ToConfigurationEditor(dataType.Configuration); + mappedProperties.Add(new TPropertyType { Id = p.Id, @@ -213,7 +216,7 @@ namespace Umbraco.Web.Models.Mapping Validation = new PropertyTypeValidation {Mandatory = p.Mandatory, Pattern = p.ValidationRegExp}, Label = p.Name, View = propertyEditor.GetValueEditor().View, - Config = propertyEditor.GetConfigurationEditor().ToConfigurationEditor(configuration), + Config = config, //Value = "", GroupId = groupId, Inherited = inherited, diff --git a/src/Umbraco.Web/PublishedCache/IPublishedSnapshotService.cs b/src/Umbraco.Web/PublishedCache/IPublishedSnapshotService.cs index ccdac5664d..9949b4b3f8 100644 --- a/src/Umbraco.Web/PublishedCache/IPublishedSnapshotService.cs +++ b/src/Umbraco.Web/PublishedCache/IPublishedSnapshotService.cs @@ -48,6 +48,21 @@ namespace Umbraco.Web.PublishedCache #endregion + #region Rebuild + + /// + /// Rebuilds internal caches (but does not reload). + /// + /// + /// Forces the snapshot service to rebuild its internal caches. For instance, some caches + /// may rely on a database table to store pre-serialized version of documents. + /// This does *not* reload the caches. Caches need to be reloaded, for instance via + /// RefreshAllPublishedSnapshot method. + /// + void Rebuild(); + + #endregion + #region Preview /* Later on we can imagine that EnterPreview would handle a "level" that would be either diff --git a/src/Umbraco.Web/PublishedCache/NuCache/PublishedSnapshotService.cs b/src/Umbraco.Web/PublishedCache/NuCache/PublishedSnapshotService.cs index cc1216eb68..023b8c999a 100755 --- a/src/Umbraco.Web/PublishedCache/NuCache/PublishedSnapshotService.cs +++ b/src/Umbraco.Web/PublishedCache/NuCache/PublishedSnapshotService.cs @@ -27,6 +27,7 @@ using Umbraco.Web.Cache; using Umbraco.Web.Install; using Umbraco.Web.PublishedCache.NuCache.DataSource; using Umbraco.Web.Routing; +using File = System.IO.File; namespace Umbraco.Web.PublishedCache.NuCache { @@ -142,31 +143,7 @@ namespace Umbraco.Web.PublishedCache.NuCache if (registered) { - string path; - var tempLocation = globalSettings.LocalTempStorageLocation; - switch (tempLocation) - { - case LocalTempStorage.AspNetTemp: - path = Path.Combine(HttpRuntime.CodegenDir, "UmbracoData", "NuCache"); - break; - case LocalTempStorage.EnvironmentTemp: - // TODO: why has this to be repeated everywhere?! - // include the appdomain hash is just a safety check, for example if a website is moved from worker A to worker B and then back - // to worker A again, in theory the %temp% folder should already be empty but we really want to make sure that its not - // utilizing an old path - assuming we cannot have SHA1 collisions on AppDomainAppId - var appDomainHash = HttpRuntime.AppDomainAppId.GenerateHash(); - path = Path.Combine(Environment.ExpandEnvironmentVariables("%temp%"), "UmbracoData", appDomainHash, "NuCache"); - break; - //case LocalTempStorage.Default: - //case LocalTempStorage.Unknown: - default: - path = IOHelper.MapPath("~/App_Data/TEMP/NuCache"); - break; - } - - if (!Directory.Exists(path)) - Directory.CreateDirectory(path); - + var path = GetLocalFilesPath(); var localContentDbPath = Path.Combine(path, "NuCache.Content.db"); var localMediaDbPath = Path.Combine(path, "NuCache.Media.db"); _localDbExists = System.IO.File.Exists(localContentDbPath) && System.IO.File.Exists(localMediaDbPath); @@ -295,13 +272,69 @@ namespace Umbraco.Web.PublishedCache.NuCache #endregion + #region Local files + + private string GetLocalFilesPath() + { + string path; + var tempLocation = _globalSettings.LocalTempStorageLocation; + switch (tempLocation) + { + case LocalTempStorage.AspNetTemp: + path = Path.Combine(HttpRuntime.CodegenDir, "UmbracoData", "NuCache"); + break; + case LocalTempStorage.EnvironmentTemp: + // TODO: why has this to be repeated everywhere?! + // include the appdomain hash is just a safety check, for example if a website is moved from worker A to worker B and then back + // to worker A again, in theory the %temp% folder should already be empty but we really want to make sure that its not + // utilizing an old path - assuming we cannot have SHA1 collisions on AppDomainAppId + var appDomainHash = HttpRuntime.AppDomainAppId.GenerateHash(); + path = Path.Combine(Environment.ExpandEnvironmentVariables("%temp%"), "UmbracoData", appDomainHash, "NuCache"); + break; + //case LocalTempStorage.Default: + //case LocalTempStorage.Unknown: + default: + path = IOHelper.MapPath("~/App_Data/TEMP/NuCache"); + break; + } + + if (!Directory.Exists(path)) + Directory.CreateDirectory(path); + + return path; + } + + private void DeleteLocalFilesForContent() + { + if (_isReady && _localContentDb != null) + throw new InvalidOperationException("Cannot delete local files while the cache uses them."); + + var path = GetLocalFilesPath(); + var localContentDbPath = Path.Combine(path, "NuCache.Content.db"); + if (File.Exists(localContentDbPath)) + File.Delete(localContentDbPath); + } + + private void DeleteLocalFilesForMedia() + { + if (_isReady && _localMediaDb != null) + throw new InvalidOperationException("Cannot delete local files while the cache uses them."); + + var path = GetLocalFilesPath(); + var localMediaDbPath = Path.Combine(path, "NuCache.Media.db"); + if (File.Exists(localMediaDbPath)) + File.Delete(localMediaDbPath); + } + + #endregion + #region Environment public override bool EnsureEnvironment(out IEnumerable errors) { // must have app_data and be able to write files into it - var ok = FilePermissionHelper.TryCreateDirectory(SystemDirectories.Data); - errors = ok ? Enumerable.Empty() : new[] { "NuCache local DB files." }; + var ok = FilePermissionHelper.TryCreateDirectory(GetLocalFilesPath()); + errors = ok ? Enumerable.Empty() : new[] { "NuCache local files." }; return ok; } @@ -560,10 +593,11 @@ namespace Umbraco.Web.PublishedCache.NuCache public override void Notify(ContentCacheRefresher.JsonPayload[] payloads, out bool draftChanged, out bool publishedChanged) { - // no cache, nothing we can do + // no cache, trash everything if (_isReady == false) { - draftChanged = publishedChanged = false; + DeleteLocalFilesForContent(); + draftChanged = publishedChanged = true; return; } @@ -655,10 +689,11 @@ namespace Umbraco.Web.PublishedCache.NuCache public override void Notify(MediaCacheRefresher.JsonPayload[] payloads, out bool anythingChanged) { - // no cache, nothing we can do + // no cache, trash everything if (_isReady == false) { - anythingChanged = false; + DeleteLocalFilesForMedia(); + anythingChanged = true; return; } @@ -1277,6 +1312,21 @@ namespace Umbraco.Web.PublishedCache.NuCache #region Rebuild Database PreCache + public override void Rebuild() + { + _logger.Debug("Rebuilding..."); + using (var scope = _scopeProvider.CreateScope(repositoryCacheMode: RepositoryCacheMode.Scoped)) + { + scope.ReadLock(Constants.Locks.ContentTree); + scope.ReadLock(Constants.Locks.MediaTree); + scope.ReadLock(Constants.Locks.MemberTree); + RebuildContentDbCacheLocked(scope, 5000, null); + RebuildMediaDbCacheLocked(scope, 5000, null); + RebuildMemberDbCacheLocked(scope, 5000, null); + scope.Complete(); + } + } + public void RebuildContentDbCache(int groupSize = 5000, IEnumerable contentTypeIds = null) { using (var scope = _scopeProvider.CreateScope(repositoryCacheMode: RepositoryCacheMode.Scoped)) diff --git a/src/Umbraco.Web/PublishedCache/PublishedSnapshotServiceBase.cs b/src/Umbraco.Web/PublishedCache/PublishedSnapshotServiceBase.cs index 74e08e92e8..20d3e6d8e3 100644 --- a/src/Umbraco.Web/PublishedCache/PublishedSnapshotServiceBase.cs +++ b/src/Umbraco.Web/PublishedCache/PublishedSnapshotServiceBase.cs @@ -33,6 +33,9 @@ namespace Umbraco.Web.PublishedCache public abstract void Notify(DataTypeCacheRefresher.JsonPayload[] payloads); public abstract void Notify(DomainCacheRefresher.JsonPayload[] payloads); + public virtual void Rebuild() + { } + public virtual void Dispose() { } } diff --git a/src/Umbraco.Web/Runtime/WebRuntimeComposer.cs b/src/Umbraco.Web/Runtime/WebRuntimeComposer.cs index 52373184b4..6e82177c89 100644 --- a/src/Umbraco.Web/Runtime/WebRuntimeComposer.cs +++ b/src/Umbraco.Web/Runtime/WebRuntimeComposer.cs @@ -9,6 +9,8 @@ using Umbraco.Core.Composing; using Umbraco.Core.Dashboards; using Umbraco.Core.Dictionary; using Umbraco.Core.Events; +using Umbraco.Core.Migrations.PostMigrations; +using Umbraco.Web.Migrations.PostMigrations; using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.PropertyEditors; using Umbraco.Core.PropertyEditors.ValueConverters; @@ -249,6 +251,9 @@ namespace Umbraco.Web.Runtime .Append() .Append() .Append(); + + // replace with web implementation + composition.RegisterUnique(); } } } diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index f7f6c044de..fa83b90ab8 100755 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -197,6 +197,7 @@ + @@ -886,7 +887,7 @@ - +