Merge remote-tracking branch 'origin/temp8' into temp8-implement-GetByContentType-nucache

This commit is contained in:
Shannon
2019-02-14 09:52:09 +11:00
34 changed files with 351 additions and 259 deletions

View File

@@ -110,13 +110,6 @@ namespace Umbraco.Core.Components
internal static ManifestValueValidatorCollectionBuilder Validators(this Composition composition)
=> composition.WithCollectionBuilder<ManifestValueValidatorCollectionBuilder>();
/// <summary>
/// Gets the post-migrations collection builder.
/// </summary>
/// <param name="composition">The composition.</param>
internal static PostMigrationCollectionBuilder PostMigrations(this Composition composition)
=> composition.WithCollectionBuilder<PostMigrationCollectionBuilder>();
/// <summary>
/// Gets the components collection builder.
/// </summary>

View File

@@ -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.
/// </summary>
bool BuildingExpression { get; set; }
/// <summary>
/// Adds a post-migrations.
/// </summary>
void AddPostMigration<TMigration>()
where TMigration : IMigration;
}
}

View File

@@ -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);
}
}

View File

@@ -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
/// <summary>
/// Initializes a new instance of the <see cref="DatabaseBuilder"/> class.
/// </summary>
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.</para>
/// <para>Runs whichever migrations need to run.</para>
/// </remarks>
public Result UpgradeSchemaAndData()
public Result UpgradeSchemaAndData(MigrationPlan plan)
{
try
{
@@ -496,8 +494,8 @@ namespace Umbraco.Core.Migrations.Install
_logger.Info<DatabaseBuilder>("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 = "<p>Upgrade completed!</p>";

View File

@@ -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;

View File

@@ -1,11 +1,12 @@
using System;
using System.Collections.Generic;
using Umbraco.Core.Logging;
using Umbraco.Core.Persistence;
namespace Umbraco.Core.Migrations
{
/// <summary>
/// Represents a migration context.
/// Implements <see cref="IMigrationContext"/>.
/// </summary>
internal class MigrationContext : IMigrationContext
{
@@ -32,5 +33,15 @@ namespace Umbraco.Core.Migrations
/// <inheritdoc />
public bool BuildingExpression { get; set; }
// this is only internally exposed
public List<Type> PostMigrations { get; } = new List<Type>();
/// <inheritdoc />
public void AddPostMigration<TMigration>()
where TMigration : IMigration
{
PostMigrations.Add(typeof(TMigration));
}
}
}

View File

@@ -14,6 +14,7 @@ namespace Umbraco.Core.Migrations
public class MigrationPlan
{
private readonly Dictionary<string, Transition> _transitions = new Dictionary<string, Transition>();
private readonly List<Type> _postMigrationTypes = new List<Type>();
private string _prevState;
private string _finalState;
@@ -166,6 +167,25 @@ namespace Umbraco.Core.Migrations
return this;
}
/// <summary>
/// Prepares post-migrations.
/// </summary>
/// <remarks>
/// <para>This can be overriden to filter, complement, and/or re-order post-migrations.</para>
/// </remarks>
protected virtual IEnumerable<Type> PreparePostMigrations(IEnumerable<Type> types)
=> types;
/// <summary>
/// Adds a post-migration to the plan.
/// </summary>
public virtual MigrationPlan AddPostMigration<TMigration>()
where TMigration : IMigration
{
_postMigrationTypes.Add(typeof(TMigration));
return this;
}
/// <summary>
/// Creates a random, unique state.
/// </summary>
@@ -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<Type>();
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<MigrationPlan>($"PostMigration: {postMigrationType.FullName}.");
var postMigration = migrationBuilder.Build(postMigrationType, context);
postMigration.Migrate();
}
logger.Info<MigrationPlan>("Done (pending scope completion).");
// safety check

View File

@@ -1,12 +0,0 @@
using System.Collections.Generic;
using Umbraco.Core.Composing;
namespace Umbraco.Core.Migrations
{
public class PostMigrationCollection : BuilderCollectionBase<IPostMigration>
{
public PostMigrationCollection(IEnumerable<IPostMigration> items)
: base(items)
{ }
}
}

View File

@@ -1,11 +0,0 @@
using Umbraco.Core.Composing;
namespace Umbraco.Core.Migrations
{
public class PostMigrationCollectionBuilder : LazyCollectionBuilderBase<PostMigrationCollectionBuilder, PostMigrationCollection, IPostMigration>
{
protected override PostMigrationCollectionBuilder This => this;
protected override Lifetime CollectionLifetime => Lifetime.Transient;
}
}

View File

@@ -0,0 +1,18 @@
namespace Umbraco.Core.Migrations.PostMigrations
{
/// <summary>
/// Rebuilds the published snapshot.
/// </summary>
/// <remarks>
/// <para>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.</para>
/// </remarks>
public interface IPublishedSnapshotRebuilder
{
/// <summary>
/// Rebuilds.
/// </summary>
void Rebuild();
}
}

View File

@@ -0,0 +1,12 @@
namespace Umbraco.Core.Migrations.PostMigrations
{
/// <summary>
/// Implements <see cref="IPublishedSnapshotRebuilder"/> in Umbraco.Core (doing nothing).
/// </summary>
public class PublishedSnapshotRebuilder : IPublishedSnapshotRebuilder
{
/// <inheritdoc />
public void Rebuild()
{ }
}
}

View File

@@ -0,0 +1,24 @@
namespace Umbraco.Core.Migrations.PostMigrations
{
/// <summary>
/// Rebuilds the published snapshot.
/// </summary>
public class RebuildPublishedSnapshot : IMigration
{
private readonly IPublishedSnapshotRebuilder _rebuilder;
/// <summary>
/// Initializes a new instance of the <see cref="RebuildPublishedSnapshot"/> class.
/// </summary>
public RebuildPublishedSnapshot(IPublishedSnapshotRebuilder rebuilder)
{
_rebuilder = rebuilder;
}
/// <inheritdoc />
public void Migrate()
{
_rebuilder.Rebuild();
}
}
}

View File

@@ -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
{
/// <summary>
/// Represents the Umbraco upgrader.
/// </summary>
public class UmbracoUpgrader : Upgrader
{
private PostMigrationCollection _postMigrations;
/// <summary>
/// Initializes a new instance of the <see ref="UmbracoUpgrader" /> class.
/// </summary>
public UmbracoUpgrader()
: base(new UmbracoPlan())
{ }
/// <summary>
/// Executes.
/// </summary>
public void Execute(IScopeProvider scopeProvider, IMigrationBuilder migrationBuilder, IKeyValueService keyValueService, ILogger logger, PostMigrationCollection postMigrations)
{
_postMigrations = postMigrations;
Execute(scopeProvider, migrationBuilder, keyValueService, logger);
}
/// <inheritdoc />
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);
}
}
}

View File

@@ -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<RebuildPublishedSnapshot>();
}
}

View File

@@ -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<UrlSegmentProviderCollectionBuilder>()
.Append<DefaultUrlSegmentProvider>();
composition.WithCollectionBuilder<PostMigrationCollectionBuilder>()
.Add(() => composition.TypeLoader.GetTypes<IPostMigration>());
composition.RegisterUnique<IMigrationBuilder>(factory => new MigrationBuilder(factory));
// by default, register a noop factory
composition.RegisterUnique<IPublishedModelFactory, NoopPublishedModelFactory>();
// by default, register a noop rebuilder
composition.RegisterUnique<IPublishedSnapshotRebuilder, PublishedSnapshotRebuilder>();
}
}
}

View File

@@ -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

View File

@@ -351,6 +351,9 @@
<Compile Include="Migrations\IncompleteMigrationExpressionException.cs" />
<Compile Include="Migrations\MergeBuilder.cs" />
<Compile Include="Migrations\MigrationBase_Extra.cs" />
<Compile Include="Migrations\PostMigrations\IPublishedSnapshotRebuilder.cs" />
<Compile Include="Migrations\PostMigrations\PublishedSnapshotRebuilder.cs" />
<Compile Include="Migrations\PostMigrations\RebuildPublishedSnapshot.cs" />
<Compile Include="Migrations\Upgrade\V_7_10_0\RenamePreviewFolder.cs" />
<Compile Include="Migrations\Upgrade\V_7_12_0\AddRelationTypeForMediaFolderOnDelete.cs" />
<Compile Include="Migrations\Upgrade\V_7_12_0\IncreaseLanguageIsoCodeColumnLength.cs" />
@@ -666,15 +669,11 @@
<Compile Include="Media\IEmbedProvider.cs" />
<Compile Include="Media\OEmbedResult.cs" />
<Compile Include="Media\OEmbedStatus.cs" />
<Compile Include="Migrations\IPostMigration.cs" />
<Compile Include="Migrations\MigrationBuilder.cs" />
<Compile Include="Migrations\MigrationPlan.cs" />
<Compile Include="Migrations\NoopMigration.cs" />
<Compile Include="Migrations\PostMigrationCollection.cs" />
<Compile Include="Migrations\PostMigrationCollectionBuilder.cs" />
<Compile Include="Migrations\Upgrade\UmbracoPlan.cs" />
<Compile Include="Migrations\Upgrade\V_8_0_0\AddLockTable.cs" />
<Compile Include="Migrations\Upgrade\UmbracoUpgrader.cs" />
<Compile Include="Migrations\Upgrade\Upgrader.cs" />
<Compile Include="Migrations\Upgrade\V_8_0_0\DropMigrationsTable.cs" />
<Compile Include="Models\AuditItem.cs" />

View File

@@ -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;

View File

@@ -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<ILogger>();
var changed1 = new Args { CountExecuted = 0 };
var post1 = new TestPostMigration(changed1);
var posts = new PostMigrationCollection(new [] { post1 });
var builder = Mock.Of<IMigrationBuilder>();
Mock.Get(builder)
.Setup(x => x.Build(It.IsAny<Type>(), It.IsAny<IMigrationContext>()))
@@ -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<IPocoDataFactory>());
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<IKeyValueService>(), logger, posts);
var plan = new MigrationPlan("Test")
.From(string.Empty).To("done");
Assert.AreEqual(1, changed1.CountExecuted);
plan.AddPostMigration<TestPostMigration>();
TestPostMigration.MigrateCount = 0;
var upgrader = new Upgrader(plan);
upgrader.Execute(scopeProvider, builder, Mock.Of<IKeyValueService>(), logger);
Assert.AreEqual(1, TestPostMigration.MigrateCount);
}
[Test]
public void Executes_Only_For_Specified_Product_Name()
public void MigrationCanAddPostMigration()
{
var logger = Mock.Of<ILogger>();
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<IMigrationBuilder>();
Mock.Get(builder)
.Setup(x => x.Build(It.IsAny<Type>(), It.IsAny<IMigrationContext>()))
@@ -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<IPocoDataFactory>());
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<IKeyValueService>(), logger, posts);
var plan = new MigrationPlan("Test")
.From(string.Empty).To<TestMigration>("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<IKeyValueService>(), 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<IKeyValueService>(), 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<TestPostMigration>();
}
}
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++;
}
}
}

View File

@@ -311,6 +311,8 @@ namespace Umbraco.Tests.Models.Mapping
public void IMemberType_To_MemberTypeDisplay()
{
//Arrange
_dataTypeService.Setup(x => x.GetDataType(It.IsAny<int>()))
.Returns(new DataType(new VoidEditor(Mock.Of<ILogger>())));
// setup the mocks to return the data we want to test against...
@@ -369,6 +371,8 @@ namespace Umbraco.Tests.Models.Mapping
public void IMediaType_To_MediaTypeDisplay()
{
//Arrange
_dataTypeService.Setup(x => x.GetDataType(It.IsAny<int>()))
.Returns(new DataType(new VoidEditor(Mock.Of<ILogger>())));
// setup the mocks to return the data we want to test against...
@@ -422,6 +426,8 @@ namespace Umbraco.Tests.Models.Mapping
public void IContentType_To_ContentTypeDisplay()
{
//Arrange
_dataTypeService.Setup(x => x.GetDataType(It.IsAny<int>()))
.Returns(new DataType(new VoidEditor(Mock.Of<ILogger>())));
// setup the mocks to return the data we want to test against...
@@ -687,6 +693,8 @@ namespace Umbraco.Tests.Models.Mapping
public void IMediaTypeComposition_To_MediaTypeDisplay()
{
//Arrange
_dataTypeService.Setup(x => x.GetDataType(It.IsAny<int>()))
.Returns(new DataType(new VoidEditor(Mock.Of<ILogger>())));
// setup the mocks to return the data we want to test against...
@@ -778,6 +786,8 @@ namespace Umbraco.Tests.Models.Mapping
public void IContentTypeComposition_To_ContentTypeDisplay()
{
//Arrange
_dataTypeService.Setup(x => x.GetDataType(It.IsAny<int>()))
.Returns(new DataType(new VoidEditor(Mock.Of<ILogger>())));
// setup the mocks to return the data we want to test against...

View File

@@ -133,7 +133,9 @@ Use this directive make an element sticky and follow the page when scrolling.
clonedBar.addClass('-umb-sticky-bar');
clonedBar.css({
'position': 'fixed',
'z-index': 500,
// if you change this z-index value, make sure the sticky editor sub headers do not
// clash with umb-dropdown (e.g. the content actions dropdown in content list view)
'z-index': 99,
'visibility': 'hidden'
});

View File

@@ -51,11 +51,11 @@
<!-- Show in custom help dashboard -->
<div class="umb-help-section" data-element="help-custom-dashboard" ng-if="vm.customDashboard.length > 0">
<div ng-repeat="tab in vm.customDashboard">
<div ng-repeat="property in tab.properties">
<div ng-repeat="dashboard in vm.customDashboard">
<h5 ng-show="dashboard.label">{{dashboard.label}}</h5>
<div ng-repeat="property in dashboard.properties">
<div>
<h5 ng-if="property.caption">{{property.caption}}</h5>
<div ng-include="property.path"></div>
<div ng-include="property.view"></div>
</div>
</div>
</div>

View File

@@ -188,17 +188,17 @@
<Content Include="Config\serilog.user.config">
<SubType>Designer</SubType>
</Content>
<Content Include="Config\serilog.user.Release.config">
<None Include="Config\serilog.user.Release.config">
<DependentUpon>serilog.user.config</DependentUpon>
<SubType>Designer</SubType>
</Content>
</None>
<Content Include="Config\serilog.config">
<SubType>Designer</SubType>
</Content>
<Content Include="Config\serilog.Release.config">
<None Include="Config\serilog.Release.config">
<DependentUpon>serilog.config</DependentUpon>
<SubType>Designer</SubType>
</Content>
</None>
<Content Include="Config\logviewer.searches.config.js" />
<None Include="Config\umbracoSettings.Release.config">
<DependentUpon>umbracoSettings.config</DependentUpon>

View File

@@ -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

View File

@@ -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<DatabaseUpgradeStep>("Running 'Upgrade' service");
var result = _databaseBuilder.UpgradeSchemaAndData();
var plan = new UmbracoPlan();
plan.AddPostMigration<ClearCsrfCookies>(); // needed when running installer (back-office)
var result = _databaseBuilder.UpgradeSchemaAndData(plan);
if (result.Success == false)
{

View File

@@ -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();

View File

@@ -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
{
/// <summary>
/// After upgrade we clear out the csrf tokens
/// Clears Csrf tokens.
/// </summary>
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);

View File

@@ -0,0 +1,31 @@
using Umbraco.Core.Migrations.PostMigrations;
using Umbraco.Web.Cache;
using Umbraco.Web.PublishedCache;
namespace Umbraco.Web.Migrations.PostMigrations
{
/// <summary>
/// Implements <see cref="IPublishedSnapshotRebuilder"/> in Umbraco.Web (rebuilding).
/// </summary>
public class PublishedSnapshotRebuilder : IPublishedSnapshotRebuilder
{
private readonly IPublishedSnapshotService _publishedSnapshotService;
private readonly DistributedCache _distributedCache;
/// <summary>
/// Initializes a new instance of the <see cref="PublishedSnapshotRebuilder"/> class.
/// </summary>
public PublishedSnapshotRebuilder(IPublishedSnapshotService publishedSnapshotService, DistributedCache distributedCache)
{
_publishedSnapshotService = publishedSnapshotService;
_distributedCache = distributedCache;
}
/// <inheritdoc />
public void Rebuild()
{
_publishedSnapshotService.Rebuild();
_distributedCache.RefreshAllPublishedSnapshot();
}
}
}

View File

@@ -48,6 +48,21 @@ namespace Umbraco.Web.PublishedCache
#endregion
#region Rebuild
/// <summary>
/// Rebuilds internal caches (but does not reload).
/// </summary>
/// <remarks>
/// <para>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.</para>
/// <para>This does *not* reload the caches. Caches need to be reloaded, for instance via
/// <see cref="DistributedCache" /> RefreshAllPublishedSnapshot method.</para>
/// </remarks>
void Rebuild();
#endregion
#region Preview
/* Later on we can imagine that EnterPreview would handle a "level" that would be either

View File

@@ -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<string> errors)
{
// must have app_data and be able to write files into it
var ok = FilePermissionHelper.TryCreateDirectory(SystemDirectories.Data);
errors = ok ? Enumerable.Empty<string>() : new[] { "NuCache local DB files." };
var ok = FilePermissionHelper.TryCreateDirectory(GetLocalFilesPath());
errors = ok ? Enumerable.Empty<string>() : 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<PublishedSnapshotService>("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<int> contentTypeIds = null)
{
using (var scope = _scopeProvider.CreateScope(repositoryCacheMode: RepositoryCacheMode.Scoped))

View File

@@ -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()
{ }
}

View File

@@ -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<Soundcloud>()
.Append<Issuu>()
.Append<Hulu>();
// replace with web implementation
composition.RegisterUnique<IPublishedSnapshotRebuilder, Migrations.PostMigrations.PublishedSnapshotRebuilder>();
}
}
}

View File

@@ -196,6 +196,7 @@
<Compile Include="Media\TypeDetector\SvgDetector.cs" />
<Compile Include="Media\TypeDetector\TIFFDetector.cs" />
<Compile Include="Media\UploadAutoFillProperties.cs" />
<Compile Include="Migrations\PostMigrations\PublishedSnapshotRebuilder.cs" />
<Compile Include="Models\ContentEditing\LinkDisplay.cs" />
<Compile Include="Models\ContentEditing\MacroDisplay.cs" />
<Compile Include="Models\ContentEditing\MacroParameterDisplay.cs" />
@@ -885,7 +886,7 @@
<Compile Include="Security\BackOfficeCookieManager.cs" />
<Compile Include="Security\UmbracoBackOfficeCookieAuthOptions.cs" />
<Compile Include="Scheduling\TaskAndFactoryExtensions.cs" />
<Compile Include="Migrations\ClearCsrfCookiesAfterUpgrade.cs" />
<Compile Include="Migrations\PostMigrations\ClearCsrfCookies.cs" />
<Compile Include="Components\NotificationsComponent.cs" />
<Compile Include="TagQuery.cs" />
<Compile Include="Trees\CoreTreeAttribute.cs" />