diff --git a/build/NuSpecs/UmbracoCms.Core.nuspec b/build/NuSpecs/UmbracoCms.Core.nuspec
index f3f8f47b57..56462fcc40 100644
--- a/build/NuSpecs/UmbracoCms.Core.nuspec
+++ b/build/NuSpecs/UmbracoCms.Core.nuspec
@@ -52,7 +52,7 @@
-
+
diff --git a/build/NuSpecs/UmbracoCms.Web.nuspec b/build/NuSpecs/UmbracoCms.Web.nuspec
index 3c8fed78f5..614a816f3f 100644
--- a/build/NuSpecs/UmbracoCms.Web.nuspec
+++ b/build/NuSpecs/UmbracoCms.Web.nuspec
@@ -53,9 +53,9 @@
-
-
-
+
+
+
diff --git a/src/Umbraco.Core/Compose/AuditEventsComponent.cs b/src/Umbraco.Core/Compose/AuditEventsComponent.cs
index 15fdfeacff..453fd6314a 100644
--- a/src/Umbraco.Core/Compose/AuditEventsComponent.cs
+++ b/src/Umbraco.Core/Compose/AuditEventsComponent.cs
@@ -44,21 +44,22 @@ namespace Umbraco.Core.Compose
public void Terminate()
{ }
+ internal static IUser UnknownUser => new User { Id = Constants.Security.UnknownUserId, Name = Constants.Security.UnknownUserName, Email = "" };
+
private IUser CurrentPerformingUser
{
get
{
var identity = Thread.CurrentPrincipal?.GetUmbracoIdentity();
- return identity == null
- ? new User { Id = 0, Name = "SYSTEM", Email = "" }
- : _userService.GetUserById(Convert.ToInt32(identity.Id));
+ var user = identity == null ? null : _userService.GetUserById(Convert.ToInt32(identity.Id));
+ return user ?? UnknownUser;
}
}
private IUser GetPerformingUser(int userId)
{
var found = userId >= 0 ? _userService.GetUserById(userId) : null;
- return found ?? new User {Id = 0, Name = "SYSTEM", Email = ""};
+ return found ?? UnknownUser;
}
private string PerformingIp
diff --git a/src/Umbraco.Core/Constants-Security.cs b/src/Umbraco.Core/Constants-Security.cs
index 80f18eb2e0..27d6716000 100644
--- a/src/Umbraco.Core/Constants-Security.cs
+++ b/src/Umbraco.Core/Constants-Security.cs
@@ -15,13 +15,18 @@ namespace Umbraco.Core
public const int SuperUserId = -1;
///
- /// The id for the 'unknown' user
+ /// The id for the 'unknown' user.
///
///
/// This is a user row that exists in the DB only for referential integrity but the user is never returned from any of the services
///
public const int UnknownUserId = 0;
+ ///
+ /// The name of the 'unknown' user.
+ ///
+ public const string UnknownUserName = "SYTEM";
+
public const string AdminGroupAlias = "admin";
public const string SensitiveDataGroupAlias = "sensitiveData";
public const string TranslatorGroupAlias = "translator";
diff --git a/src/Umbraco.Core/Migrations/Expressions/Create/KeysAndIndexes/CreateKeysAndIndexesBuilder.cs b/src/Umbraco.Core/Migrations/Expressions/Create/KeysAndIndexes/CreateKeysAndIndexesBuilder.cs
index b11ef7e2c8..6bf450a9b8 100644
--- a/src/Umbraco.Core/Migrations/Expressions/Create/KeysAndIndexes/CreateKeysAndIndexesBuilder.cs
+++ b/src/Umbraco.Core/Migrations/Expressions/Create/KeysAndIndexes/CreateKeysAndIndexesBuilder.cs
@@ -25,11 +25,25 @@ namespace Umbraco.Core.Migrations.Expressions.Create.KeysAndIndexes
var syntax = _context.SqlContext.SqlSyntax;
var tableDefinition = DefinitionFactory.GetTableDefinition(TypeOfDto, syntax);
+ // note: of course we are creating the keys and indexes as per the DTO, so
+ // changing the DTO may break old migrations - or, better, these migrations
+ // should capture a copy of the DTO class that will not change
+
ExecuteSql(syntax.FormatPrimaryKey(tableDefinition));
foreach (var sql in syntax.Format(tableDefinition.Indexes))
ExecuteSql(sql);
foreach (var sql in syntax.Format(tableDefinition.ForeignKeys))
ExecuteSql(sql);
+
+ // note: we do *not* create the DF_ default constraints
+ /*
+ foreach (var column in tableDefinition.Columns)
+ {
+ var sql = syntax.FormatDefaultConstraint(column);
+ if (!sql.IsNullOrWhiteSpace())
+ ExecuteSql(sql);
+ }
+ */
}
private void ExecuteSql(string sql)
diff --git a/src/Umbraco.Core/Migrations/Expressions/Delete/DefaultConstraint/DeleteDefaultConstraintBuilder.cs b/src/Umbraco.Core/Migrations/Expressions/Delete/DefaultConstraint/DeleteDefaultConstraintBuilder.cs
index 373b375fa8..92bc11b04d 100644
--- a/src/Umbraco.Core/Migrations/Expressions/Delete/DefaultConstraint/DeleteDefaultConstraintBuilder.cs
+++ b/src/Umbraco.Core/Migrations/Expressions/Delete/DefaultConstraint/DeleteDefaultConstraintBuilder.cs
@@ -10,9 +10,13 @@ namespace Umbraco.Core.Migrations.Expressions.Delete.DefaultConstraint
IDeleteDefaultConstraintOnTableBuilder,
IDeleteDefaultConstraintOnColumnBuilder
{
- public DeleteDefaultConstraintBuilder(DeleteDefaultConstraintExpression expression)
+ private readonly IMigrationContext _context;
+
+ public DeleteDefaultConstraintBuilder(IMigrationContext context, DeleteDefaultConstraintExpression expression)
: base(expression)
- { }
+ {
+ _context = context;
+ }
///
public IDeleteDefaultConstraintOnColumnBuilder OnTable(string tableName)
@@ -25,6 +29,9 @@ namespace Umbraco.Core.Migrations.Expressions.Delete.DefaultConstraint
public IExecutableBuilder OnColumn(string columnName)
{
Expression.ColumnName = columnName;
+ Expression.HasDefaultConstraint = _context.SqlContext.SqlSyntax.TryGetDefaultConstraint(_context.Database, Expression.TableName, columnName, out var constraintName);
+ Expression.ConstraintName = constraintName ?? string.Empty;
+
return new ExecutableBuilder(Expression);
}
}
diff --git a/src/Umbraco.Core/Migrations/Expressions/Delete/DeleteBuilder.cs b/src/Umbraco.Core/Migrations/Expressions/Delete/DeleteBuilder.cs
index d081305cde..9a4f437f62 100644
--- a/src/Umbraco.Core/Migrations/Expressions/Delete/DeleteBuilder.cs
+++ b/src/Umbraco.Core/Migrations/Expressions/Delete/DeleteBuilder.cs
@@ -1,4 +1,4 @@
-using NPoco;
+using Umbraco.Core.Exceptions;
using Umbraco.Core.Migrations.Expressions.Common;
using Umbraco.Core.Migrations.Expressions.Delete.Column;
using Umbraco.Core.Migrations.Expressions.Delete.Constraint;
@@ -29,9 +29,19 @@ namespace Umbraco.Core.Migrations.Expressions.Delete
}
///
- public IExecutableBuilder KeysAndIndexes(string tableName = null)
+ public IExecutableBuilder KeysAndIndexes(bool local = true, bool foreign = true)
{
- return new DeleteKeysAndIndexesBuilder(_context) { TableName = tableName };
+ var syntax = _context.SqlContext.SqlSyntax;
+ var tableDefinition = DefinitionFactory.GetTableDefinition(typeof(TDto), syntax);
+ return KeysAndIndexes(tableDefinition.Name, local, foreign);
+ }
+
+ ///
+ public IExecutableBuilder KeysAndIndexes(string tableName, bool local = true, bool foreign = true)
+ {
+ if (tableName.IsNullOrWhiteSpace())
+ throw new ArgumentNullOrEmptyException(nameof(tableName));
+ return new DeleteKeysAndIndexesBuilder(_context) { TableName = tableName, DeleteLocal = local, DeleteForeign = foreign };
}
///
@@ -100,7 +110,7 @@ namespace Umbraco.Core.Migrations.Expressions.Delete
public IDeleteDefaultConstraintOnTableBuilder DefaultConstraint()
{
var expression = new DeleteDefaultConstraintExpression(_context);
- return new DeleteDefaultConstraintBuilder(expression);
+ return new DeleteDefaultConstraintBuilder(_context, expression);
}
}
}
diff --git a/src/Umbraco.Core/Migrations/Expressions/Delete/Expressions/DeleteDefaultConstraintExpression.cs b/src/Umbraco.Core/Migrations/Expressions/Delete/Expressions/DeleteDefaultConstraintExpression.cs
index 8b0b20c0e2..b73d3f0d13 100644
--- a/src/Umbraco.Core/Migrations/Expressions/Delete/Expressions/DeleteDefaultConstraintExpression.cs
+++ b/src/Umbraco.Core/Migrations/Expressions/Delete/Expressions/DeleteDefaultConstraintExpression.cs
@@ -10,12 +10,17 @@ namespace Umbraco.Core.Migrations.Expressions.Delete.Expressions
public virtual string TableName { get; set; }
public virtual string ColumnName { get; set; }
+ public virtual string ConstraintName { get; set; }
+ public virtual bool HasDefaultConstraint { get; set; }
protected override string GetSql()
{
- return string.Format(SqlSyntax.DeleteDefaultConstraint,
- SqlSyntax.GetQuotedTableName(TableName),
- SqlSyntax.GetQuotedColumnName(ColumnName));
+ return HasDefaultConstraint
+ ? string.Format(SqlSyntax.DeleteDefaultConstraint,
+ SqlSyntax.GetQuotedTableName(TableName),
+ SqlSyntax.GetQuotedColumnName(ColumnName),
+ SqlSyntax.GetQuotedName(ConstraintName))
+ : string.Empty;
}
}
}
diff --git a/src/Umbraco.Core/Migrations/Expressions/Delete/IDeleteBuilder.cs b/src/Umbraco.Core/Migrations/Expressions/Delete/IDeleteBuilder.cs
index 07faf5028e..84e44d0d93 100644
--- a/src/Umbraco.Core/Migrations/Expressions/Delete/IDeleteBuilder.cs
+++ b/src/Umbraco.Core/Migrations/Expressions/Delete/IDeleteBuilder.cs
@@ -19,9 +19,14 @@ namespace Umbraco.Core.Migrations.Expressions.Delete
IExecutableBuilder Table(string tableName);
///
- /// Specifies the table to delete keys and indexes for.
+ /// Builds a Delete Keys and Indexes expression, and executes.
///
- IExecutableBuilder KeysAndIndexes(string tableName = null);
+ IExecutableBuilder KeysAndIndexes(bool local = true, bool foreign = true);
+
+ ///
+ /// Builds a Delete Keys and Indexes expression, and executes.
+ ///
+ IExecutableBuilder KeysAndIndexes(string tableName, bool local = true, bool foreign = true);
///
/// Specifies the column to delete.
diff --git a/src/Umbraco.Core/Migrations/Expressions/Delete/KeysAndIndexes/DeleteKeysAndIndexesBuilder.cs b/src/Umbraco.Core/Migrations/Expressions/Delete/KeysAndIndexes/DeleteKeysAndIndexesBuilder.cs
index 1c595d9103..9b13457b76 100644
--- a/src/Umbraco.Core/Migrations/Expressions/Delete/KeysAndIndexes/DeleteKeysAndIndexesBuilder.cs
+++ b/src/Umbraco.Core/Migrations/Expressions/Delete/KeysAndIndexes/DeleteKeysAndIndexesBuilder.cs
@@ -18,34 +18,38 @@ namespace Umbraco.Core.Migrations.Expressions.Delete.KeysAndIndexes
public string TableName { get; set; }
+ public bool DeleteLocal { get; set; }
+
+ public bool DeleteForeign { get; set; }
+
///
public void Do()
{
- if (TableName == null)
- {
- // drop keys
- var keys = _context.SqlContext.SqlSyntax.GetConstraintsPerTable(_context.Database).DistinctBy(x => x.Item2).ToArray();
- foreach (var key in keys.Where(x => x.Item2.StartsWith("FK_")))
- Delete.ForeignKey(key.Item2).OnTable(key.Item1).Do();
- foreach (var key in keys.Where(x => x.Item2.StartsWith("PK_")))
- Delete.PrimaryKey(key.Item2).FromTable(key.Item1).Do();
+ _context.BuildingExpression = false;
- // drop indexes
- var indexes = _context.SqlContext.SqlSyntax.GetDefinedIndexesDefinitions(_context.Database).DistinctBy(x => x.IndexName).ToArray();
- foreach (var index in indexes)
- Delete.Index(index.IndexName).OnTable(index.TableName).Do();
+ // drop keys
+ if (DeleteLocal || DeleteForeign)
+ {
+ // table, constraint
+ var tableKeys = _context.SqlContext.SqlSyntax.GetConstraintsPerTable(_context.Database).DistinctBy(x => x.Item2).ToList();
+ if (DeleteForeign)
+ {
+ foreach (var key in tableKeys.Where(x => x.Item1 == TableName && x.Item2.StartsWith("FK_")))
+ Delete.ForeignKey(key.Item2).OnTable(key.Item1).Do();
+ }
+ if (DeleteLocal)
+ {
+ foreach (var key in tableKeys.Where(x => x.Item1 == TableName && x.Item2.StartsWith("PK_")))
+ Delete.PrimaryKey(key.Item2).FromTable(key.Item1).Do();
+
+ // note: we do *not* delete the DEFAULT constraints
+ }
}
- else
- {
- // drop keys
- var keys = _context.SqlContext.SqlSyntax.GetConstraintsPerTable(_context.Database).DistinctBy(x => x.Item2).ToArray();
- foreach (var key in keys.Where(x => x.Item1 == TableName && x.Item2.StartsWith("FK_")))
- Delete.ForeignKey(key.Item2).OnTable(key.Item1).Do();
- foreach (var key in keys.Where(x => x.Item1 == TableName && x.Item2.StartsWith("PK_")))
- Delete.PrimaryKey(key.Item2).FromTable(key.Item1).Do();
- // drop indexes
- var indexes = _context.SqlContext.SqlSyntax.GetDefinedIndexesDefinitions(_context.Database).DistinctBy(x => x.IndexName).ToArray();
+ // drop indexes
+ if (DeleteLocal)
+ {
+ var indexes = _context.SqlContext.SqlSyntax.GetDefinedIndexesDefinitions(_context.Database).DistinctBy(x => x.IndexName).ToList();
foreach (var index in indexes.Where(x => x.TableName == TableName))
Delete.Index(index.IndexName).OnTable(index.TableName).Do();
}
diff --git a/src/Umbraco.Core/Migrations/IMigrationContext.cs b/src/Umbraco.Core/Migrations/IMigrationContext.cs
index 2baadc79eb..c76de8dfb3 100644
--- a/src/Umbraco.Core/Migrations/IMigrationContext.cs
+++ b/src/Umbraco.Core/Migrations/IMigrationContext.cs
@@ -36,7 +36,7 @@ namespace Umbraco.Core.Migrations
bool BuildingExpression { get; set; }
///
- /// Adds a post-migrations.
+ /// Adds a post-migration.
///
void AddPostMigration()
where TMigration : IMigration;
diff --git a/src/Umbraco.Core/Migrations/Install/DatabaseBuilder.cs b/src/Umbraco.Core/Migrations/Install/DatabaseBuilder.cs
index 5c4defab0c..2295745637 100644
--- a/src/Umbraco.Core/Migrations/Install/DatabaseBuilder.cs
+++ b/src/Umbraco.Core/Migrations/Install/DatabaseBuilder.cs
@@ -539,7 +539,7 @@ namespace Umbraco.Core.Migrations.Install
{
Message =
"The database configuration failed with the following message: " + ex.Message +
- "\n Please check log file for additional information (can be found in '/App_Data/Logs/UmbracoTraceLog.txt')",
+ "\n Please check log file for additional information (can be found in '/App_Data/Logs/')",
Success = false,
Percentage = "90"
};
diff --git a/src/Umbraco.Core/Migrations/MigrationContext.cs b/src/Umbraco.Core/Migrations/MigrationContext.cs
index a8d052036c..0bb2bc11ae 100644
--- a/src/Umbraco.Core/Migrations/MigrationContext.cs
+++ b/src/Umbraco.Core/Migrations/MigrationContext.cs
@@ -41,6 +41,7 @@ namespace Umbraco.Core.Migrations
public void AddPostMigration()
where TMigration : IMigration
{
+ // just adding - will be de-duplicated when executing
PostMigrations.Add(typeof(TMigration));
}
}
diff --git a/src/Umbraco.Core/Migrations/MigrationExpressionBase.cs b/src/Umbraco.Core/Migrations/MigrationExpressionBase.cs
index 8b5d9cc78c..be06a32ec7 100644
--- a/src/Umbraco.Core/Migrations/MigrationExpressionBase.cs
+++ b/src/Umbraco.Core/Migrations/MigrationExpressionBase.cs
@@ -92,6 +92,7 @@ namespace Umbraco.Core.Migrations
if (_executed)
throw new InvalidOperationException("This expression has already been executed.");
_executed = true;
+ Context.BuildingExpression = false;
if (sql == null)
{
diff --git a/src/Umbraco.Core/Migrations/MigrationPlan.cs b/src/Umbraco.Core/Migrations/MigrationPlan.cs
index 4be4ae7d30..37d1a03a5a 100644
--- a/src/Umbraco.Core/Migrations/MigrationPlan.cs
+++ b/src/Umbraco.Core/Migrations/MigrationPlan.cs
@@ -240,7 +240,8 @@ namespace Umbraco.Core.Migrations
if (finalState == null)
finalState = kvp.Key;
else
- throw new Exception("Multiple final states have been detected.");
+ throw new InvalidOperationException($"Multiple final states have been detected in the plan (\"{finalState}\", \"{kvp.Key}\")."
+ + " Make sure the plan contains only one final state.");
}
// now check for loops
@@ -254,7 +255,8 @@ namespace Umbraco.Core.Migrations
while (nextTransition != null && !verified.Contains(nextTransition.SourceState))
{
if (visited.Contains(nextTransition.SourceState))
- throw new Exception("A loop has been detected.");
+ throw new InvalidOperationException($"A loop has been detected in the plan around state \"{nextTransition.SourceState}\"."
+ + " Make sure the plan does not contain circular transition paths.");
visited.Add(nextTransition.SourceState);
nextTransition = _transitions[nextTransition.TargetState];
}
@@ -264,6 +266,14 @@ namespace Umbraco.Core.Migrations
_finalState = finalState;
}
+ ///
+ /// Throws an exception when the initial state is unknown.
+ ///
+ protected virtual void ThrowOnUnknownInitialState(string state)
+ {
+ throw new InvalidOperationException($"The migration plan does not support migrating from state \"{state}\".");
+ }
+
///
/// Executes the plan.
///
@@ -287,13 +297,15 @@ namespace Umbraco.Core.Migrations
logger.Info("At {OrigState}", string.IsNullOrWhiteSpace(origState) ? "origin": origState);
if (!_transitions.TryGetValue(origState, out var transition))
- throw new Exception($"Unknown state \"{origState}\".");
+ ThrowOnUnknownInitialState(origState);
var context = new MigrationContext(scope.Database, logger);
context.PostMigrations.AddRange(_postMigrationTypes);
while (transition != null)
{
+ logger.Info("Execute {MigrationType}", transition.MigrationType.Name);
+
var migration = migrationBuilder.Build(transition.MigrationType, context);
migration.Migrate();
@@ -302,6 +314,8 @@ namespace Umbraco.Core.Migrations
logger.Info("At {OrigState}", origState);
+ // throw a raw exception here: this should never happen as the plan has
+ // been validated - this is just a paranoid safety test
if (!_transitions.TryGetValue(origState, out transition))
throw new Exception($"Unknown state \"{origState}\".");
}
@@ -322,7 +336,8 @@ namespace Umbraco.Core.Migrations
logger.Info("Done (pending scope completion).");
- // safety check
+ // safety check - again, this should never happen as the plan has been validated,
+ // and this is just a paranoid safety test
if (origState != _finalState)
throw new Exception($"Internal error, reached state {origState} which is not final state {_finalState}");
diff --git a/src/Umbraco.Core/Migrations/Upgrade/Common/CreateKeysAndIndexes.cs b/src/Umbraco.Core/Migrations/Upgrade/Common/CreateKeysAndIndexes.cs
new file mode 100644
index 0000000000..29006c8811
--- /dev/null
+++ b/src/Umbraco.Core/Migrations/Upgrade/Common/CreateKeysAndIndexes.cs
@@ -0,0 +1,21 @@
+using Umbraco.Core.Migrations.Install;
+
+namespace Umbraco.Core.Migrations.Upgrade.Common
+{
+ public class CreateKeysAndIndexes : MigrationBase
+ {
+ public CreateKeysAndIndexes(IMigrationContext context)
+ : base(context)
+ { }
+
+ public override void Migrate()
+ {
+ // remove those that may already have keys
+ Delete.KeysAndIndexes(Constants.DatabaseSchema.Tables.KeyValue).Do();
+
+ // re-create *all* keys and indexes
+ foreach (var x in DatabaseSchemaCreator.OrderedTables)
+ Create.KeysAndIndexes(x).Do();
+ }
+ }
+}
diff --git a/src/Umbraco.Core/Migrations/Upgrade/Common/DeleteKeysAndIndexes.cs b/src/Umbraco.Core/Migrations/Upgrade/Common/DeleteKeysAndIndexes.cs
new file mode 100644
index 0000000000..9e4af17c09
--- /dev/null
+++ b/src/Umbraco.Core/Migrations/Upgrade/Common/DeleteKeysAndIndexes.cs
@@ -0,0 +1,75 @@
+namespace Umbraco.Core.Migrations.Upgrade.Common
+{
+ public class DeleteKeysAndIndexes : MigrationBase
+ {
+ public DeleteKeysAndIndexes(IMigrationContext context)
+ : base(context)
+ { }
+
+ public override void Migrate()
+ {
+ // all v7.14 tables
+ var tables = new[]
+ {
+ "cmsContent",
+ "cmsContentType",
+ "cmsContentType2ContentType",
+ "cmsContentTypeAllowedContentType",
+ "cmsContentVersion",
+ "cmsContentXml",
+ "cmsDataType",
+ "cmsDataTypePreValues",
+ "cmsDictionary",
+ "cmsDocument",
+ "cmsDocumentType",
+ "cmsLanguageText",
+ "cmsMacro",
+ "cmsMacroProperty",
+ "cmsMedia",
+ "cmsMember",
+ "cmsMember2MemberGroup",
+ "cmsMemberType",
+ "cmsPreviewXml",
+ "cmsPropertyData",
+ "cmsPropertyType",
+ "cmsPropertyTypeGroup",
+ "cmsTagRelationship",
+ "cmsTags",
+ "cmsTask",
+ "cmsTaskType",
+ "cmsTemplate",
+ "umbracoAccess",
+ "umbracoAccessRule",
+ "umbracoAudit",
+ "umbracoCacheInstruction",
+ "umbracoConsent",
+ "umbracoDomains",
+ "umbracoExternalLogin",
+ "umbracoLanguage",
+ "umbracoLock",
+ "umbracoLog",
+ "umbracoMigration",
+ "umbracoNode",
+ "umbracoRedirectUrl",
+ "umbracoRelation",
+ "umbracoRelationType",
+ "umbracoServer",
+ "umbracoUser",
+ "umbracoUser2NodeNotify",
+ "umbracoUser2UserGroup",
+ "umbracoUserGroup",
+ "umbracoUserGroup2App",
+ "umbracoUserGroup2NodePermission",
+ "umbracoUserLogin",
+ "umbracoUserStartNode",
+ };
+
+ // delete *all* keys and indexes - because of FKs
+ // on known v7 tables only
+ foreach (var table in tables)
+ Delete.KeysAndIndexes(table, false, true).Do();
+ foreach (var table in tables)
+ Delete.KeysAndIndexes(table, true, false).Do();
+ }
+ }
+}
diff --git a/src/Umbraco.Core/Migrations/Upgrade/UmbracoPlan.cs b/src/Umbraco.Core/Migrations/Upgrade/UmbracoPlan.cs
index cf06a16d31..834eade986 100644
--- a/src/Umbraco.Core/Migrations/Upgrade/UmbracoPlan.cs
+++ b/src/Umbraco.Core/Migrations/Upgrade/UmbracoPlan.cs
@@ -2,8 +2,7 @@
using System.Configuration;
using Semver;
using Umbraco.Core.Configuration;
-using Umbraco.Core.Migrations.Upgrade.V_7_12_0;
-using Umbraco.Core.Migrations.Upgrade.V_7_14_0;
+using Umbraco.Core.Migrations.Upgrade.Common;
using Umbraco.Core.Migrations.Upgrade.V_8_0_0;
using Umbraco.Core.Migrations.Upgrade.V_8_0_1;
using Umbraco.Core.Migrations.Upgrade.V_8_1_0;
@@ -15,6 +14,9 @@ namespace Umbraco.Core.Migrations.Upgrade
///
public class UmbracoPlan : MigrationPlan
{
+ private const string InitPrefix = "{init-";
+ private const string InitSuffix = "}";
+
///
/// Initializes a new instance of the class.
///
@@ -24,6 +26,27 @@ namespace Umbraco.Core.Migrations.Upgrade
DefinePlan();
}
+ ///
+ /// Gets the initial state corresponding to a version.
+ ///
+ private static string GetInitState(SemVersion version)
+ => InitPrefix + version + InitSuffix;
+
+ ///
+ /// Tries to extract a version from an initial state.
+ ///
+ private static bool TryGetInitStateVersion(string state, out string version)
+ {
+ if (state.StartsWith(InitPrefix) && state.EndsWith(InitSuffix))
+ {
+ version = state.TrimStart(InitPrefix).TrimEnd(InitSuffix);
+ return true;
+ }
+
+ version = null;
+ return false;
+ }
+
///
///
/// The default initial state in plans is string.Empty.
@@ -41,23 +64,32 @@ namespace Umbraco.Core.Migrations.Upgrade
if (!SemVersion.TryParse(ConfigurationManager.AppSettings[Constants.AppSettings.ConfigurationStatus], out var currentVersion))
throw new InvalidOperationException($"Could not get current version from web.config {Constants.AppSettings.ConfigurationStatus} appSetting.");
- // we currently support upgrading from 7.10.0 and later
- if (currentVersion < new SemVersion(7, 10))
- throw new InvalidOperationException($"Version {currentVersion} cannot be migrated to {UmbracoVersion.SemanticVersion}.");
-
// cannot go back in time
if (currentVersion > UmbracoVersion.SemanticVersion)
throw new InvalidOperationException($"Version {currentVersion} cannot be downgraded to {UmbracoVersion.SemanticVersion}.");
- // upgrading from version 7 => initial state is eg "{init-7.10.0}"
- // anything else is not supported - ie if 8 and above, we should have an initial state already
- if (currentVersion.Major != 7)
- throw new InvalidOperationException($"Version {currentVersion} is not supported by the migration plan.");
+ // only from 7.14.0 and above
+ var minVersion = new SemVersion(7, 14);
+ if (currentVersion < minVersion)
+ throw new InvalidOperationException($"Version {currentVersion} cannot be migrated to {UmbracoVersion.SemanticVersion}."
+ + $" Please upgrade first to at least {minVersion}.");
- return "{init-" + currentVersion + "}";
+ // initial state is eg "{init-7.14.0}"
+ return GetInitState(currentVersion);
}
}
+ protected override void ThrowOnUnknownInitialState(string state)
+ {
+ if (TryGetInitStateVersion(state, out var initVersion))
+ {
+ throw new InvalidOperationException($"Version {UmbracoVersion.SemanticVersion} does not support migrating from {initVersion}."
+ + $" Please verify which versions support migrating from {initVersion}.");
+ }
+
+ base.ThrowOnUnknownInitialState(state);
+ }
+
// define the plan
protected void DefinePlan()
{
@@ -70,21 +102,23 @@ namespace Umbraco.Core.Migrations.Upgrade
//
// If the new migration causes a merge conflict, because someone else also added another
// new migration, you NEED to fix the conflict by providing one default path, and paths
- // out of the conflict states (see example below).
+ // out of the conflict states (see examples below).
//
// * Porting from version 7:
// Append the ported migration to the main chain, using a new guid (same as above).
- // Create a new special chain from the {init-...} state to the main chain (see example
- // below).
+ // Create a new special chain from the {init-...} state to the main chain.
- // plan starts at 7.10.0 (anything before 7.10.0 is not supported)
- // upgrades from 7 to 8, and then takes care of all eventual upgrades
+ // plan starts at 7.14.0 (anything before 7.14.0 is not supported)
//
- From("{init-7.10.0}");
+ From(GetInitState(new SemVersion(7, 14, 0)));
+
+ // begin migrating from v7 - remove all keys and indexes
+ To("{B36B9ABD-374E-465B-9C5F-26AB0D39326F}");
+
To("{7C447271-CA3F-4A6A-A913-5D77015655CB}");
To("{CBFF58A2-7B50-4F75-8E98-249920DB0F37}");
- To("{3D18920C-E84D-405C-A06A-B7CEE52FE5DD}");
+ To("{5CB66059-45F4-48BA-BCBD-C5035D79206B}");
To("{FB0A5429-587E-4BD0-8A67-20F0E7E62FF7}");
To("{F0C42457-6A3B-4912-A7EA-F27ED85A2092}");
To("{8640C9E4-A1C0-4C59-99BB-609B4E604981}");
@@ -95,91 +129,55 @@ namespace Umbraco.Core.Migrations.Upgrade
ToWithReplace("{941B2ABA-2D06-4E04-81F5-74224F1DB037}", "{76DF5CD7-A884-41A5-8DC6-7860D95B1DF5}"); // kill AddVariationTable1
To("{A7540C58-171D-462A-91C5-7A9AA5CB8BFD}");
- Merge().To("{3E44F712-E2E3-473A-AE49-5D7F8E67CE3F}") // shannon added that one
- .With().To("{65D6B71C-BDD5-4A2E-8D35-8896325E9151}") // stephan added that one
+ Merge()
+ .To("{3E44F712-E2E3-473A-AE49-5D7F8E67CE3F}")
+ .With()
+ .To("{65D6B71C-BDD5-4A2E-8D35-8896325E9151}")
.As("{4CACE351-C6B9-4F0C-A6BA-85A02BBD39E4}");
To("{1350617A-4930-4D61-852F-E3AA9E692173}");
- To("{39E5B1F7-A50B-437E-B768-1723AEC45B65}"); // from 7.12.0
-
- Merge()
- .To("{0541A62B-EF87-4CA2-8225-F0EB98ECCC9F}") // from 7.12.0
- .To("{EB34B5DC-BB87-4005-985E-D983EA496C38}") // from 7.12.0
- .To("{517CE9EA-36D7-472A-BF4B-A0D6FB1B8F89}") // from 7.12.0
- .To("{BBD99901-1545-40E4-8A5A-D7A675C7D2F2}") // from 7.12.0
- .With()
- .To("{CF51B39B-9B9A-4740-BB7C-EAF606A7BFBF}") // andy added that one
- .As("{8B14CEBD-EE47-4AAD-A841-93551D917F11}");
-
- ToWithReplace("{2C87AA47-D1BC-4ECB-8A73-2D8D1046C27F}", "{5F4597F4-A4E0-4AFE-90B5-6D2F896830EB}"); // merge
- ToWithReplace("{B19BF0F2-E1C6-4AEB-A146-BC559D97A2C6}", "{290C18EE-B3DE-4769-84F1-1F467F3F76DA}"); // merge
+ To("{CF51B39B-9B9A-4740-BB7C-EAF606A7BFBF}");
+ To("{5F4597F4-A4E0-4AFE-90B5-6D2F896830EB}");
+ To("{290C18EE-B3DE-4769-84F1-1F467F3F76DA}");
To("{6A2C7C1B-A9DB-4EA9-B6AB-78E7D5B722A7}");
- To("{77874C77-93E5-4488-A404-A630907CEEF0}");
To("{8804D8E8-FE62-4E3A-B8A2-C047C2118C38}");
To("{23275462-446E-44C7-8C2C-3B8C1127B07D}");
To("{6B251841-3069-4AD5-8AE9-861F9523E8DA}");
To("{EE429F1B-9B26-43CA-89F8-A86017C809A3}");
To("{08919C4B-B431-449C-90EC-2B8445B5C6B1}");
To("{7EB0254C-CB8B-4C75-B15B-D48C55B449EB}");
- To("{648A2D5F-7467-48F8-B309-E99CEEE00E2A}"); // fixed version
To("{C39BF2A7-1454-4047-BBFE-89E40F66ED63}");
To("{64EBCE53-E1F0-463A-B40B-E98EFCCA8AE2}");
To("{0009109C-A0B8-4F3F-8FEB-C137BBDDA268}");
- To("{8A027815-D5CD-4872-8B88-9A51AB5986A6}"); // from 7.14.0
To("{ED28B66A-E248-4D94-8CDB-9BDF574023F0}");
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()
- .To("{940FD19A-00A8-4D5C-B8FF-939143585726}")
+ .To("{940FD19A-00A8-4D5C-B8FF-939143585726}")
.As("{0576E786-5C30-4000-B969-302B61E90CA3}");
+ To("{48AD6CCD-C7A4-4305-A8AB-38728AD23FC5}");
+
+ // finish migrating from v7 - recreate all keys and indexes
+ To("{3F9764F5-73D0-4D45-8804-1240A66E43A2}");
+
To("{E0CBE54D-A84F-4A8F-9B13-900945FD7ED9}");
To("{78BAF571-90D0-4D28-8175-EF96316DA789}");
+ // release-8.0.0
+
+ // to 8.0.1...
To("{80C0A0CB-0DD5-4573-B000-C4B7C313C70D}");
+ // release-8.0.1
+
+ // to 8.1.0...
To("{B69B6E8C-A769-4044-A27E-4A4E18D1645A}");
+ To("{0372A42B-DECF-498D-B4D1-6379E907EB94}");
+ To("{5B1E0D93-F5A3-449B-84BA-65366B84E2D4}");
//FINAL
-
-
-
-
- // and then, need to support upgrading from more recent 7.x
- //
- From("{init-7.10.1}").To("{init-7.10.0}"); // same as 7.10.0
- From("{init-7.10.2}").To("{init-7.10.0}"); // same as 7.10.0
- From("{init-7.10.3}").To("{init-7.10.0}"); // same as 7.10.0
- From("{init-7.10.4}").To("{init-7.10.0}"); // same as 7.10.0
- From("{init-7.10.5}").To("{init-7.10.0}"); // same as 7.10.0
- From("{init-7.11.0}").To("{init-7.10.0}"); // same as 7.10.0
- From("{init-7.11.1}").To("{init-7.10.0}"); // same as 7.10.0
- From("{init-7.11.2}").To("{init-7.10.0}"); // same as 7.10.0
-
- // 7.12.0 has migrations, define a custom chain which copies the chain
- // going from {init-7.10.0} to former final (1350617A) , and then goes straight to
- // main chain, skipping the migrations
- //
- From("{init-7.12.0}");
- // clone start / clone stop / target
- ToWithClone("{init-7.10.0}", "{1350617A-4930-4D61-852F-E3AA9E692173}", "{BBD99901-1545-40E4-8A5A-D7A675C7D2F2}");
-
- From("{init-7.12.1}").To("{init-7.10.0}"); // same as 7.12.0
- From("{init-7.12.2}").To("{init-7.10.0}"); // same as 7.12.0
- From("{init-7.12.3}").To("{init-7.10.0}"); // same as 7.12.0
- From("{init-7.12.4}").To("{init-7.10.0}"); // same as 7.12.0
- From("{init-7.13.0}").To("{init-7.10.0}"); // same as 7.12.0
- From("{init-7.13.1}").To("{init-7.10.0}"); // same as 7.12.0
-
- // 7.14.0 has migrations, handle it...
- // clone going from 7.10 to 1350617A (the last one before we started to merge 7.12 migrations), then
- // clone going from CF51B39B (after 7.12 migrations) to 0009109C (the last one before we started to merge 7.12 migrations),
- // ending in 8A027815 (after 7.14 migrations)
- From("{init-7.14.0}")
- .ToWithClone("{init-7.10.0}", "{1350617A-4930-4D61-852F-E3AA9E692173}", "{9109B8AF-6B34-46EE-9484-7434196D0C79}")
- .ToWithClone("{CF51B39B-9B9A-4740-BB7C-EAF606A7BFBF}", "{0009109C-A0B8-4F3F-8FEB-C137BBDDA268}", "{8A027815-D5CD-4872-8B88-9A51AB5986A6}");
}
}
}
diff --git a/src/Umbraco.Core/Migrations/Upgrade/V_7_10_0/RenamePreviewFolder.cs b/src/Umbraco.Core/Migrations/Upgrade/V_7_10_0/RenamePreviewFolder.cs
deleted file mode 100644
index 48e6d0085d..0000000000
--- a/src/Umbraco.Core/Migrations/Upgrade/V_7_10_0/RenamePreviewFolder.cs
+++ /dev/null
@@ -1,36 +0,0 @@
-using System.IO;
-using Umbraco.Core.IO;
-using File = System.IO.File;
-
-namespace Umbraco.Core.Migrations.Upgrade.V_7_10_0
-{
- ///
- /// Renames the preview folder containing static HTML files to ensure it does not interfere with the MVC route
- /// that is now supposed to render these views dynamically. We don't want to delete as people may have made
- /// customizations to these files that would need to be migrated to the new .cshtml view files.
- ///
- public class RenamePreviewFolder : MigrationBase
- {
- public RenamePreviewFolder(IMigrationContext context)
- : base(context)
- { }
-
- public override void Migrate()
- {
- var previewFolderPath = IOHelper.MapPath(SystemDirectories.Umbraco + "/preview");
- if (Directory.Exists(previewFolderPath))
- {
- var newPath = previewFolderPath.Replace("preview", "preview.old");
- if (Directory.Exists(newPath) == false)
- {
- Directory.Move(previewFolderPath, newPath);
- var readmeText =
- $"Static HTML files used for preview and canvas editing functionality no longer live in this directory.\r\n" +
- $"Instead they have been recreated as MVC views and can now be found in '~/Umbraco/Views/Preview'.\r\n" +
- $"See issue: http://issues.umbraco.org/issue/U4-11090";
- File.WriteAllText(Path.Combine(newPath, "readme.txt"), readmeText);
- }
- }
- }
- }
-}
diff --git a/src/Umbraco.Core/Migrations/Upgrade/V_7_12_0/AddRelationTypeForMediaFolderOnDelete.cs b/src/Umbraco.Core/Migrations/Upgrade/V_7_12_0/AddRelationTypeForMediaFolderOnDelete.cs
deleted file mode 100644
index f34ed9fb68..0000000000
--- a/src/Umbraco.Core/Migrations/Upgrade/V_7_12_0/AddRelationTypeForMediaFolderOnDelete.cs
+++ /dev/null
@@ -1,33 +0,0 @@
-using Umbraco.Core.Persistence.Dtos;
-
-namespace Umbraco.Core.Migrations.Upgrade.V_7_12_0
-{
- public class AddRelationTypeForMediaFolderOnDelete : MigrationBase
- {
-
- public AddRelationTypeForMediaFolderOnDelete(IMigrationContext context) : base(context)
- {
- }
-
- public override void Migrate()
- {
- var relationTypeCount = Context.Database.ExecuteScalar("SELECT COUNT(*) FROM umbracoRelationType WHERE alias=@alias",
- new { alias = Constants.Conventions.RelationTypes.RelateParentMediaFolderOnDeleteAlias });
-
- if (relationTypeCount > 0)
- return;
-
- var uniqueId = (Constants.Conventions.RelationTypes.RelateParentMediaFolderOnDeleteAlias + "____" + Constants.Conventions.RelationTypes.RelateParentMediaFolderOnDeleteName).ToGuid();
- Insert.IntoTable("umbracoRelationType").Row(new
- {
- typeUniqueId = uniqueId,
- alias = Constants.Conventions.RelationTypes.RelateParentMediaFolderOnDeleteAlias,
- name = Constants.Conventions.RelationTypes.RelateParentMediaFolderOnDeleteName,
- childObjectType = Constants.ObjectTypes.MediaType,
- parentObjectType = Constants.ObjectTypes.MediaType,
- dual = false
- }).Do();
- }
-
- }
-}
diff --git a/src/Umbraco.Core/Migrations/Upgrade/V_7_12_0/IncreaseLanguageIsoCodeColumnLength.cs b/src/Umbraco.Core/Migrations/Upgrade/V_7_12_0/IncreaseLanguageIsoCodeColumnLength.cs
deleted file mode 100644
index fc7a21f4fa..0000000000
--- a/src/Umbraco.Core/Migrations/Upgrade/V_7_12_0/IncreaseLanguageIsoCodeColumnLength.cs
+++ /dev/null
@@ -1,46 +0,0 @@
-using System.Linq;
-using Umbraco.Core.Persistence.DatabaseModelDefinitions;
-using Umbraco.Core.Persistence.SqlSyntax;
-
-namespace Umbraco.Core.Migrations.Upgrade.V_7_12_0
-{
- public class IncreaseLanguageIsoCodeColumnLength : MigrationBase
- {
- public IncreaseLanguageIsoCodeColumnLength(IMigrationContext context)
- : base(context)
- { }
-
- public override void Migrate()
- {
- // Some people seem to have a constraint in their DB instead of an index, we'd need to drop that one
- // See: https://our.umbraco.com/forum/using-umbraco-and-getting-started/93282-upgrade-from-711-to-712-fails
- var constraints = SqlSyntax.GetConstraintsPerTable(Context.Database).Distinct().ToArray();
- if (constraints.Any(x => x.Item2.InvariantEquals("IX_umbracoLanguage_languageISOCode")))
- {
- Delete.UniqueConstraint("IX_umbracoLanguage_languageISOCode").FromTable("umbracoLanguage").Do();
- }
-
- //Now check for indexes of that name and drop that if it exists
- var dbIndexes = SqlSyntax.GetDefinedIndexesDefinitions(Context.Database);
- if (dbIndexes.Any(x => x.IndexName.InvariantEquals("IX_umbracoLanguage_languageISOCode")))
- {
- Delete.Index("IX_umbracoLanguage_languageISOCode").OnTable("umbracoLanguage").Do();
- }
-
- Alter.Table("umbracoLanguage")
- .AlterColumn("languageISOCode")
- .AsString(14)
- .Nullable()
- .Do();
-
- Create.Index("IX_umbracoLanguage_languageISOCode")
- .OnTable("umbracoLanguage")
- .OnColumn("languageISOCode")
- .Ascending()
- .WithOptions()
- .Unique()
- .Do();
- }
-
- }
-}
diff --git a/src/Umbraco.Core/Migrations/Upgrade/V_7_12_0/RenameTrueFalseField.cs b/src/Umbraco.Core/Migrations/Upgrade/V_7_12_0/RenameTrueFalseField.cs
deleted file mode 100644
index 4022739ece..0000000000
--- a/src/Umbraco.Core/Migrations/Upgrade/V_7_12_0/RenameTrueFalseField.cs
+++ /dev/null
@@ -1,19 +0,0 @@
-using Umbraco.Core.Logging;
-using Umbraco.Core.Persistence.Dtos;
-using Umbraco.Core.Persistence.SqlSyntax;
-
-namespace Umbraco.Core.Migrations.Upgrade.V_7_12_0
-{
- public class RenameTrueFalseField : MigrationBase
- {
- public RenameTrueFalseField(IMigrationContext context) : base(context)
- {
- }
-
- public override void Migrate()
- {
- //rename the existing true/false field
- Update.Table(NodeDto.TableName).Set(new { text = "Checkbox" }).Where(new { id = Constants.DataTypes.Boolean }).Do();
- }
- }
-}
diff --git a/src/Umbraco.Core/Migrations/Upgrade/V_7_12_0/SetDefaultTagsStorageType.cs b/src/Umbraco.Core/Migrations/Upgrade/V_7_12_0/SetDefaultTagsStorageType.cs
deleted file mode 100644
index c8d65961f4..0000000000
--- a/src/Umbraco.Core/Migrations/Upgrade/V_7_12_0/SetDefaultTagsStorageType.cs
+++ /dev/null
@@ -1,51 +0,0 @@
-using Newtonsoft.Json;
-using Newtonsoft.Json.Linq;
-using Umbraco.Core.Models;
-using Umbraco.Core.Persistence;
-using Umbraco.Core.Persistence.Dtos;
-using Umbraco.Core.PropertyEditors;
-
-namespace Umbraco.Core.Migrations.Upgrade.V_7_12_0
-{
- ///
- /// Set the default storageType for the tags datatype to "CSV" to ensure backwards compatibility since the default is going to be JSON in new versions.
- ///
- public class SetDefaultTagsStorageType : MigrationBase
- {
- public SetDefaultTagsStorageType(IMigrationContext context)
- : base(context)
- { }
-
- // dummy editor for deserialization
- private class TagConfigurationEditor : ConfigurationEditor
- { }
-
- public override void Migrate()
- {
- // get all Umbraco.Tags datatypes
- var dataTypeDtos = Database.Fetch(Context.SqlContext.Sql()
- .Select()
- .From()
- .Where(x => x.EditorAlias == Constants.PropertyEditors.Aliases.Tags));
-
- // get a dummy editor for deserialization
- var editor = new TagConfigurationEditor();
-
- foreach (var dataTypeDto in dataTypeDtos)
- {
- // need to check storageType on raw dictionary, as TagConfiguration would have a default value
- var dictionary = JsonConvert.DeserializeObject(dataTypeDto.Configuration);
-
- // if missing, use TagConfiguration to properly update the configuration
- // due to ... reasons ... the key can start with a lower or upper 'S'
- if (!dictionary.ContainsKey("storageType") && !dictionary.ContainsKey("StorageType"))
- {
- var configuration = (TagConfiguration)editor.FromDatabase(dataTypeDto.Configuration);
- configuration.StorageType = TagsStorageType.Csv;
- dataTypeDto.Configuration = ConfigurationEditor.ToDatabase(configuration);
- Database.Update(dataTypeDto);
- }
- }
- }
- }
-}
diff --git a/src/Umbraco.Core/Migrations/Upgrade/V_7_12_0/UpdateUmbracoConsent.cs b/src/Umbraco.Core/Migrations/Upgrade/V_7_12_0/UpdateUmbracoConsent.cs
deleted file mode 100644
index 7596e3d7dd..0000000000
--- a/src/Umbraco.Core/Migrations/Upgrade/V_7_12_0/UpdateUmbracoConsent.cs
+++ /dev/null
@@ -1,15 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace Umbraco.Core.Migrations.Upgrade.V_7_12_0
-{
public class UpdateUmbracoConsent : MigrationBase
{
- public UpdateUmbracoConsent(IMigrationContext context)
- : base(context)
- { }
-
- public override void Migrate()
{
Alter.Table(Constants.DatabaseSchema.Tables.Consent).AlterColumn("comment").AsString().Nullable().Do();
}
- }
-}
diff --git a/src/Umbraco.Core/Migrations/Upgrade/V_7_14_0/UpdateMemberGroupPickerData.cs b/src/Umbraco.Core/Migrations/Upgrade/V_7_14_0/UpdateMemberGroupPickerData.cs
deleted file mode 100644
index c70f42076f..0000000000
--- a/src/Umbraco.Core/Migrations/Upgrade/V_7_14_0/UpdateMemberGroupPickerData.cs
+++ /dev/null
@@ -1,29 +0,0 @@
-namespace Umbraco.Core.Migrations.Upgrade.V_7_14_0
-{
- ///
- /// Migrates member group picker properties from NVarchar to NText. See https://github.com/umbraco/Umbraco-CMS/issues/3268.
- ///
- public class UpdateMemberGroupPickerData : MigrationBase
- {
- ///
- /// Migrates member group picker properties from NVarchar to NText. See https://github.com/umbraco/Umbraco-CMS/issues/3268.
- ///
- public UpdateMemberGroupPickerData(IMigrationContext context)
- : base(context)
- { }
-
- public override void Migrate()
- {
- Database.Execute($@"UPDATE umbracoPropertyData SET textValue = varcharValue, varcharValue = NULL
- WHERE textValue IS NULL AND id IN (
- SELECT id FROM umbracoPropertyData WHERE propertyTypeId in (
- SELECT id from cmsPropertyType where dataTypeId IN (
- SELECT nodeId FROM umbracoDataType WHERE propertyEditorAlias = '{Constants.PropertyEditors.Aliases.MemberGroupPicker}'
- )
- )
- )");
-
- Database.Execute($"UPDATE umbracoDataType SET dbType = 'Ntext' WHERE propertyEditorAlias = '{Constants.PropertyEditors.Aliases.MemberGroupPicker}'");
- }
- }
-}
diff --git a/src/Umbraco.Core/Migrations/Upgrade/V_7_5_0/AddRedirectUrlTable.cs b/src/Umbraco.Core/Migrations/Upgrade/V_7_5_0/AddRedirectUrlTable.cs
deleted file mode 100644
index 7040874a74..0000000000
--- a/src/Umbraco.Core/Migrations/Upgrade/V_7_5_0/AddRedirectUrlTable.cs
+++ /dev/null
@@ -1,50 +0,0 @@
-using System.Linq;
-
-namespace Umbraco.Core.Migrations.Upgrade.V_7_5_0
-{
- public class AddRedirectUrlTable : MigrationBase
- {
- public AddRedirectUrlTable(IMigrationContext context)
- : base(context)
- { }
-
- public override void Migrate()
- {
- var database = Database;
- var umbracoRedirectUrlTableName = "umbracoRedirectUrl";
-
- var tables = SqlSyntax.GetTablesInSchema(database).ToArray();
-
- if (tables.InvariantContains(umbracoRedirectUrlTableName))
- {
- var columns = SqlSyntax.GetColumnsInSchema(database).ToArray();
- if (columns.Any(x => x.TableName.InvariantEquals(umbracoRedirectUrlTableName) && x.ColumnName.InvariantEquals("id") && x.DataType == "uniqueidentifier"))
- return;
- Delete.Table(umbracoRedirectUrlTableName).Do();
- }
-
- Create.Table(umbracoRedirectUrlTableName)
- .WithColumn("id").AsGuid().NotNullable().PrimaryKey("PK_" + umbracoRedirectUrlTableName)
- .WithColumn("createDateUtc").AsDateTime().NotNullable()
- .WithColumn("url").AsString(2048).NotNullable()
- .WithColumn("contentKey").AsGuid().NotNullable()
- .WithColumn("urlHash").AsString(40).NotNullable()
- .Do();
-
- Create.Index("IX_" + umbracoRedirectUrlTableName).OnTable(umbracoRedirectUrlTableName)
- .OnColumn("urlHash")
- .Ascending()
- .OnColumn("contentKey")
- .Ascending()
- .OnColumn("createDateUtc")
- .Descending()
- .WithOptions().NonClustered()
- .Do();
-
- Create.ForeignKey("FK_" + umbracoRedirectUrlTableName)
- .FromTable(umbracoRedirectUrlTableName).ForeignColumn("contentKey")
- .ToTable("umbracoNode").PrimaryColumn("uniqueID")
- .Do();
- }
- }
-}
diff --git a/src/Umbraco.Core/Migrations/Upgrade/V_7_5_0/RemoveStylesheetDataAndTablesAgain.cs b/src/Umbraco.Core/Migrations/Upgrade/V_7_5_0/RemoveStylesheetDataAndTablesAgain.cs
deleted file mode 100644
index d27ed11a21..0000000000
--- a/src/Umbraco.Core/Migrations/Upgrade/V_7_5_0/RemoveStylesheetDataAndTablesAgain.cs
+++ /dev/null
@@ -1,40 +0,0 @@
-using System;
-using System.Linq;
-
-namespace Umbraco.Core.Migrations.Upgrade.V_7_5_0
-{
- ///
- /// This is here to re-remove these tables, we dropped them in 7.3 but new installs created them again so we're going to re-drop them
- ///
- public class RemoveStylesheetDataAndTablesAgain : MigrationBase
- {
- public RemoveStylesheetDataAndTablesAgain(IMigrationContext context)
- : base(context)
- {
- }
-
- public override void Migrate()
- {
- // these have been obsoleted, need to copy the values here
- var stylesheetPropertyObjectType = new Guid("5555da4f-a123-42b2-4488-dcdfb25e4111");
- var stylesheetObjectType = new Guid("9F68DA4F-A3A8-44C2-8226-DCBD125E4840");
-
- //Clear all stylesheet data if the tables exist
- var tables = SqlSyntax.GetTablesInSchema(Context.Database).ToArray();
- if (tables.InvariantContains("cmsStylesheetProperty"))
- {
- Delete.FromTable("cmsStylesheetProperty").AllRows().Do();
- Delete.FromTable("umbracoNode").Row(new { nodeObjectType = stylesheetPropertyObjectType }).Do();
-
- Delete.Table("cmsStylesheetProperty").Do();
- }
- if (tables.InvariantContains("cmsStylesheet"))
- {
- Delete.FromTable("cmsStylesheet").AllRows().Do();
- Delete.FromTable("umbracoNode").Row(new { nodeObjectType = stylesheetObjectType }).Do();
-
- Delete.Table("cmsStylesheet").Do();
- }
- }
- }
-}
diff --git a/src/Umbraco.Core/Migrations/Upgrade/V_7_5_0/UpdateUniqueIndexOnPropertyData.cs b/src/Umbraco.Core/Migrations/Upgrade/V_7_5_0/UpdateUniqueIndexOnPropertyData.cs
deleted file mode 100644
index 8c688cfd28..0000000000
--- a/src/Umbraco.Core/Migrations/Upgrade/V_7_5_0/UpdateUniqueIndexOnPropertyData.cs
+++ /dev/null
@@ -1,44 +0,0 @@
-using System.Linq;
-using Umbraco.Core.Persistence;
-using Umbraco.Core.Persistence.SqlSyntax;
-
-namespace Umbraco.Core.Migrations.Upgrade.V_7_5_0
-{
- ///
- /// See: http://issues.umbraco.org/issue/U4-8522
- ///
- public class UpdateUniqueIndexOnPropertyData : MigrationBase
- {
- public UpdateUniqueIndexOnPropertyData(IMigrationContext context)
- : base(context)
- {
- }
-
- public override void Migrate()
- {
- //Clear all stylesheet data if the tables exist
- //tuple = tablename, indexname, columnname, unique
- var indexes = SqlSyntax.GetDefinedIndexes(Context.Database).ToArray();
- var found = indexes.FirstOrDefault(
- x => x.Item1.InvariantEquals("cmsPropertyData")
- && x.Item2.InvariantEquals("IX_cmsPropertyData_1")
- //we're searching for the old index which is not unique
- && x.Item4 == false);
-
- if (found != null)
- {
- Database.Execute("DELETE FROM cmsPropertyData WHERE id NOT IN (SELECT MIN(id) FROM cmsPropertyData GROUP BY nodeId, versionId, propertytypeid HAVING MIN(id) IS NOT NULL)");
-
- //we need to re create this index
- Delete.Index("IX_cmsPropertyData_1").OnTable("cmsPropertyData").Do();
- Create.Index("IX_cmsPropertyData_1").OnTable("cmsPropertyData")
- .OnColumn("nodeId").Ascending()
- .OnColumn("versionId").Ascending()
- .OnColumn("propertytypeid").Ascending()
- .WithOptions().NonClustered()
- .WithOptions().Unique()
- .Do();
- }
- }
- }
-}
diff --git a/src/Umbraco.Core/Migrations/Upgrade/V_7_5_5/UpdateAllowedMediaTypesAtRoot.cs b/src/Umbraco.Core/Migrations/Upgrade/V_7_5_5/UpdateAllowedMediaTypesAtRoot.cs
deleted file mode 100644
index 362b8e251c..0000000000
--- a/src/Umbraco.Core/Migrations/Upgrade/V_7_5_5/UpdateAllowedMediaTypesAtRoot.cs
+++ /dev/null
@@ -1,17 +0,0 @@
-namespace Umbraco.Core.Migrations.Upgrade.V_7_5_5
-{
- ///
- /// See: http://issues.umbraco.org/issue/U4-4196
- ///
- public class UpdateAllowedMediaTypesAtRoot : MigrationBase
- {
- public UpdateAllowedMediaTypesAtRoot(IMigrationContext context)
- : base(context)
- { }
-
- public override void Migrate()
- {
- Database.Execute("UPDATE cmsContentType SET allowAtRoot = 1 WHERE nodeId = 1032 OR nodeId = 1033");
- }
- }
-}
diff --git a/src/Umbraco.Core/Migrations/Upgrade/V_7_6_0/AddIndexToCmsMemberLoginName.cs b/src/Umbraco.Core/Migrations/Upgrade/V_7_6_0/AddIndexToCmsMemberLoginName.cs
deleted file mode 100644
index a223d76a07..0000000000
--- a/src/Umbraco.Core/Migrations/Upgrade/V_7_6_0/AddIndexToCmsMemberLoginName.cs
+++ /dev/null
@@ -1,41 +0,0 @@
-using System.Linq;
-using Umbraco.Core.Persistence.SqlSyntax;
-
-namespace Umbraco.Core.Migrations.Upgrade.V_7_6_0
-{
- public class AddIndexToCmsMemberLoginName : MigrationBase
- {
- public AddIndexToCmsMemberLoginName(IMigrationContext context)
- : base(context)
- { }
-
- public override void Migrate()
- {
- var database = Database;
-
- //Now we need to check if we can actually d6 this because we won't be able to if there's data in there that is too long
- //http://issues.umbraco.org/issue/U4-9758
-
- var colLen = database.ExecuteScalar("select max(datalength(LoginName)) from cmsMember");
-
- if (colLen < 900 == false && colLen != null)
- {
- return;
- }
-
- var dbIndexes = SqlSyntax.GetDefinedIndexesDefinitions(Context.Database);
-
- //make sure it doesn't already exist
- if (dbIndexes.Any(x => x.IndexName.InvariantEquals("IX_cmsMember_LoginName")) == false)
- {
- //we can apply the index
- Create.Index("IX_cmsMember_LoginName").OnTable("cmsMember")
- .OnColumn("LoginName")
- .Ascending()
- .WithOptions()
- .NonClustered()
- .Do();
- }
- }
- }
-}
diff --git a/src/Umbraco.Core/Migrations/Upgrade/V_7_6_0/AddIndexToUmbracoNodePath.cs b/src/Umbraco.Core/Migrations/Upgrade/V_7_6_0/AddIndexToUmbracoNodePath.cs
deleted file mode 100644
index 191f410b47..0000000000
--- a/src/Umbraco.Core/Migrations/Upgrade/V_7_6_0/AddIndexToUmbracoNodePath.cs
+++ /dev/null
@@ -1,28 +0,0 @@
-using System.Linq;
-using Umbraco.Core.Persistence.SqlSyntax;
-
-namespace Umbraco.Core.Migrations.Upgrade.V_7_6_0
-{
- public class AddIndexToUmbracoNodePath : MigrationBase
- {
- public AddIndexToUmbracoNodePath(IMigrationContext context)
- : base(context)
- { }
-
- public override void Migrate()
- {
- var dbIndexes = SqlSyntax.GetDefinedIndexesDefinitions(Context.Database);
-
- //make sure it doesn't already exist
- if (dbIndexes.Any(x => x.IndexName.InvariantEquals("IX_umbracoNodePath")) == false)
- {
- Create.Index("IX_umbracoNodePath").OnTable("umbracoNode")
- .OnColumn("path")
- .Ascending()
- .WithOptions()
- .NonClustered()
- .Do();
- }
- }
- }
-}
diff --git a/src/Umbraco.Core/Migrations/Upgrade/V_7_6_0/AddIndexToUser2NodePermission.cs b/src/Umbraco.Core/Migrations/Upgrade/V_7_6_0/AddIndexToUser2NodePermission.cs
deleted file mode 100644
index 87b392b09c..0000000000
--- a/src/Umbraco.Core/Migrations/Upgrade/V_7_6_0/AddIndexToUser2NodePermission.cs
+++ /dev/null
@@ -1,28 +0,0 @@
-using System.Linq;
-using Umbraco.Core.Persistence.SqlSyntax;
-
-namespace Umbraco.Core.Migrations.Upgrade.V_7_6_0
-{
- public class AddIndexToUser2NodePermission : MigrationBase
- {
- public AddIndexToUser2NodePermission(IMigrationContext context)
- : base(context)
- { }
-
- public override void Migrate()
- {
- var dbIndexes = SqlSyntax.GetDefinedIndexesDefinitions(Context.Database);
-
- //make sure it doesn't already exist
- if (dbIndexes.Any(x => x.IndexName.InvariantEquals("IX_umbracoUser2NodePermission_nodeId")) == false)
- {
- Create.Index("IX_umbracoUser2NodePermission_nodeId").OnTable("umbracoUser2NodePermission")
- .OnColumn("nodeId")
- .Ascending()
- .WithOptions()
- .NonClustered()
- .Do();
- }
- }
- }
-}
diff --git a/src/Umbraco.Core/Migrations/Upgrade/V_7_6_0/AddIndexesToUmbracoRelationTables.cs b/src/Umbraco.Core/Migrations/Upgrade/V_7_6_0/AddIndexesToUmbracoRelationTables.cs
deleted file mode 100644
index 9042ae105e..0000000000
--- a/src/Umbraco.Core/Migrations/Upgrade/V_7_6_0/AddIndexesToUmbracoRelationTables.cs
+++ /dev/null
@@ -1,85 +0,0 @@
-using System;
-using System.Linq;
-using Umbraco.Core.Persistence.SqlSyntax;
-
-namespace Umbraco.Core.Migrations.Upgrade.V_7_6_0
-{
- public class AddIndexesToUmbracoRelationTables : MigrationBase
- {
- public AddIndexesToUmbracoRelationTables(IMigrationContext context)
- : base(context)
- { }
-
- public override void Migrate()
- {
- var dbIndexes = SqlSyntax.GetDefinedIndexesDefinitions(Context.Database).ToArray();
-
- //make sure it doesn't already exist
- if (dbIndexes.Any(x => x.IndexName.InvariantEquals("IX_umbracoRelation_parentChildType")) == false)
- {
- //This will remove any corrupt/duplicate data in the relation table before the index is applied
- //Ensure this executes in a deferred block which will be done inside of the migration transaction
- var database = Database;
-
- //We need to check if this index has corrupted data and then clear that data
- var duplicates = database.Fetch("SELECT parentId,childId,relType FROM umbracoRelation GROUP BY parentId,childId,relType HAVING COUNT(*) > 1");
- if (duplicates.Count > 0)
- {
- //need to fix this there cannot be duplicates so we'll take the latest entries, it's really not going to matter though
- foreach (var duplicate in duplicates)
- {
- var ids = database.Fetch("SELECT id FROM umbracoRelation WHERE parentId=@parentId AND childId=@childId AND relType=@relType ORDER BY datetime DESC",
- new { parentId = duplicate.parentId, childId = duplicate.childId, relType = duplicate.relType });
-
- if (ids.Count == 1)
- {
- //this is just a safety check, this should absolutely never happen
- throw new InvalidOperationException("Duplicates were detected but could not be discovered");
- }
-
- //delete the others
- ids = ids.Skip(0).ToList();
-
- //iterate in groups of 2000 to avoid the max sql parameter limit
- foreach (var idGroup in ids.InGroupsOf(2000))
- {
- database.Execute("DELETE FROM umbracoRelation WHERE id IN (@ids)", new { ids = idGroup });
- }
- }
- }
-
- //unique index to prevent duplicates - and for better perf
- Create.Index("IX_umbracoRelation_parentChildType").OnTable("umbracoRelation")
- .OnColumn("parentId").Ascending()
- .OnColumn("childId").Ascending()
- .OnColumn("relType").Ascending()
- .WithOptions()
- .Unique()
- .Do();
- }
-
- //need indexes on alias and name for relation type since these are queried against
-
- //make sure it doesn't already exist
- if (dbIndexes.Any(x => x.IndexName.InvariantEquals("IX_umbracoRelationType_alias")) == false)
- {
- Create.Index("IX_umbracoRelationType_alias").OnTable("umbracoRelationType")
- .OnColumn("alias")
- .Ascending()
- .WithOptions()
- .NonClustered()
- .Do();
- }
- if (dbIndexes.Any(x => x.IndexName.InvariantEquals("IX_umbracoRelationType_name")) == false)
- {
- Create.Index("IX_umbracoRelationType_name").OnTable("umbracoRelationType")
- .OnColumn("name")
- .Ascending()
- .WithOptions()
- .NonClustered()
- .Do();
- }
-
- }
- }
-}
diff --git a/src/Umbraco.Core/Migrations/Upgrade/V_7_6_0/AddLockObjects.cs b/src/Umbraco.Core/Migrations/Upgrade/V_7_6_0/AddLockObjects.cs
deleted file mode 100644
index 2cc62cd2f9..0000000000
--- a/src/Umbraco.Core/Migrations/Upgrade/V_7_6_0/AddLockObjects.cs
+++ /dev/null
@@ -1,27 +0,0 @@
-using Umbraco.Core.Persistence.Dtos;
-
-namespace Umbraco.Core.Migrations.Upgrade.V_7_6_0
-{
- public class AddLockObjects : MigrationBase
- {
- public AddLockObjects(IMigrationContext context)
- : base(context)
- { }
-
- public override void Migrate()
- {
- EnsureLockObject(Constants.Locks.Servers, "Servers");
- }
-
- private void EnsureLockObject(int id, string name)
- {
- var db = Database;
- var exists = db.Exists(id);
- if (exists) return;
- // be safe: delete old umbracoNode lock objects if any
- db.Execute("DELETE FROM umbracoNode WHERE id=@id;", new { id });
- // then create umbracoLock object
- db.Execute("INSERT umbracoLock (id, name, value) VALUES (@id, @name, 1);", new { id, name });
- }
- }
-}
diff --git a/src/Umbraco.Core/Migrations/Upgrade/V_7_6_0/AddLockTable.cs b/src/Umbraco.Core/Migrations/Upgrade/V_7_6_0/AddLockTable.cs
deleted file mode 100644
index 369bda0758..0000000000
--- a/src/Umbraco.Core/Migrations/Upgrade/V_7_6_0/AddLockTable.cs
+++ /dev/null
@@ -1,24 +0,0 @@
-using System.Linq;
-
-namespace Umbraco.Core.Migrations.Upgrade.V_7_6_0
-{
- public class AddLockTable : MigrationBase
- {
- public AddLockTable(IMigrationContext context)
- : base(context)
- { }
-
- public override void Migrate()
- {
- var tables = SqlSyntax.GetTablesInSchema(Context.Database).ToArray();
- if (tables.InvariantContains("umbracoLock") == false)
- {
- Create.Table("umbracoLock")
- .WithColumn("id").AsInt32().PrimaryKey("PK_umbracoLock")
- .WithColumn("value").AsInt32().NotNullable()
- .WithColumn("name").AsString(64).NotNullable()
- .Do();
- }
- }
- }
-}
diff --git a/src/Umbraco.Core/Migrations/Upgrade/V_7_6_0/AddMacroUniqueIdColumn.cs b/src/Umbraco.Core/Migrations/Upgrade/V_7_6_0/AddMacroUniqueIdColumn.cs
deleted file mode 100644
index 82888ab970..0000000000
--- a/src/Umbraco.Core/Migrations/Upgrade/V_7_6_0/AddMacroUniqueIdColumn.cs
+++ /dev/null
@@ -1,68 +0,0 @@
-using System;
-using System.Linq;
-
-namespace Umbraco.Core.Migrations.Upgrade.V_7_6_0
-{
- public class AddMacroUniqueIdColumn : MigrationBase
- {
- public AddMacroUniqueIdColumn(IMigrationContext context)
- : base(context)
- { }
-
- public override void Migrate()
- {
- var columns = SqlSyntax.GetColumnsInSchema(Context.Database).ToArray();
-
- if (columns.Any(x => x.TableName.InvariantEquals("cmsMacro") && x.ColumnName.InvariantEquals("uniqueId")) == false)
- {
- Create.Column("uniqueId").OnTable("cmsMacro").AsGuid().Nullable().Do();
- UpdateMacroGuids();
- Alter.Table("cmsMacro").AlterColumn("uniqueId").AsGuid().NotNullable().Do();
- Create.Index("IX_cmsMacro_UniqueId").OnTable("cmsMacro").OnColumn("uniqueId")
- .Ascending()
- .WithOptions().NonClustered()
- .WithOptions().Unique()
- .Do();
-
- }
-
- if (columns.Any(x => x.TableName.InvariantEquals("cmsMacroProperty") && x.ColumnName.InvariantEquals("uniquePropertyId")) == false)
- {
- Create.Column("uniquePropertyId").OnTable("cmsMacroProperty").AsGuid().Nullable().Do();
- UpdateMacroPropertyGuids();
- Alter.Table("cmsMacroProperty").AlterColumn("uniquePropertyId").AsGuid().NotNullable().Do();
- Create.Index("IX_cmsMacroProperty_UniquePropertyId").OnTable("cmsMacroProperty").OnColumn("uniquePropertyId")
- .Ascending()
- .WithOptions().NonClustered()
- .WithOptions().Unique()
- .Do();
- }
- }
-
- private void UpdateMacroGuids()
- {
- var database = Database;
-
- var updates = database.Query("SELECT id, macroAlias FROM cmsMacro")
- .Select(macro => Tuple.Create((int) macro.id, ("macro____" + (string) macro.macroAlias).ToGuid()))
- .ToList();
-
- foreach (var update in updates)
- database.Execute("UPDATE cmsMacro set uniqueId=@guid WHERE id=@id", new { guid = update.Item2, id = update.Item1 });
- }
-
- private void UpdateMacroPropertyGuids()
- {
- var database = Database;
-
- var updates = database.Query(@"SELECT cmsMacroProperty.id id, macroPropertyAlias propertyAlias, cmsMacro.macroAlias macroAlias
-FROM cmsMacroProperty
-JOIN cmsMacro ON cmsMacroProperty.macro=cmsMacro.id")
- .Select(prop => Tuple.Create((int) prop.id, ("macro____" + (string) prop.macroAlias + "____" + (string) prop.propertyAlias).ToGuid()))
- .ToList();
-
- foreach (var update in updates)
- database.Execute("UPDATE cmsMacroProperty set uniquePropertyId=@guid WHERE id=@id", new { guid = update.Item2, id = update.Item1 });
- }
- }
-}
diff --git a/src/Umbraco.Core/Migrations/Upgrade/V_7_6_0/AddRelationTypeUniqueIdColumn.cs b/src/Umbraco.Core/Migrations/Upgrade/V_7_6_0/AddRelationTypeUniqueIdColumn.cs
deleted file mode 100644
index e166a4582d..0000000000
--- a/src/Umbraco.Core/Migrations/Upgrade/V_7_6_0/AddRelationTypeUniqueIdColumn.cs
+++ /dev/null
@@ -1,40 +0,0 @@
-using System;
-using System.Linq;
-
-namespace Umbraco.Core.Migrations.Upgrade.V_7_6_0
-{
- public class AddRelationTypeUniqueIdColumn : MigrationBase
- {
- public AddRelationTypeUniqueIdColumn(IMigrationContext context)
- : base(context)
- { }
-
- public override void Migrate()
- {
- var columns = SqlSyntax.GetColumnsInSchema(Context.Database).ToArray();
-
- if (columns.Any(x => x.TableName.InvariantEquals("umbracoRelationType") && x.ColumnName.InvariantEquals("typeUniqueId")) == false)
- {
- Create.Column("typeUniqueId").OnTable("umbracoRelationType").AsGuid().Nullable().Do();
- UpdateRelationTypeGuids();
- Alter.Table("umbracoRelationType").AlterColumn("typeUniqueId").AsGuid().NotNullable().Do();
- Create.Index("IX_umbracoRelationType_UniqueId").OnTable("umbracoRelationType").OnColumn("typeUniqueId")
- .Ascending()
- .WithOptions().NonClustered()
- .WithOptions().Unique()
- .Do();
- }
- }
-
- private void UpdateRelationTypeGuids()
- {
- var database = Database;
- var updates = database.Query("SELECT id, alias, name FROM umbracoRelationType")
- .Select(relationType => Tuple.Create((int) relationType.id, ("relationType____" + (string) relationType.alias + "____" + (string) relationType.name).ToGuid()))
- .ToList();
-
- foreach (var update in updates)
- database.Execute("UPDATE umbracoRelationType set typeUniqueId=@guid WHERE id=@id", new { guid = update.Item2, id = update.Item1 });
- }
- }
-}
diff --git a/src/Umbraco.Core/Migrations/Upgrade/V_7_6_0/NormalizeTemplateGuids.cs b/src/Umbraco.Core/Migrations/Upgrade/V_7_6_0/NormalizeTemplateGuids.cs
deleted file mode 100644
index 9e8c739104..0000000000
--- a/src/Umbraco.Core/Migrations/Upgrade/V_7_6_0/NormalizeTemplateGuids.cs
+++ /dev/null
@@ -1,37 +0,0 @@
-using System;
-using System.Linq;
-
-namespace Umbraco.Core.Migrations.Upgrade.V_7_6_0
-{
- public class NormalizeTemplateGuids : MigrationBase
- {
- public NormalizeTemplateGuids(IMigrationContext context)
- : base(context)
- { }
-
- public override void Migrate()
- {
- var database = Database;
-
- // we need this migration because ppl running pre-7.6 on Cloud and Courier have templates in different
- // environments having different GUIDs (Courier does not sync template GUIDs) and we need to normalize
- // these GUIDs so templates with the same alias on different environments have the same GUID.
- // however, if already running a prerelease version of 7.6, we do NOT want to normalize the GUIDs as quite
- // probably, we are already running Deploy and the GUIDs are OK. assuming noone is running a prerelease
- // of 7.6 on Courier.
- // so... testing if we already have a 7.6.0 version installed. not pretty but...?
- //
- var version = database.FirstOrDefault("SELECT version FROM umbracoMigration WHERE name=@name ORDER BY version DESC", new { name = Constants.System.UmbracoUpgradePlanName });
- if (version != null && version.StartsWith("7.6.0")) return;
-
- var updates = database.Query(@"SELECT umbracoNode.id, cmsTemplate.alias FROM umbracoNode
-JOIN cmsTemplate ON umbracoNode.id=cmsTemplate.nodeId
-WHERE nodeObjectType = @guid", new { guid = Constants.ObjectTypes.TemplateType })
- .Select(template => Tuple.Create((int) template.id, ("template____" + (string) template.alias).ToGuid()))
- .ToList();
-
- foreach (var update in updates)
- database.Execute("UPDATE umbracoNode set uniqueId=@guid WHERE id=@id", new { guid = update.Item2, id = update.Item1 });
- }
- }
-}
diff --git a/src/Umbraco.Core/Migrations/Upgrade/V_7_6_0/ReduceLoginNameColumnsSize.cs b/src/Umbraco.Core/Migrations/Upgrade/V_7_6_0/ReduceLoginNameColumnsSize.cs
deleted file mode 100644
index 1af21617f3..0000000000
--- a/src/Umbraco.Core/Migrations/Upgrade/V_7_6_0/ReduceLoginNameColumnsSize.cs
+++ /dev/null
@@ -1,41 +0,0 @@
-using System.Linq;
-using Umbraco.Core.Persistence.SqlSyntax;
-
-namespace Umbraco.Core.Migrations.Upgrade.V_7_6_0
-{
- public class ReduceLoginNameColumnsSize : MigrationBase
- {
- public ReduceLoginNameColumnsSize(IMigrationContext context)
- : base(context)
- { }
-
- public override void Migrate()
- {
- //Now we need to check if we can actually d6 this because we won't be able to if there's data in there that is too long
- //http://issues.umbraco.org/issue/U4-9758
-
- var database = Database;
- var dbIndexes = SqlSyntax.GetDefinedIndexesDefinitions(database);
-
- var colLen = database.ExecuteScalar("select max(datalength(LoginName)) from cmsMember");
-
- if (colLen < 900 == false) return;
-
- //if an index exists on this table we need to drop it. Normally we'd check via index name but in some odd cases (i.e. Our)
- //the index name is something odd (starts with "mi_"). In any case, the index cannot exist if we want to alter the column
- //so we'll drop whatever index is there and add one with the correct name after.
- var loginNameIndex = dbIndexes.FirstOrDefault(x => x.TableName.InvariantEquals("cmsMember") && x.ColumnName.InvariantEquals("LoginName"));
- if (loginNameIndex != null)
- {
- Delete.Index(loginNameIndex.IndexName).OnTable("cmsMember").Do();
- }
-
- //we can apply the col length change
- Alter.Table("cmsMember")
- .AlterColumn("LoginName")
- .AsString(225)
- .NotNullable()
- .Do();
- }
- }
-}
diff --git a/src/Umbraco.Core/Migrations/Upgrade/V_7_6_0/RemovePropertyDataIdIndex.cs b/src/Umbraco.Core/Migrations/Upgrade/V_7_6_0/RemovePropertyDataIdIndex.cs
deleted file mode 100644
index 804714d1ff..0000000000
--- a/src/Umbraco.Core/Migrations/Upgrade/V_7_6_0/RemovePropertyDataIdIndex.cs
+++ /dev/null
@@ -1,29 +0,0 @@
-using System.Linq;
-
-namespace Umbraco.Core.Migrations.Upgrade.V_7_6_0
-{
- ///
- /// See: http://issues.umbraco.org/issue/U4-9188
- ///
- public class UpdateUniqueIndexOnPropertyData : MigrationBase
- {
- public UpdateUniqueIndexOnPropertyData(IMigrationContext context)
- : base(context)
- { }
-
- public override void Migrate()
- {
- //tuple = tablename, indexname, columnname, unique
- var indexes = SqlSyntax.GetDefinedIndexes(Context.Database).ToArray();
- var found = indexes.FirstOrDefault(
- x => x.Item1.InvariantEquals("cmsPropertyData")
- && x.Item2.InvariantEquals("IX_cmsPropertyData"));
-
- if (found != null)
- {
- //drop the index
- Delete.Index("IX_cmsPropertyData").OnTable("cmsPropertyData").Do();
- }
- }
- }
-}
diff --git a/src/Umbraco.Core/Migrations/Upgrade/V_7_6_0/RemoveUmbracoDeployTables.cs b/src/Umbraco.Core/Migrations/Upgrade/V_7_6_0/RemoveUmbracoDeployTables.cs
deleted file mode 100644
index 744b441b32..0000000000
--- a/src/Umbraco.Core/Migrations/Upgrade/V_7_6_0/RemoveUmbracoDeployTables.cs
+++ /dev/null
@@ -1,30 +0,0 @@
-using System.Linq;
-
-namespace Umbraco.Core.Migrations.Upgrade.V_7_6_0
-{
- public class RemoveUmbracoDeployTables : MigrationBase
- {
- public RemoveUmbracoDeployTables(IMigrationContext context)
- : base(context)
- { }
-
- public override void Migrate()
- {
- var tables = SqlSyntax.GetTablesInSchema(Context.Database).ToArray();
-
- // there are two versions of umbracoDeployDependency,
- // 1. one created by 7.4 and never used, we need to remove it (has a sourceId column)
- // 2. one created by Deploy itself, we need to keep it (has a sourceUdi column)
- if (tables.InvariantContains("umbracoDeployDependency"))
- {
- var columns = SqlSyntax.GetColumnsInSchema(Context.Database).ToArray();
- if (columns.Any(x => x.TableName.InvariantEquals("umbracoDeployDependency") && x.ColumnName.InvariantEquals("sourceId")))
- Delete.Table("umbracoDeployDependency").Do();
- }
-
- // always remove umbracoDeployChecksum
- if (tables.InvariantContains("umbracoDeployChecksum"))
- Delete.Table("umbracoDeployChecksum").Do();
- }
- }
-}
diff --git a/src/Umbraco.Core/Migrations/Upgrade/V_7_7_0/AddIndexToDictionaryKeyColumn.cs b/src/Umbraco.Core/Migrations/Upgrade/V_7_7_0/AddIndexToDictionaryKeyColumn.cs
deleted file mode 100644
index b366c7dab9..0000000000
--- a/src/Umbraco.Core/Migrations/Upgrade/V_7_7_0/AddIndexToDictionaryKeyColumn.cs
+++ /dev/null
@@ -1,38 +0,0 @@
-using System.Linq;
-using Umbraco.Core.Persistence.SqlSyntax;
-
-namespace Umbraco.Core.Migrations.Upgrade.V_7_7_0
-{
- public class AddIndexToDictionaryKeyColumn : MigrationBase
- {
- public AddIndexToDictionaryKeyColumn(IMigrationContext context)
- : base(context)
- { }
-
- public override void Migrate()
- {
- var database = Database;
- //Now we need to check if we can actually do this because we won't be able to if there's data in there that is too long
- var colLen = database.ExecuteScalar(string.Format("select max(datalength({0})) from cmsDictionary", SqlSyntax.GetQuotedColumnName("key")));
-
- if (colLen < 900 == false && colLen != null)
- {
- return;
- }
-
- var dbIndexes = SqlSyntax.GetDefinedIndexesDefinitions(Context.Database);
-
- //make sure it doesn't already exist
- if (dbIndexes.Any(x => x.IndexName.InvariantEquals("IX_cmsDictionary_key")) == false)
- {
- //we can apply the index
- Create.Index("IX_cmsDictionary_key").OnTable("cmsDictionary")
- .OnColumn("key")
- .Ascending()
- .WithOptions()
- .NonClustered()
- .Do();
- }
- }
- }
-}
diff --git a/src/Umbraco.Core/Migrations/Upgrade/V_7_7_0/AddUserGroupTables.cs b/src/Umbraco.Core/Migrations/Upgrade/V_7_7_0/AddUserGroupTables.cs
deleted file mode 100644
index edd78e6c84..0000000000
--- a/src/Umbraco.Core/Migrations/Upgrade/V_7_7_0/AddUserGroupTables.cs
+++ /dev/null
@@ -1,357 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Data;
-using System.Linq;
-using Umbraco.Core.Persistence;
-using Umbraco.Core.Persistence.Dtos;
-using ColumnInfo = Umbraco.Core.Persistence.SqlSyntax.ColumnInfo;
-
-namespace Umbraco.Core.Migrations.Upgrade.V_7_7_0
-{
- public class AddUserGroupTables : MigrationBase
- {
- private readonly string _collateSyntax;
-
- public AddUserGroupTables(IMigrationContext context)
- : base(context)
- {
- //For some of the migration data inserts we require to use a special MSSQL collate expression since
- //some databases may have a custom collation specified and if that is the case, when we compare strings
- //in dynamic SQL it will try to compare strings in different collations and this will yield errors.
- _collateSyntax = "COLLATE DATABASE_DEFAULT";
- }
-
- public override void Migrate()
- {
- var tables = SqlSyntax.GetTablesInSchema(Context.Database).ToList();
- var constraints = SqlSyntax.GetConstraintsPerColumn(Context.Database).Distinct().ToArray();
- var columns = SqlSyntax.GetColumnsInSchema(Context.Database).ToArray();
-
- //In some very rare cases, there might already be user group tables that we'll need to remove first
- //but of course we don't want to remove the tables we will be creating below if they already exist so
- //need to do some checks first since these old rare tables have a different schema
- RemoveOldTablesIfExist(tables, columns);
-
- if (AddNewTables(tables))
- {
- MigrateUserPermissions();
- MigrateUserTypesToGroups();
- DeleteOldTables(tables, constraints);
- SetDefaultIcons();
- }
- else
- {
- //if we aren't adding the tables, make sure that the umbracoUserGroup table has the correct FKs - these
- //were added after the beta release so we need to do some cleanup
- //if the FK doesn't exist
- if (constraints.Any(x => x.Item1.InvariantEquals("umbracoUserGroup")
- && x.Item2.InvariantEquals("startContentId")
- && x.Item3.InvariantEquals("FK_startContentId_umbracoNode_id")) == false)
- {
- //before we add any foreign key we need to make sure there's no stale data in there which would have happened in the beta
- //release if a start node was assigned and then that start node was deleted.
- Database.Execute(@"UPDATE umbracoUserGroup SET startContentId = NULL WHERE startContentId NOT IN (SELECT id FROM umbracoNode)");
-
- Create.ForeignKey("FK_startContentId_umbracoNode_id")
- .FromTable("umbracoUserGroup")
- .ForeignColumn("startContentId")
- .ToTable("umbracoNode")
- .PrimaryColumn("id")
- .OnDelete(Rule.None)
- .OnUpdate(Rule.None)
- .Do();
- }
-
- if (constraints.Any(x => x.Item1.InvariantEquals("umbracoUserGroup")
- && x.Item2.InvariantEquals("startMediaId")
- && x.Item3.InvariantEquals("FK_startMediaId_umbracoNode_id")) == false)
- {
- //before we add any foreign key we need to make sure there's no stale data in there which would have happened in the beta
- //release if a start node was assigned and then that start node was deleted.
- Database.Execute(@"UPDATE umbracoUserGroup SET startMediaId = NULL WHERE startMediaId NOT IN (SELECT id FROM umbracoNode)");
-
- Create.ForeignKey("FK_startMediaId_umbracoNode_id")
- .FromTable("umbracoUserGroup")
- .ForeignColumn("startMediaId")
- .ToTable("umbracoNode")
- .PrimaryColumn("id")
- .OnDelete(Rule.None)
- .OnUpdate(Rule.None)
- .Do();
- }
- }
- }
-
- ///
- /// In some very rare cases, there might already be user group tables that we'll need to remove first
- /// but of course we don't want to remove the tables we will be creating below if they already exist so
- /// need to do some checks first since these old rare tables have a different schema
- ///
- ///
- ///
- private void RemoveOldTablesIfExist(List tables, ColumnInfo[] columns)
- {
- if (tables.Contains("umbracoUser2userGroup", StringComparer.InvariantCultureIgnoreCase))
- {
- //this column doesn't exist in the 7.7 schema, so if it's there, then this is a super old table
- var foundOldColumn = columns
- .FirstOrDefault(x =>
- x.ColumnName.Equals("user", StringComparison.InvariantCultureIgnoreCase)
- && x.TableName.Equals("umbracoUser2userGroup", StringComparison.InvariantCultureIgnoreCase));
- if (foundOldColumn != null)
- {
- Delete.Table("umbracoUser2userGroup").Do();
- //remove from the tables list since this will be re-checked in further logic
- tables.Remove("umbracoUser2userGroup");
- }
- }
-
- if (tables.Contains("umbracoUserGroup", StringComparer.InvariantCultureIgnoreCase))
- {
- //The new schema has several columns, the super old one for this table only had 2 so if it's 2 get rid of it
- var countOfCols = columns
- .Count(x => x.TableName.Equals("umbracoUserGroup", StringComparison.InvariantCultureIgnoreCase));
- if (countOfCols == 2)
- {
- Delete.Table("umbracoUserGroup").Do();
- //remove from the tables list since this will be re-checked in further logic
- tables.Remove("umbracoUserGroup");
- }
- }
- }
-
- private void SetDefaultIcons()
- {
- Database.Execute($"UPDATE umbracoUserGroup SET icon = \'\' WHERE userGroupAlias = \'{Constants.Security.AdminGroupAlias}\'");
- Database.Execute("UPDATE umbracoUserGroup SET icon = \'icon-edit\' WHERE userGroupAlias = \'writer\'");
- Database.Execute("UPDATE umbracoUserGroup SET icon = \'icon-tools\' WHERE userGroupAlias = \'editor\'");
- Database.Execute("UPDATE umbracoUserGroup SET icon = \'icon-globe\' WHERE userGroupAlias = \'translator\'");
- }
-
- private bool AddNewTables(List tables)
- {
- var updated = false;
- if (tables.InvariantContains("umbracoUserGroup") == false)
- {
- Create.Table().Do();
- updated = true;
- }
-
- if (tables.InvariantContains("umbracoUser2UserGroup") == false)
- {
- Create.Table().Do();
- updated = true;
- }
-
- if (tables.InvariantContains("umbracoUserGroup2App") == false)
- {
- Create.Table().Do();
- updated = true;
- }
-
- if (tables.InvariantContains("umbracoUserGroup2NodePermission") == false)
- {
- Create.Table().Do();
- updated = true;
- }
-
- return updated;
- }
-
- private void MigrateUserTypesToGroups()
- {
- // Create a user group for each user type
- Database.Execute(@"INSERT INTO umbracoUserGroup (userGroupAlias, userGroupName, userGroupDefaultPermissions)
- SELECT userTypeAlias, userTypeName, userTypeDefaultPermissions
- FROM umbracoUserType");
-
- // Add each user to the group created from their type
- Database.Execute(string.Format(@"INSERT INTO umbracoUser2UserGroup (userId, userGroupId)
- SELECT u.id, ug.id
- FROM umbracoUser u
- INNER JOIN umbracoUserType ut ON ut.id = u.userType
- INNER JOIN umbracoUserGroup ug ON ug.userGroupAlias {0} = ut.userTypeAlias {0}", _collateSyntax));
-
- // Add the built-in administrator account to all apps
- // this will lookup all of the apps that the admin currently has access to in order to assign the sections
- // instead of use statically assigning since there could be extra sections we don't know about.
- Database.Execute(@"INSERT INTO umbracoUserGroup2app (userGroupId,app)
- SELECT ug.id, app
- FROM umbracoUserGroup ug
- INNER JOIN umbracoUser2UserGroup u2ug ON u2ug.userGroupId = ug.id
- INNER JOIN umbracoUser u ON u.id = u2ug.userId
- INNER JOIN umbracoUser2app u2a ON u2a." + SqlSyntax.GetQuotedColumnName("user") + @" = u.id
- WHERE u.id = 0");
-
- // Add the default section access to the other built-in accounts
- // writer:
- Database.Execute(string.Format(@"INSERT INTO umbracoUserGroup2app (userGroupId, app)
- SELECT ug.id, 'content' as app
- FROM umbracoUserGroup ug
- WHERE ug.userGroupAlias {0} = 'writer' {0}", _collateSyntax));
- // editor
- Database.Execute(string.Format(@"INSERT INTO umbracoUserGroup2app (userGroupId, app)
- SELECT ug.id, 'content' as app
- FROM umbracoUserGroup ug
- WHERE ug.userGroupAlias {0} = 'editor' {0}", _collateSyntax));
- Database.Execute(string.Format(@"INSERT INTO umbracoUserGroup2app (userGroupId, app)
- SELECT ug.id, 'media' as app
- FROM umbracoUserGroup ug
- WHERE ug.userGroupAlias {0} = 'editor' {0}", _collateSyntax));
- // translator
- Database.Execute(string.Format(@"INSERT INTO umbracoUserGroup2app (userGroupId, app)
- SELECT ug.id, 'translation' as app
- FROM umbracoUserGroup ug
- WHERE ug.userGroupAlias {0} = 'translator' {0}", _collateSyntax));
-
- //We need to lookup all distinct combinations of section access and create a group for each distinct collection
- //and assign groups accordingly. We'll perform the lookup 'now' to then create the queued SQL migrations.
- var userAppsData = Context.Database.Query(@"SELECT u.id, u2a.app FROM umbracoUser u
- INNER JOIN umbracoUser2app u2a ON u2a." + SqlSyntax.GetQuotedColumnName("user") + @" = u.id
- ORDER BY u.id, u2a.app");
- var usersWithApps = new Dictionary>();
- foreach (var userApps in userAppsData)
- {
- if (usersWithApps.TryGetValue(userApps.id, out List apps) == false)
- {
- apps = new List {userApps.app};
- usersWithApps.Add(userApps.id, apps);
- }
- else
- {
- apps.Add(userApps.app);
- }
- }
- //At this stage we have a dictionary of users with a collection of their apps which are sorted
- //and we need to determine the unique/distinct app collections for each user to create groups with.
- //We can do this by creating a hash value of all of the app values and since they are already sorted we can get a distinct
- //collection by this hash.
- var distinctApps = usersWithApps
- .Select(x => new {appCollection = x.Value, appsHash = string.Join("", x.Value).GenerateHash()})
- .DistinctBy(x => x.appsHash)
- .ToArray();
- //Now we need to create user groups for each of these distinct app collections, and then assign the corresponding users to those groups
- for (var i = 0; i < distinctApps.Length; i++)
- {
- //create the group
- var alias = "MigratedSectionAccessGroup_" + (i + 1);
- Insert.IntoTable("umbracoUserGroup").Row(new
- {
- userGroupAlias = "MigratedSectionAccessGroup_" + (i + 1),
- userGroupName = "Migrated Section Access Group " + (i + 1)
- }).Do();
- //now assign the apps
- var distinctApp = distinctApps[i];
- foreach (var app in distinctApp.appCollection)
- {
- Database.Execute(string.Format(@"INSERT INTO umbracoUserGroup2app (userGroupId, app)
- SELECT ug.id, '" + app + @"' as app
- FROM umbracoUserGroup ug
- WHERE ug.userGroupAlias {0} = '" + alias + "' {0}", _collateSyntax));
- }
- //now assign the corresponding users to this group
- foreach (var userWithApps in usersWithApps)
- {
- //check if this user's groups hash matches the current groups hash
- var hash = string.Join("", userWithApps.Value).GenerateHash();
- if (hash == distinctApp.appsHash)
- {
- //it matches so assign the user to this group
- Database.Execute(string.Format(@"INSERT INTO umbracoUser2UserGroup (userId, userGroupId)
- SELECT " + userWithApps.Key + @", ug.id
- FROM umbracoUserGroup ug
- WHERE ug.userGroupAlias {0} = '" + alias + "' {0}", _collateSyntax));
- }
- }
- }
-
- // Rename some groups for consistency (plural form)
- Database.Execute("UPDATE umbracoUserGroup SET userGroupName = 'Writers' WHERE userGroupAlias = 'writer'");
- Database.Execute("UPDATE umbracoUserGroup SET userGroupName = 'Translators' WHERE userGroupAlias = 'translator'");
-
- //Ensure all built in groups have a start node of -1
- Database.Execute("UPDATE umbracoUserGroup SET startContentId = -1 WHERE userGroupAlias = 'editor'");
- Database.Execute("UPDATE umbracoUserGroup SET startMediaId = -1 WHERE userGroupAlias = 'editor'");
- Database.Execute("UPDATE umbracoUserGroup SET startContentId = -1 WHERE userGroupAlias = 'writer'");
- Database.Execute("UPDATE umbracoUserGroup SET startMediaId = -1 WHERE userGroupAlias = 'writer'");
- Database.Execute("UPDATE umbracoUserGroup SET startContentId = -1 WHERE userGroupAlias = 'translator'");
- Database.Execute("UPDATE umbracoUserGroup SET startMediaId = -1 WHERE userGroupAlias = 'translator'");
- Database.Execute("UPDATE umbracoUserGroup SET startContentId = -1 WHERE userGroupAlias = 'admin'");
- Database.Execute("UPDATE umbracoUserGroup SET startMediaId = -1 WHERE userGroupAlias = 'admin'");
- }
-
- private void MigrateUserPermissions()
- {
- // Create user group records for all non-admin users that have specific permissions set
- Database.Execute(@"INSERT INTO umbracoUserGroup(userGroupAlias, userGroupName)
- SELECT 'permissionGroupFor' + userLogin, 'Migrated Permission Group for ' + userLogin
- FROM umbracoUser
- WHERE (id IN (
- SELECT userid
- FROM umbracoUser2NodePermission
- ))
- AND id > 0");
-
- // Associate those groups with the users
- Database.Execute(string.Format(@"INSERT INTO umbracoUser2UserGroup (userId, userGroupId)
- SELECT u.id, ug.id
- FROM umbracoUser u
- INNER JOIN umbracoUserGroup ug ON ug.userGroupAlias {0} = 'permissionGroupFor' + userLogin {0}", _collateSyntax));
-
- // Create node permissions on the groups
- Database.Execute(string.Format(@"INSERT INTO umbracoUserGroup2NodePermission (userGroupId,nodeId,permission)
- SELECT ug.id, nodeId, permission
- FROM umbracoUserGroup ug
- INNER JOIN umbracoUser2UserGroup u2ug ON u2ug.userGroupId = ug.id
- INNER JOIN umbracoUser u ON u.id = u2ug.userId
- INNER JOIN umbracoUser2NodePermission u2np ON u2np.userId = u.id
- WHERE ug.userGroupAlias {0} NOT IN (
- SELECT userTypeAlias {0}
- FROM umbracoUserType
- )", _collateSyntax));
-
- // Create app permissions on the groups
- Database.Execute(string.Format(@"INSERT INTO umbracoUserGroup2app (userGroupId,app)
- SELECT ug.id, app
- FROM umbracoUserGroup ug
- INNER JOIN umbracoUser2UserGroup u2ug ON u2ug.userGroupId = ug.id
- INNER JOIN umbracoUser u ON u.id = u2ug.userId
- INNER JOIN umbracoUser2app u2a ON u2a." + SqlSyntax.GetQuotedColumnName("user") + @" = u.id
- WHERE ug.userGroupAlias {0} NOT IN (
- SELECT userTypeAlias {0}
- FROM umbracoUserType
- )", _collateSyntax));
- }
-
- private void DeleteOldTables(List tables, Tuple[] constraints)
- {
- if (tables.InvariantContains("umbracoUser2App"))
- {
- Delete.Table("umbracoUser2App").Do();
- }
-
- if (tables.InvariantContains("umbracoUser2NodePermission"))
- {
- Delete.Table("umbracoUser2NodePermission").Do();
- }
-
- if (tables.InvariantContains("umbracoUserType") && tables.InvariantContains("umbracoUser"))
- {
- //Delete the FK if it exists before dropping the column
- if (constraints.Any(x => x.Item1.InvariantEquals("umbracoUser") && x.Item3.InvariantEquals("FK_umbracoUser_umbracoUserType_id")))
- {
- Delete.ForeignKey("FK_umbracoUser_umbracoUserType_id").OnTable("umbracoUser").Do();
- }
-
- //This is the super old constraint name of the FK for user type so check this one too
- if (constraints.Any(x => x.Item1.InvariantEquals("umbracoUser") && x.Item3.InvariantEquals("FK_user_userType")))
- {
- Delete.ForeignKey("FK_user_userType").OnTable("umbracoUser").Do();
- }
-
- Delete.Column("userType").FromTable("umbracoUser").Do();
- Delete.Table("umbracoUserType").Do();
- }
- }
- }
-}
diff --git a/src/Umbraco.Core/Migrations/Upgrade/V_7_7_0/AddUserStartNodeTable.cs b/src/Umbraco.Core/Migrations/Upgrade/V_7_7_0/AddUserStartNodeTable.cs
deleted file mode 100644
index 54545e06d3..0000000000
--- a/src/Umbraco.Core/Migrations/Upgrade/V_7_7_0/AddUserStartNodeTable.cs
+++ /dev/null
@@ -1,41 +0,0 @@
-using System.Linq;
-using Umbraco.Core.Persistence.Dtos;
-
-namespace Umbraco.Core.Migrations.Upgrade.V_7_7_0
-{
- public class AddUserStartNodeTable : MigrationBase
- {
- public AddUserStartNodeTable(IMigrationContext context)
- : base(context)
- { }
-
- public override void Migrate()
- {
- var tables = SqlSyntax.GetTablesInSchema(Context.Database).ToArray();
-
- if (tables.InvariantContains("umbracoUserStartNode")) return;
-
- Create.Table().Do();
-
- MigrateUserStartNodes();
-
- //now remove the old columns
-
- Delete.Column("startStructureID").FromTable("umbracoUser").Do();
- Delete.Column("startMediaID").FromTable("umbracoUser").Do();
- }
-
- private void MigrateUserStartNodes()
- {
- Database.Execute(@"INSERT INTO umbracoUserStartNode (userId, startNode, startNodeType)
- SELECT id, startStructureID, 1
- FROM umbracoUser
- WHERE startStructureID IS NOT NULL AND startStructureID > 0 AND startStructureID IN (SELECT id FROM umbracoNode WHERE nodeObjectType='" + Constants.ObjectTypes.Document + "')");
-
- Database.Execute(@"INSERT INTO umbracoUserStartNode (userId, startNode, startNodeType)
- SELECT id, startMediaID, 2
- FROM umbracoUser
- WHERE startMediaID IS NOT NULL AND startMediaID > 0 AND startMediaID IN (SELECT id FROM umbracoNode WHERE nodeObjectType='" + Constants.ObjectTypes.Media + "')");
- }
- }
-}
diff --git a/src/Umbraco.Core/Migrations/Upgrade/V_7_7_0/EnsureContentTemplatePermissions.cs b/src/Umbraco.Core/Migrations/Upgrade/V_7_7_0/EnsureContentTemplatePermissions.cs
deleted file mode 100644
index 1f7e2faf33..0000000000
--- a/src/Umbraco.Core/Migrations/Upgrade/V_7_7_0/EnsureContentTemplatePermissions.cs
+++ /dev/null
@@ -1,37 +0,0 @@
-using System.Linq;
-using Umbraco.Core.Persistence;
-using Umbraco.Core.Persistence.Dtos;
-
-namespace Umbraco.Core.Migrations.Upgrade.V_7_7_0
-{
- ///
- /// Ensures the built-in user groups have the blueprint permission by default on upgrade
- ///
- public class EnsureContentTemplatePermissions : MigrationBase
- {
- public EnsureContentTemplatePermissions(IMigrationContext context)
- : base(context)
- { }
-
- public override void Migrate()
- {
- var database = Database;
- var userGroups = database.Fetch(
- Context.SqlContext.Sql().Select("*")
- .From()
- .Where(x => x.Alias == "admin" || x.Alias == "editor"));
-
- foreach (var userGroup in userGroups)
- {
- if (userGroup.DefaultPermissions.Contains('�') == false)
- {
- userGroup.DefaultPermissions += "�";
- Update.Table("umbracoUserGroup")
- .Set(new { userGroupDefaultPermissions = userGroup.DefaultPermissions })
- .Where(new { id = userGroup.Id })
- .Do();
- }
- }
- }
- }
-}
diff --git a/src/Umbraco.Core/Migrations/Upgrade/V_7_7_0/ReduceDictionaryKeyColumnsSize.cs b/src/Umbraco.Core/Migrations/Upgrade/V_7_7_0/ReduceDictionaryKeyColumnsSize.cs
deleted file mode 100644
index 17dd3064eb..0000000000
--- a/src/Umbraco.Core/Migrations/Upgrade/V_7_7_0/ReduceDictionaryKeyColumnsSize.cs
+++ /dev/null
@@ -1,37 +0,0 @@
-using System.Linq;
-using Umbraco.Core.Persistence.SqlSyntax;
-
-namespace Umbraco.Core.Migrations.Upgrade.V_7_7_0
-{
- public class ReduceDictionaryKeyColumnsSize : MigrationBase
- {
- public ReduceDictionaryKeyColumnsSize(IMigrationContext context)
- : base(context)
- { }
-
- public override void Migrate()
- {
- //Now we need to check if we can actually do this because we won't be able to if there's data in there that is too long
-
- var database = Database;
- var dbIndexes = SqlSyntax.GetDefinedIndexesDefinitions(database);
-
- var colLen = database.ExecuteScalar(string.Format("select max(datalength({0})) from cmsDictionary", SqlSyntax.GetQuotedColumnName("key")));
-
- if (colLen < 900 == false) return;
-
- //if it exists we need to drop it first
- if (dbIndexes.Any(x => x.IndexName.InvariantEquals("IX_cmsDictionary_key")))
- {
- Delete.Index("IX_cmsDictionary_key").OnTable("cmsDictionary").Do();
- }
-
- //we can apply the col length change
- Alter.Table("cmsDictionary")
- .AlterColumn("key")
- .AsString(450)
- .NotNullable()
- .Do();
- }
- }
-}
diff --git a/src/Umbraco.Core/Migrations/Upgrade/V_7_7_0/UpdateUserTables.cs b/src/Umbraco.Core/Migrations/Upgrade/V_7_7_0/UpdateUserTables.cs
deleted file mode 100644
index 509b3f91dd..0000000000
--- a/src/Umbraco.Core/Migrations/Upgrade/V_7_7_0/UpdateUserTables.cs
+++ /dev/null
@@ -1,48 +0,0 @@
-using System.Linq;
-using System.Web.Security;
-using Newtonsoft.Json;
-using Umbraco.Core.Persistence.DatabaseModelDefinitions;
-using Umbraco.Core.Security;
-
-namespace Umbraco.Core.Migrations.Upgrade.V_7_7_0
-{
- public class UpdateUserTables : MigrationBase
- {
- public UpdateUserTables(IMigrationContext context)
- : base(context)
- { }
-
- public override void Migrate()
- {
- //Don't execute if the column is already there
- var columns = SqlSyntax.GetColumnsInSchema(Context.Database).ToArray();
-
- if (columns.Any(x => x.TableName.InvariantEquals("umbracoUser") && x.ColumnName.InvariantEquals("createDate")) == false)
- Create.Column("createDate").OnTable("umbracoUser").AsDateTime().NotNullable().WithDefault(SystemMethods.CurrentDateTime).Do();
-
- if (columns.Any(x => x.TableName.InvariantEquals("umbracoUser") && x.ColumnName.InvariantEquals("updateDate")) == false)
- Create.Column("updateDate").OnTable("umbracoUser").AsDateTime().NotNullable().WithDefault(SystemMethods.CurrentDateTime).Do();
-
- if (columns.Any(x => x.TableName.InvariantEquals("umbracoUser") && x.ColumnName.InvariantEquals("emailConfirmedDate")) == false)
- Create.Column("emailConfirmedDate").OnTable("umbracoUser").AsDateTime().Nullable().Do();
-
- if (columns.Any(x => x.TableName.InvariantEquals("umbracoUser") && x.ColumnName.InvariantEquals("invitedDate")) == false)
- Create.Column("invitedDate").OnTable("umbracoUser").AsDateTime().Nullable().Do();
-
- if (columns.Any(x => x.TableName.InvariantEquals("umbracoUser") && x.ColumnName.InvariantEquals("avatar")) == false)
- Create.Column("avatar").OnTable("umbracoUser").AsString(500).Nullable().Do();
-
- if (columns.Any(x => x.TableName.InvariantEquals("umbracoUser") && x.ColumnName.InvariantEquals("passwordConfig")) == false)
- {
- Create.Column("passwordConfig").OnTable("umbracoUser").AsString(500).Nullable().Do();
- //Check if we have a known config, we only want to store config for hashing
- var membershipProvider = MembershipProviderExtensions.GetUsersMembershipProvider();
- if (membershipProvider.PasswordFormat == MembershipPasswordFormat.Hashed)
- {
- var json = JsonConvert.SerializeObject(new { hashAlgorithm = Membership.HashAlgorithmType });
- Database.Execute("UPDATE umbracoUser SET passwordConfig = '" + json + "'");
- }
- }
- }
- }
-}
diff --git a/src/Umbraco.Core/Migrations/Upgrade/V_7_8_0/AddIndexToPropertyTypeAliasColumn.cs b/src/Umbraco.Core/Migrations/Upgrade/V_7_8_0/AddIndexToPropertyTypeAliasColumn.cs
deleted file mode 100644
index ddb084a609..0000000000
--- a/src/Umbraco.Core/Migrations/Upgrade/V_7_8_0/AddIndexToPropertyTypeAliasColumn.cs
+++ /dev/null
@@ -1,27 +0,0 @@
-using System.Linq;
-using Umbraco.Core.Persistence.SqlSyntax;
-
-namespace Umbraco.Core.Migrations.Upgrade.V_7_8_0
-{
- internal class AddIndexToPropertyTypeAliasColumn : MigrationBase
- {
- public AddIndexToPropertyTypeAliasColumn(IMigrationContext context)
- : base(context)
- { }
-
- public override void Migrate()
- {
- var dbIndexes = SqlSyntax.GetDefinedIndexesDefinitions(Context.Database);
-
- //make sure it doesn't already exist
- if (dbIndexes.Any(x => x.IndexName.InvariantEquals("IX_cmsPropertyTypeAlias")) == false)
- {
- //we can apply the index
- Create.Index("IX_cmsPropertyTypeAlias").OnTable(Constants.DatabaseSchema.Tables.PropertyType)
- .OnColumn("Alias")
- .Ascending().WithOptions().NonClustered()
- .Do();
- }
- }
- }
-}
diff --git a/src/Umbraco.Core/Migrations/Upgrade/V_7_8_0/AddInstructionCountColumn.cs b/src/Umbraco.Core/Migrations/Upgrade/V_7_8_0/AddInstructionCountColumn.cs
deleted file mode 100644
index 0ce2c91f2e..0000000000
--- a/src/Umbraco.Core/Migrations/Upgrade/V_7_8_0/AddInstructionCountColumn.cs
+++ /dev/null
@@ -1,20 +0,0 @@
-using System.Linq;
-using Umbraco.Core.Persistence.Dtos;
-
-namespace Umbraco.Core.Migrations.Upgrade.V_7_8_0
-{
- internal class AddInstructionCountColumn : MigrationBase
- {
- public AddInstructionCountColumn(IMigrationContext context)
- : base(context)
- { }
-
- public override void Migrate()
- {
- var columns = SqlSyntax.GetColumnsInSchema(Context.Database).ToArray();
-
- if (columns.Any(x => x.TableName.InvariantEquals(Constants.DatabaseSchema.Tables.CacheInstruction) && x.ColumnName.InvariantEquals("instructionCount")) == false)
- AddColumn("instructionCount");
- }
- }
-}
diff --git a/src/Umbraco.Core/Migrations/Upgrade/V_7_8_0/AddMediaVersionTable.cs b/src/Umbraco.Core/Migrations/Upgrade/V_7_8_0/AddMediaVersionTable.cs
deleted file mode 100644
index b4c0062770..0000000000
--- a/src/Umbraco.Core/Migrations/Upgrade/V_7_8_0/AddMediaVersionTable.cs
+++ /dev/null
@@ -1,65 +0,0 @@
-using System.Collections.Generic;
-using System.Linq;
-using Umbraco.Core.Persistence;
-using Umbraco.Core.Persistence.Dtos;
-using Umbraco.Core.Persistence.Factories;
-using static Umbraco.Core.Persistence.NPocoSqlExtensions.Statics;
-
-namespace Umbraco.Core.Migrations.Upgrade.V_7_8_0
-{
- internal class AddMediaVersionTable : MigrationBase
- {
- public AddMediaVersionTable(IMigrationContext context)
- : base(context)
- { }
-
- public override void Migrate()
- {
- var tables = SqlSyntax.GetTablesInSchema(Context.Database).ToArray();
-
- if (tables.InvariantContains(Constants.DatabaseSchema.Tables.MediaVersion)) return;
-
- Create.Table().Do();
- MigrateMediaPaths();
- }
-
- private void MigrateMediaPaths()
- {
- // this may not be the most efficient way to do it, compared to how it's done in v7, but this
- // migration should only run for v8 sites that are being developed, before v8 is released, so
- // no big sites and performances don't matter here - keep it simple
-
- var sql = Sql()
- .Select(x => x.VarcharValue, x => x.TextValue)
- .AndSelect(x => Alias(x.Id, "versionId"))
- .From()
- .InnerJoin().On((left, right) => left.PropertyTypeId == right.Id)
- .InnerJoin().On((left, right) => left.VersionId == right.Id)
- .InnerJoin().On((left, right) => left.NodeId == right.NodeId)
- .Where(x => x.Alias == "umbracoFile")
- .Where(x => x.NodeObjectType == Constants.ObjectTypes.Media);
-
- var paths = new List();
-
- //using QUERY = a db cursor, we won't load this all into memory first, just row by row
- foreach (var row in Database.Query(sql))
- {
- // if there's values then ensure there's a media path match and extract it
- string mediaPath = null;
- if (
- (row.varcharValue != null && ContentBaseFactory.TryMatch((string) row.varcharValue, out mediaPath))
- || (row.textValue != null && ContentBaseFactory.TryMatch((string) row.textValue, out mediaPath)))
- {
- paths.Add(new MediaVersionDto
- {
- Id = (int) row.versionId,
- Path = mediaPath
- });
- }
- }
-
- // bulk insert
- Database.BulkInsertRecords(paths);
- }
- }
-}
diff --git a/src/Umbraco.Core/Migrations/Upgrade/V_7_8_0/AddTourDataUserColumn.cs b/src/Umbraco.Core/Migrations/Upgrade/V_7_8_0/AddTourDataUserColumn.cs
deleted file mode 100644
index cd2678205f..0000000000
--- a/src/Umbraco.Core/Migrations/Upgrade/V_7_8_0/AddTourDataUserColumn.cs
+++ /dev/null
@@ -1,21 +0,0 @@
-using System.Linq;
-using Umbraco.Core.Persistence.DatabaseAnnotations;
-using Umbraco.Core.Persistence.Dtos;
-
-namespace Umbraco.Core.Migrations.Upgrade.V_7_8_0
-{
- internal class AddTourDataUserColumn : MigrationBase
- {
- public AddTourDataUserColumn(IMigrationContext context)
- : base(context)
- { }
-
- public override void Migrate()
- {
- var columns = SqlSyntax.GetColumnsInSchema(Context.Database).ToArray();
-
- if (columns.Any(x => x.TableName.InvariantEquals(Constants.DatabaseSchema.Tables.User) && x.ColumnName.InvariantEquals("tourData")) == false)
- AddColumn("tourData");
- }
- }
-}
diff --git a/src/Umbraco.Core/Migrations/Upgrade/V_7_8_0/AddUserLoginTable.cs b/src/Umbraco.Core/Migrations/Upgrade/V_7_8_0/AddUserLoginTable.cs
deleted file mode 100644
index 7a55362072..0000000000
--- a/src/Umbraco.Core/Migrations/Upgrade/V_7_8_0/AddUserLoginTable.cs
+++ /dev/null
@@ -1,22 +0,0 @@
-using System.Linq;
-using Umbraco.Core.Persistence.Dtos;
-
-namespace Umbraco.Core.Migrations.Upgrade.V_7_8_0
-{
- internal class AddUserLoginTable : MigrationBase
- {
- public AddUserLoginTable(IMigrationContext context)
- : base(context)
- { }
-
- public override void Migrate()
- {
- var tables = SqlSyntax.GetTablesInSchema(Context.Database).ToArray();
-
- if (tables.InvariantContains(Constants.DatabaseSchema.Tables.UserLogin) == false)
- {
- Create.Table().Do();
- }
- }
- }
-}
diff --git a/src/Umbraco.Core/Migrations/Upgrade/V_7_9_0/AddIsSensitiveMemberTypeColumn.cs b/src/Umbraco.Core/Migrations/Upgrade/V_7_9_0/AddIsSensitiveMemberTypeColumn.cs
deleted file mode 100644
index 2b5f481769..0000000000
--- a/src/Umbraco.Core/Migrations/Upgrade/V_7_9_0/AddIsSensitiveMemberTypeColumn.cs
+++ /dev/null
@@ -1,20 +0,0 @@
-using System.Linq;
-using Umbraco.Core.Persistence.Dtos;
-
-namespace Umbraco.Core.Migrations.Upgrade.V_7_9_0
-{
- internal class AddIsSensitiveMemberTypeColumn : MigrationBase
- {
- public AddIsSensitiveMemberTypeColumn(IMigrationContext context)
- : base(context)
- { }
-
- public override void Migrate()
- {
- var columns = SqlSyntax.GetColumnsInSchema(Context.Database).ToArray();
-
- if (columns.Any(x => x.TableName.InvariantEquals(Constants.DatabaseSchema.Tables.MemberPropertyType) && x.ColumnName.InvariantEquals("isSensitive")) == false)
- AddColumn("isSensitive");
- }
- }
-}
diff --git a/src/Umbraco.Core/Migrations/Upgrade/V_7_9_0/AddUmbracoAuditTable.cs b/src/Umbraco.Core/Migrations/Upgrade/V_7_9_0/AddUmbracoAuditTable.cs
deleted file mode 100644
index e7880dfc73..0000000000
--- a/src/Umbraco.Core/Migrations/Upgrade/V_7_9_0/AddUmbracoAuditTable.cs
+++ /dev/null
@@ -1,22 +0,0 @@
-using System.Linq;
-using Umbraco.Core.Persistence.Dtos;
-
-namespace Umbraco.Core.Migrations.Upgrade.V_7_9_0
-{
- internal class AddUmbracoAuditTable : MigrationBase
- {
- public AddUmbracoAuditTable(IMigrationContext context)
- : base(context)
- { }
-
- public override void Migrate()
- {
- var tables = SqlSyntax.GetTablesInSchema(Context.Database).ToArray();
-
- if (tables.InvariantContains(Constants.DatabaseSchema.Tables.AuditEntry))
- return;
-
- Create.Table().Do();
- }
- }
-}
diff --git a/src/Umbraco.Core/Migrations/Upgrade/V_7_9_0/AddUmbracoConsentTable.cs b/src/Umbraco.Core/Migrations/Upgrade/V_7_9_0/AddUmbracoConsentTable.cs
deleted file mode 100644
index e3656f69ac..0000000000
--- a/src/Umbraco.Core/Migrations/Upgrade/V_7_9_0/AddUmbracoConsentTable.cs
+++ /dev/null
@@ -1,22 +0,0 @@
-using System.Linq;
-using Umbraco.Core.Persistence.Dtos;
-
-namespace Umbraco.Core.Migrations.Upgrade.V_7_9_0
-{
- internal class AddUmbracoConsentTable : MigrationBase
- {
- public AddUmbracoConsentTable(IMigrationContext context)
- : base(context)
- { }
-
- public override void Migrate()
- {
- var tables = SqlSyntax.GetTablesInSchema(Context.Database).ToArray();
-
- if (tables.InvariantContains(Constants.DatabaseSchema.Tables.Consent))
- return;
-
- Create.Table().Do();
- }
- }
-}
diff --git a/src/Umbraco.Core/Migrations/Upgrade/V_7_9_0/CreateSensitiveDataUserGroup.cs b/src/Umbraco.Core/Migrations/Upgrade/V_7_9_0/CreateSensitiveDataUserGroup.cs
deleted file mode 100644
index ce656aa0c1..0000000000
--- a/src/Umbraco.Core/Migrations/Upgrade/V_7_9_0/CreateSensitiveDataUserGroup.cs
+++ /dev/null
@@ -1,27 +0,0 @@
-using System;
-using Umbraco.Core.Persistence;
-using Umbraco.Core.Persistence.Dtos;
-
-namespace Umbraco.Core.Migrations.Upgrade.V_7_9_0
-{
- internal class CreateSensitiveDataUserGroup : MigrationBase
- {
- public CreateSensitiveDataUserGroup(IMigrationContext context)
- : base(context)
- { }
-
- public override void Migrate()
- {
- var sql = Sql()
- .SelectCount()
- .From()
- .Where(x => x.Alias == Constants.Security.SensitiveDataGroupAlias);
-
- var exists = Database.ExecuteScalar(sql) > 0;
- if (exists) return;
-
- var groupId = Database.Insert(Constants.DatabaseSchema.Tables.UserGroup, "id", new UserGroupDto { StartMediaId = -1, StartContentId = -1, Alias = Constants.Security.SensitiveDataGroupAlias, Name = "Sensitive data", DefaultPermissions = "", CreateDate = DateTime.Now, UpdateDate = DateTime.Now, Icon = "icon-lock" });
- Database.Insert(new User2UserGroupDto { UserGroupId = Convert.ToInt32(groupId), UserId = Constants.Security.SuperUserId }); // add super to sensitive data
- }
- }
-}
diff --git a/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/AddContentNuTable.cs b/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/AddContentNuTable.cs
index efa54a0f59..5342755ebf 100644
--- a/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/AddContentNuTable.cs
+++ b/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/AddContentNuTable.cs
@@ -1,6 +1,7 @@
using System.Data;
using System.Linq;
using Umbraco.Core.Persistence.DatabaseAnnotations;
+using Umbraco.Core.Persistence.Dtos;
namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0
{
@@ -12,31 +13,10 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0
public override void Migrate()
{
- var tables = SqlSyntax.GetTablesInSchema(Context.Database).ToArray();
+ var tables = SqlSyntax.GetTablesInSchema(Context.Database);
if (tables.InvariantContains("cmsContentNu")) return;
- var textType = SqlSyntax.GetSpecialDbType(SpecialDbTypes.NTEXT);
-
- Create.Table("cmsContentNu")
- .WithColumn("nodeId").AsInt32().NotNullable()
- .WithColumn("published").AsBoolean().NotNullable()
- .WithColumn("data").AsCustom(textType).NotNullable()
- .WithColumn("rv").AsInt64().NotNullable().WithDefaultValue(0)
- .Do();
-
- Create.PrimaryKey("PK_cmsContentNu")
- .OnTable("cmsContentNu")
- .Columns(new[] { "nodeId", "published" })
- .Do();
-
- Create.ForeignKey("FK_cmsContentNu_umbracoNode_id")
- .FromTable("cmsContentNu")
- .ForeignColumn("nodeId")
- .ToTable("umbracoNode")
- .PrimaryColumn("id")
- .OnDelete(Rule.Cascade)
- .OnUpdate(Rule.None)
- .Do();
+ Create.Table(true).Do();
}
}
}
diff --git a/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/AddLockTable.cs b/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/AddLockTable.cs
deleted file mode 100644
index aa14bc81c8..0000000000
--- a/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/AddLockTable.cs
+++ /dev/null
@@ -1,24 +0,0 @@
-using System.Linq;
-
-namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0
-{
- public class AddLockTable : MigrationBase
- {
- public AddLockTable(IMigrationContext context)
- : base(context)
- { }
-
- public override void Migrate()
- {
- var tables = SqlSyntax.GetTablesInSchema(Context.Database).ToArray();
- if (tables.InvariantContains("umbracoLock") == false)
- {
- Create.Table("umbracoLock")
- .WithColumn("id").AsInt32().PrimaryKey("PK_umbracoLock")
- .WithColumn("value").AsInt32().NotNullable()
- .WithColumn("name").AsString(64).NotNullable()
- .Do();
- }
- }
- }
-}
diff --git a/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/AddUserLoginDtoDateIndex.cs b/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/AddUserLoginDtoDateIndex.cs
deleted file mode 100644
index 0ccc2d93ff..0000000000
--- a/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/AddUserLoginDtoDateIndex.cs
+++ /dev/null
@@ -1,22 +0,0 @@
-using Umbraco.Core.Persistence.Dtos;
-
-namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0
-{
- public class AddUserLoginDtoDateIndex : MigrationBase
- {
- public AddUserLoginDtoDateIndex(IMigrationContext context)
- : base(context)
- { }
-
- public override void Migrate()
- {
- if (!IndexExists("IX_umbracoUserLogin_lastValidatedUtc"))
- Create.Index("IX_umbracoUserLogin_lastValidatedUtc")
- .OnTable(UserLoginDto.TableName)
- .OnColumn("lastValidatedUtc")
- .Ascending()
- .WithOptions().NonClustered()
- .Do();
- }
- }
-}
diff --git a/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/AddVariationTables2.cs b/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/AddVariationTables2.cs
index c6cad2eac1..4044b5a173 100644
--- a/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/AddVariationTables2.cs
+++ b/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/AddVariationTables2.cs
@@ -11,8 +11,8 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0
public override void Migrate()
{
- Create.Table().Do();
- Create.Table().Do();
+ Create.Table(true).Do();
+ Create.Table(true).Do();
}
}
}
diff --git a/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/DataTypeMigration.cs b/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/DataTypeMigration.cs
index d7180385f0..438b02385b 100644
--- a/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/DataTypeMigration.cs
+++ b/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/DataTypeMigration.cs
@@ -1,28 +1,33 @@
using System;
-using System.Collections.Generic;
using System.Linq;
-using System.Reflection;
using Newtonsoft.Json;
-using NPoco;
-using Umbraco.Core.Migrations.Install;
+using Umbraco.Core.Composing;
+using Umbraco.Core.Logging;
+using Umbraco.Core.Migrations.Upgrade.V_8_0_0.DataTypes;
using Umbraco.Core.Persistence;
using Umbraco.Core.Persistence.Dtos;
using Umbraco.Core.Persistence.Querying;
+using Umbraco.Core.PropertyEditors;
namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0
{
public class DataTypeMigration : MigrationBase
{
- public DataTypeMigration(IMigrationContext context)
+ private readonly PreValueMigratorCollection _preValueMigrators;
+ private readonly PropertyEditorCollection _propertyEditors;
+ private readonly ILogger _logger;
+
+ public DataTypeMigration(IMigrationContext context, PreValueMigratorCollection preValueMigrators, PropertyEditorCollection propertyEditors, ILogger logger)
: base(context)
- { }
+ {
+ _preValueMigrators = preValueMigrators;
+ _propertyEditors = propertyEditors;
+ _logger = logger;
+ }
public override void Migrate()
{
- // delete *all* keys and indexes - because of FKs
- Delete.KeysAndIndexes().Do();
-
// drop and create columns
Delete.Column("pk").FromTable("cmsDataType").Do();
@@ -31,21 +36,17 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0
// create column
AddColumn(Constants.DatabaseSchema.Tables.DataType, "config");
- Execute.Sql(Sql().Update(u => u.Set(x => x.Configuration, string.Empty)).SQL).Do();
-
- // re-create *all* keys and indexes
- foreach (var x in DatabaseSchemaCreator.OrderedTables)
- Create.KeysAndIndexes(x).Do();
+ Execute.Sql(Sql().Update(u => u.Set(x => x.Configuration, string.Empty))).Do();
// renames
Execute.Sql(Sql()
.Update(u => u.Set(x => x.EditorAlias, "Umbraco.ColorPicker"))
- .Where(x => x.EditorAlias == "Umbraco.ColorPickerAlias").SQL).Do();
+ .Where(x => x.EditorAlias == "Umbraco.ColorPickerAlias")).Do();
// from preValues to configuration...
var sql = Sql()
.Select()
- .AndSelect(x => x.Alias, x => x.SortOrder, x => x.Value)
+ .AndSelect(x => x.Id, x => x.Alias, x => x.SortOrder, x => x.Value)
.From()
.InnerJoin().On((left, right) => left.NodeId == right.NodeId)
.OrderBy(x => x.NodeId)
@@ -60,43 +61,45 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0
.From()
.Where(x => x.NodeId == group.Key)).First();
- var aliases = group.Select(x => x.Alias).Distinct().ToArray();
- if (aliases.Length == 1 && string.IsNullOrWhiteSpace(aliases[0]))
+ // migrate the preValues to configuration
+ var migrator = _preValueMigrators.GetMigrator(dataType.EditorAlias) ?? new DefaultPreValueMigrator();
+ var config = migrator.GetConfiguration(dataType.NodeId, dataType.EditorAlias, group.ToDictionary(x => x.Alias, x => x));
+ var json = JsonConvert.SerializeObject(config);
+
+ // validate - and kill the migration if it fails
+ var newAlias = migrator.GetNewAlias(dataType.EditorAlias);
+ if (newAlias == null)
{
- // array-based prevalues
- var values = new Dictionary { ["values"] = group.OrderBy(x => x.SortOrder).Select(x => x.Value).ToArray() };
- dataType.Configuration = JsonConvert.SerializeObject(values);
+ _logger.Warn("Skipping validation of configuration for data type {NodeId} : {EditorAlias}."
+ + " Please ensure that the configuration is valid. The site may fail to start and / or load data types and run.",
+ dataType.NodeId, dataType.EditorAlias);
+ }
+ else if (!_propertyEditors.TryGet(newAlias, out var propertyEditor))
+ {
+ _logger.Warn("Skipping validation of configuration for data type {NodeId} : {NewEditorAlias} (was: {EditorAlias})"
+ + " because no property editor with that alias was found."
+ + " Please ensure that the configuration is valid. The site may fail to start and / or load data types and run.",
+ dataType.NodeId, newAlias, dataType.EditorAlias);
}
else
{
- // assuming we don't want to fall back to array
- if (aliases.Length != group.Count() || aliases.Any(string.IsNullOrWhiteSpace))
- throw new InvalidOperationException($"Cannot migrate datatype w/ id={dataType.NodeId} preValues: duplicate or null/empty alias.");
-
- // dictionary-base prevalues
- var values = group.ToDictionary(x => x.Alias, x => x.Value);
- dataType.Configuration = JsonConvert.SerializeObject(values);
+ var configEditor = propertyEditor.GetConfigurationEditor();
+ try
+ {
+ var _ = configEditor.FromDatabase(json);
+ }
+ catch (Exception e)
+ {
+ _logger.Warn(e, "Failed to validate configuration for data type {NodeId} : {NewEditorAlias} (was: {EditorAlias})."
+ + " Please fix the configuration and ensure it is valid. The site may fail to start and / or load data types and run.",
+ dataType.NodeId, newAlias, dataType.EditorAlias);
+ }
}
+ // update
+ dataType.Configuration = JsonConvert.SerializeObject(config);
Database.Update(dataType);
}
}
-
- [TableName("cmsDataTypePreValues")]
- [ExplicitColumns]
- public class PreValueDto
- {
- [Column("datatypeNodeId")]
- public int NodeId { get; set; }
-
- [Column("alias")]
- public string Alias { get; set; }
-
- [Column("sortorder")]
- public int SortOrder { get; set; }
-
- [Column("value")]
- public string Value { get; set; }
- }
}
}
diff --git a/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/DataTypes/ContentPickerPreValueMigrator.cs b/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/DataTypes/ContentPickerPreValueMigrator.cs
new file mode 100644
index 0000000000..2e341ad091
--- /dev/null
+++ b/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/DataTypes/ContentPickerPreValueMigrator.cs
@@ -0,0 +1,20 @@
+namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0.DataTypes
+{
+ class ContentPickerPreValueMigrator : DefaultPreValueMigrator
+ {
+ public override bool CanMigrate(string editorAlias)
+ => editorAlias == "Umbraco.ContentPicker2";
+
+ public override string GetNewAlias(string editorAlias)
+ => null;
+
+ protected override object GetPreValueValue(PreValueDto preValue)
+ {
+ if (preValue.Alias == "showOpenButton" ||
+ preValue.Alias == "ignoreUserStartNodes")
+ return preValue.Value == "1";
+
+ return base.GetPreValueValue(preValue);
+ }
+ }
+}
diff --git a/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/DataTypes/DecimalPreValueMigrator.cs b/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/DataTypes/DecimalPreValueMigrator.cs
new file mode 100644
index 0000000000..8dc0f1dcd5
--- /dev/null
+++ b/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/DataTypes/DecimalPreValueMigrator.cs
@@ -0,0 +1,20 @@
+using Newtonsoft.Json;
+
+namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0.DataTypes
+{
+ class DecimalPreValueMigrator : DefaultPreValueMigrator
+ {
+ public override bool CanMigrate(string editorAlias)
+ => editorAlias == "Umbraco.Decimal";
+
+ protected override object GetPreValueValue(PreValueDto preValue)
+ {
+ if (preValue.Alias == "min" ||
+ preValue.Alias == "step" ||
+ preValue.Alias == "max")
+ return decimal.TryParse(preValue.Value, out var d) ? (decimal?) d : null;
+
+ return preValue.Value.DetectIsJson() ? JsonConvert.DeserializeObject(preValue.Value) : preValue.Value;
+ }
+ }
+}
diff --git a/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/DataTypes/DefaultPreValueMigrator.cs b/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/DataTypes/DefaultPreValueMigrator.cs
new file mode 100644
index 0000000000..7112679de2
--- /dev/null
+++ b/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/DataTypes/DefaultPreValueMigrator.cs
@@ -0,0 +1,42 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Newtonsoft.Json;
+
+namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0.DataTypes
+{
+ class DefaultPreValueMigrator : IPreValueMigrator
+ {
+ public virtual bool CanMigrate(string editorAlias)
+ => true;
+
+ public virtual string GetNewAlias(string editorAlias)
+ => editorAlias;
+
+ public object GetConfiguration(int dataTypeId, string editorAlias, Dictionary preValues)
+ {
+ var preValuesA = preValues.Values.ToList();
+ var aliases = preValuesA.Select(x => x.Alias).Distinct().ToArray();
+ if (aliases.Length == 1 && string.IsNullOrWhiteSpace(aliases[0]))
+ {
+ // array-based prevalues
+ return new Dictionary { ["values"] = preValuesA.OrderBy(x => x.SortOrder).Select(x => x.Value).ToArray() };
+ }
+
+ // assuming we don't want to fall back to array
+ if (aliases.Length != preValuesA.Count || aliases.Any(string.IsNullOrWhiteSpace))
+ throw new InvalidOperationException($"Cannot migrate datatype w/ id={dataTypeId} preValues: duplicate or null/empty alias.");
+
+ // dictionary-base prevalues
+ return GetPreValues(preValuesA).ToDictionary(x => x.Alias, GetPreValueValue);
+ }
+
+ protected virtual IEnumerable GetPreValues(IEnumerable preValues)
+ => preValues;
+
+ protected virtual object GetPreValueValue(PreValueDto preValue)
+ {
+ return preValue.Value.DetectIsJson() ? JsonConvert.DeserializeObject(preValue.Value) : preValue.Value;
+ }
+ }
+}
diff --git a/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/DataTypes/IPreValueMigrator.cs b/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/DataTypes/IPreValueMigrator.cs
new file mode 100644
index 0000000000..01e0ed3875
--- /dev/null
+++ b/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/DataTypes/IPreValueMigrator.cs
@@ -0,0 +1,36 @@
+using System.Collections.Generic;
+
+namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0.DataTypes
+{
+ ///
+ /// Defines a service migrating preValues.
+ ///
+ public interface IPreValueMigrator
+ {
+ ///
+ /// Determines whether this migrator can migrate a data type.
+ ///
+ /// The data type editor alias.
+ bool CanMigrate(string editorAlias);
+
+ ///
+ /// Gets the v8 codebase data type editor alias.
+ ///
+ /// The original v7 codebase editor alias.
+ ///
+ /// This is used to validate that the migrated configuration can be parsed
+ /// by the new property editor. Return null to bypass this validation,
+ /// when for instance we know it will fail, and another, later migration will
+ /// deal with it.
+ ///
+ string GetNewAlias(string editorAlias);
+
+ ///
+ /// Gets the configuration object corresponding to preValue.
+ ///
+ /// The data type identifier.
+ /// The data type editor alias.
+ /// PreValues.
+ object GetConfiguration(int dataTypeId, string editorAlias, Dictionary preValues);
+ }
+}
diff --git a/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/DataTypes/ListViewPreValueMigrator.cs b/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/DataTypes/ListViewPreValueMigrator.cs
new file mode 100644
index 0000000000..d8daf9b5e6
--- /dev/null
+++ b/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/DataTypes/ListViewPreValueMigrator.cs
@@ -0,0 +1,25 @@
+using System.Collections.Generic;
+using System.Linq;
+using Newtonsoft.Json;
+
+namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0.DataTypes
+{
+ class ListViewPreValueMigrator : DefaultPreValueMigrator
+ {
+ public override bool CanMigrate(string editorAlias)
+ => editorAlias == "Umbraco.ListView";
+
+ protected override IEnumerable GetPreValues(IEnumerable preValues)
+ {
+ return preValues.Where(preValue => preValue.Alias != "displayAtTabNumber");
+ }
+
+ protected override object GetPreValueValue(PreValueDto preValue)
+ {
+ if (preValue.Alias == "pageSize")
+ return int.TryParse(preValue.Value, out var i) ? (int?)i : null;
+
+ return preValue.Value.DetectIsJson() ? JsonConvert.DeserializeObject(preValue.Value) : preValue.Value;
+ }
+ }
+}
diff --git a/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/DataTypes/MediaPickerPreValueMigrator.cs b/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/DataTypes/MediaPickerPreValueMigrator.cs
new file mode 100644
index 0000000000..a46b1eefb7
--- /dev/null
+++ b/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/DataTypes/MediaPickerPreValueMigrator.cs
@@ -0,0 +1,37 @@
+using System.Linq;
+
+namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0.DataTypes
+{
+ class MediaPickerPreValueMigrator : DefaultPreValueMigrator //PreValueMigratorBase
+ {
+ private readonly string[] _editors =
+ {
+ "Umbraco.MediaPicker2",
+ "Umbraco.MediaPicker"
+ };
+
+ public override bool CanMigrate(string editorAlias)
+ => _editors.Contains(editorAlias);
+
+ public override string GetNewAlias(string editorAlias)
+ => "Umbraco.MediaPicker";
+
+ // you wish - but MediaPickerConfiguration lives in Umbraco.Web
+ /*
+ public override object GetConfiguration(int dataTypeId, string editorAlias, Dictionary preValues)
+ {
+ return new MediaPickerConfiguration { ... };
+ }
+ */
+
+ protected override object GetPreValueValue(PreValueDto preValue)
+ {
+ if (preValue.Alias == "multiPicker" ||
+ preValue.Alias == "onlyImages" ||
+ preValue.Alias == "disableFolderSelect")
+ return preValue.Value == "1";
+
+ return base.GetPreValueValue(preValue);
+ }
+ }
+}
diff --git a/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/DataTypes/NestedContentPreValueMigrator.cs b/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/DataTypes/NestedContentPreValueMigrator.cs
new file mode 100644
index 0000000000..22c87f8503
--- /dev/null
+++ b/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/DataTypes/NestedContentPreValueMigrator.cs
@@ -0,0 +1,33 @@
+using System.Collections.Generic;
+using Newtonsoft.Json;
+
+namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0.DataTypes
+{
+ class NestedContentPreValueMigrator : DefaultPreValueMigrator //PreValueMigratorBase
+ {
+ public override bool CanMigrate(string editorAlias)
+ => editorAlias == "Umbraco.NestedContent";
+
+ // you wish - but NestedContentConfiguration lives in Umbraco.Web
+ /*
+ public override object GetConfiguration(int dataTypeId, string editorAlias, Dictionary preValues)
+ {
+ return new NestedContentConfiguration { ... };
+ }
+ */
+
+ protected override object GetPreValueValue(PreValueDto preValue)
+ {
+ if (preValue.Alias == "confirmDeletes" ||
+ preValue.Alias == "showIcons" ||
+ preValue.Alias == "hideLabel")
+ return preValue.Value == "1";
+
+ if (preValue.Alias == "minItems" ||
+ preValue.Alias == "maxItems")
+ return int.TryParse(preValue.Value, out var i) ? (int?)i : null;
+
+ return preValue.Value.DetectIsJson() ? JsonConvert.DeserializeObject(preValue.Value) : preValue.Value;
+ }
+ }
+}
diff --git a/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/DataTypes/PreValueDto.cs b/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/DataTypes/PreValueDto.cs
new file mode 100644
index 0000000000..b6ab622510
--- /dev/null
+++ b/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/DataTypes/PreValueDto.cs
@@ -0,0 +1,24 @@
+using NPoco;
+
+namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0.DataTypes
+{
+ [TableName("cmsDataTypePreValues")]
+ [ExplicitColumns]
+ public class PreValueDto
+ {
+ [Column("id")]
+ public int Id { get; set; }
+
+ [Column("datatypeNodeId")]
+ public int NodeId { get; set; }
+
+ [Column("alias")]
+ public string Alias { get; set; }
+
+ [Column("sortorder")]
+ public int SortOrder { get; set; }
+
+ [Column("value")]
+ public string Value { get; set; }
+ }
+}
diff --git a/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/DataTypes/PreValueMigratorBase.cs b/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/DataTypes/PreValueMigratorBase.cs
new file mode 100644
index 0000000000..62e2b2347b
--- /dev/null
+++ b/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/DataTypes/PreValueMigratorBase.cs
@@ -0,0 +1,20 @@
+using System.Collections.Generic;
+
+namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0.DataTypes
+{
+ public abstract class PreValueMigratorBase : IPreValueMigrator
+ {
+ public abstract bool CanMigrate(string editorAlias);
+
+ public virtual string GetNewAlias(string editorAlias)
+ => editorAlias;
+
+ public abstract object GetConfiguration(int dataTypeId, string editorAlias, Dictionary preValues);
+
+ protected bool GetBoolValue(Dictionary preValues, string alias, bool defaultValue = false)
+ => preValues.TryGetValue(alias, out var preValue) ? preValue.Value == "1" : defaultValue;
+
+ protected decimal GetDecimalValue(Dictionary preValues, string alias, decimal defaultValue = 0)
+ => preValues.TryGetValue(alias, out var preValue) && decimal.TryParse(preValue.Value, out var value) ? value : defaultValue;
+ }
+}
diff --git a/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/DataTypes/PreValueMigratorCollection.cs b/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/DataTypes/PreValueMigratorCollection.cs
new file mode 100644
index 0000000000..06f5d45deb
--- /dev/null
+++ b/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/DataTypes/PreValueMigratorCollection.cs
@@ -0,0 +1,26 @@
+using System.Collections.Generic;
+using System.Linq;
+using Umbraco.Core.Composing;
+using Umbraco.Core.Logging;
+
+namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0.DataTypes
+{
+ public class PreValueMigratorCollection : BuilderCollectionBase
+ {
+ private readonly ILogger _logger;
+
+ public PreValueMigratorCollection(IEnumerable items, ILogger logger)
+ : base(items)
+ {
+ _logger = logger;
+ _logger.Debug(GetType(), "Migrators: " + string.Join(", ", items.Select(x => x.GetType().Name)));
+ }
+
+ public IPreValueMigrator GetMigrator(string editorAlias)
+ {
+ var migrator = this.FirstOrDefault(x => x.CanMigrate(editorAlias));
+ _logger.Debug(GetType(), "Getting migrator for \"{EditorAlias}\" = {MigratorType}", editorAlias, migrator == null ? "" : migrator.GetType().Name);
+ return migrator;
+ }
+ }
+}
diff --git a/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/DataTypes/PreValueMigratorCollectionBuilder.cs b/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/DataTypes/PreValueMigratorCollectionBuilder.cs
new file mode 100644
index 0000000000..3859e63767
--- /dev/null
+++ b/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/DataTypes/PreValueMigratorCollectionBuilder.cs
@@ -0,0 +1,9 @@
+using Umbraco.Core.Composing;
+
+namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0.DataTypes
+{
+ public class PreValueMigratorCollectionBuilder : OrderedCollectionBuilderBase
+ {
+ protected override PreValueMigratorCollectionBuilder This => this;
+ }
+}
diff --git a/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/DataTypes/PreValueMigratorComposer.cs b/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/DataTypes/PreValueMigratorComposer.cs
new file mode 100644
index 0000000000..9e2dec9b70
--- /dev/null
+++ b/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/DataTypes/PreValueMigratorComposer.cs
@@ -0,0 +1,25 @@
+using Umbraco.Core.Composing;
+
+namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0.DataTypes
+{
+ [RuntimeLevel(MinLevel = RuntimeLevel.Upgrade, MaxLevel = RuntimeLevel.Upgrade)] // only on upgrades
+ public class PreValueMigratorComposer : ICoreComposer
+ {
+ public void Compose(Composition composition)
+ {
+ // do NOT add DefaultPreValueMigrator to this list!
+ // it will be automatically used if nothing matches
+
+ composition.WithCollectionBuilder()
+ .Append()
+ .Append()
+ .Append()
+ .Append()
+ .Append()
+ .Append()
+ .Append()
+ .Append()
+ .Append();
+ }
+ }
+}
diff --git a/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/DataTypes/RenamingPreValueMigrator.cs b/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/DataTypes/RenamingPreValueMigrator.cs
new file mode 100644
index 0000000000..c04e7c8fda
--- /dev/null
+++ b/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/DataTypes/RenamingPreValueMigrator.cs
@@ -0,0 +1,27 @@
+using System;
+using System.Linq;
+
+namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0.DataTypes
+{
+ class RenamingPreValueMigrator : DefaultPreValueMigrator
+ {
+ private readonly string[] _editors =
+ {
+ "Umbraco.NoEdit"
+ };
+
+ public override bool CanMigrate(string editorAlias)
+ => _editors.Contains(editorAlias);
+
+ public override string GetNewAlias(string editorAlias)
+ {
+ switch (editorAlias)
+ {
+ case "Umbraco.NoEdit":
+ return Constants.PropertyEditors.Aliases.Label;
+ default:
+ throw new Exception("panic");
+ }
+ }
+ }
+}
diff --git a/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/DataTypes/RichTextPreValueMigrator.cs b/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/DataTypes/RichTextPreValueMigrator.cs
new file mode 100644
index 0000000000..3670c52c64
--- /dev/null
+++ b/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/DataTypes/RichTextPreValueMigrator.cs
@@ -0,0 +1,21 @@
+using Newtonsoft.Json;
+
+namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0.DataTypes
+{
+ class RichTextPreValueMigrator : DefaultPreValueMigrator
+ {
+ public override bool CanMigrate(string editorAlias)
+ => editorAlias == "Umbraco.TinyMCEv3";
+
+ public override string GetNewAlias(string editorAlias)
+ => Constants.PropertyEditors.Aliases.TinyMce;
+
+ protected override object GetPreValueValue(PreValueDto preValue)
+ {
+ if (preValue.Alias == "hideLabel")
+ return preValue.Value == "1";
+
+ return preValue.Value.DetectIsJson() ? JsonConvert.DeserializeObject(preValue.Value) : preValue.Value;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/DataTypes/UmbracoSliderPreValueMigrator.cs b/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/DataTypes/UmbracoSliderPreValueMigrator.cs
new file mode 100644
index 0000000000..dc6de5e493
--- /dev/null
+++ b/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/DataTypes/UmbracoSliderPreValueMigrator.cs
@@ -0,0 +1,24 @@
+using System.Collections.Generic;
+using Umbraco.Core.PropertyEditors;
+
+namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0.DataTypes
+{
+ class UmbracoSliderPreValueMigrator : PreValueMigratorBase
+ {
+ public override bool CanMigrate(string editorAlias)
+ => editorAlias == "Umbraco.Slider";
+
+ public override object GetConfiguration(int dataTypeId, string editorAlias, Dictionary preValues)
+ {
+ return new SliderConfiguration
+ {
+ EnableRange = GetBoolValue(preValues, "enableRange"),
+ InitialValue = GetDecimalValue(preValues, "initVal1"),
+ InitialValue2 = GetDecimalValue(preValues, "initVal2"),
+ MaximumValue = GetDecimalValue(preValues, "maxVal"),
+ MinimumValue = GetDecimalValue(preValues, "minVal"),
+ StepIncrements = GetDecimalValue(preValues, "step")
+ };
+ }
+ }
+}
diff --git a/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/DataTypes/ValueListPreValueMigrator.cs b/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/DataTypes/ValueListPreValueMigrator.cs
new file mode 100644
index 0000000000..7249ebd6ec
--- /dev/null
+++ b/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/DataTypes/ValueListPreValueMigrator.cs
@@ -0,0 +1,32 @@
+using System.Collections.Generic;
+using System.Linq;
+using Umbraco.Core.PropertyEditors;
+
+namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0.DataTypes
+{
+ class ValueListPreValueMigrator : IPreValueMigrator
+ {
+ private readonly string[] _editors =
+ {
+ "Umbraco.RadioButtonList",
+ "Umbraco.DropDown",
+ "Umbraco.DropdownlistPublishingKeys",
+ "Umbraco.DropDownMultiple",
+ "Umbraco.DropdownlistMultiplePublishKeys"
+ };
+
+ public bool CanMigrate(string editorAlias)
+ => _editors.Contains(editorAlias);
+
+ public virtual string GetNewAlias(string editorAlias)
+ => null;
+
+ public object GetConfiguration(int dataTypeId, string editorAlias, Dictionary preValues)
+ {
+ var config = new ValueListConfiguration();
+ foreach (var preValue in preValues.Values)
+ config.Items.Add(new ValueListConfiguration.ValueListItem { Id = preValue.Id, Value = preValue.Value });
+ return config;
+ }
+ }
+}
diff --git a/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/DropDownPropertyEditorsMigration.cs b/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/DropDownPropertyEditorsMigration.cs
index ed2990aff7..d30719231a 100644
--- a/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/DropDownPropertyEditorsMigration.cs
+++ b/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/DropDownPropertyEditorsMigration.cs
@@ -1,39 +1,35 @@
using System;
using System.Collections.Generic;
using System.Linq;
-using Umbraco.Core.Cache;
using Umbraco.Core.Persistence;
using Umbraco.Core.Persistence.Dtos;
using Umbraco.Core.PropertyEditors;
using Umbraco.Core.Logging;
+using Umbraco.Core.Migrations.PostMigrations;
using Umbraco.Core.Models;
-using Umbraco.Core.Sync;
namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0
{
- public class DropDownPropertyEditorsMigration : MigrationBase
+ public class DropDownPropertyEditorsMigration : PropertyEditorsMigrationBase
{
- private readonly CacheRefresherCollection _cacheRefreshers;
- private readonly IServerMessenger _serverMessenger;
-
- public DropDownPropertyEditorsMigration(IMigrationContext context, CacheRefresherCollection cacheRefreshers, IServerMessenger serverMessenger)
+ public DropDownPropertyEditorsMigration(IMigrationContext context)
: base(context)
- {
- _cacheRefreshers = cacheRefreshers;
- _serverMessenger = serverMessenger;
- }
-
- // dummy editor for deserialization
- private class ValueListConfigurationEditor : ConfigurationEditor
{ }
public override void Migrate()
{
- //need to convert the old drop down data types to use the new one
- var dataTypes = Database.Fetch(Sql()
- .Select()
- .From()
- .Where(x => x.EditorAlias.Contains(".DropDown")));
+ var refreshCache = Migrate(GetDataTypes(".DropDown", false));
+
+ // if some data types have been updated directly in the database (editing DataTypeDto and/or PropertyDataDto),
+ // bypassing the services, then we need to rebuild the cache entirely, including the umbracoContentNu table
+ if (refreshCache)
+ Context.AddPostMigration();
+ }
+
+ private bool Migrate(IEnumerable dataTypes)
+ {
+ var refreshCache = false;
+ ConfigurationEditor configurationEditor = null;
foreach (var dataType in dataTypes)
{
@@ -42,14 +38,16 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0
if (!dataType.Configuration.IsNullOrWhiteSpace())
{
// parse configuration, and update everything accordingly
+ if (configurationEditor == null)
+ configurationEditor = new ValueListConfigurationEditor();
try
{
- config = (ValueListConfiguration) new ValueListConfigurationEditor().FromDatabase(dataType.Configuration);
+ config = (ValueListConfiguration) configurationEditor.FromDatabase(dataType.Configuration);
}
catch (Exception ex)
{
Logger.Error(
- ex, "Invalid drop down configuration detected: \"{Configuration}\", cannot convert editor, values will be cleared",
+ ex, "Invalid configuration: \"{Configuration}\", cannot convert editor.",
dataType.Configuration);
// reset
@@ -65,7 +63,7 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0
.Where(x => x.DataTypeId == dataType.NodeId));
// update dtos
- var updatedDtos = propertyDataDtos.Where(x => UpdatePropertyDataDto(x, config));
+ var updatedDtos = propertyDataDtos.Where(x => UpdatePropertyDataDto(x, config, true));
// persist changes
foreach (var propertyDataDto in updatedDtos)
@@ -77,7 +75,6 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0
config = new ValueListConfiguration();
}
- var requiresCacheRebuild = false;
switch (dataType.EditorAlias)
{
case string ea when ea.InvariantEquals("Umbraco.DropDown"):
@@ -85,29 +82,25 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0
break;
case string ea when ea.InvariantEquals("Umbraco.DropdownlistPublishingKeys"):
UpdateDataType(dataType, config, false);
- requiresCacheRebuild = true;
break;
case string ea when ea.InvariantEquals("Umbraco.DropDownMultiple"):
UpdateDataType(dataType, config, true);
break;
case string ea when ea.InvariantEquals("Umbraco.DropdownlistMultiplePublishKeys"):
UpdateDataType(dataType, config, true);
- requiresCacheRebuild = true;
break;
}
- if (requiresCacheRebuild)
- {
- var dataTypeCacheRefresher = _cacheRefreshers[Guid.Parse("35B16C25-A17E-45D7-BC8F-EDAB1DCC28D2")];
- _serverMessenger.PerformRefreshAll(dataTypeCacheRefresher);
- }
+ refreshCache = true;
}
+
+ return refreshCache;
}
private void UpdateDataType(DataTypeDto dataType, ValueListConfiguration config, bool isMultiple)
{
- dataType.EditorAlias = Constants.PropertyEditors.Aliases.DropDownListFlexible;
dataType.DbType = ValueStorageType.Nvarchar.ToString();
+ dataType.EditorAlias = Constants.PropertyEditors.Aliases.DropDownListFlexible;
var flexConfig = new DropDownFlexibleConfiguration
{
@@ -118,68 +111,5 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0
Database.Update(dataType);
}
-
- private bool UpdatePropertyDataDto(PropertyDataDto propData, ValueListConfiguration config)
- {
- //Get the INT ids stored for this property/drop down
- int[] ids = null;
- if (!propData.VarcharValue.IsNullOrWhiteSpace())
- {
- ids = ConvertStringValues(propData.VarcharValue);
- }
- else if (!propData.TextValue.IsNullOrWhiteSpace())
- {
- ids = ConvertStringValues(propData.TextValue);
- }
- else if (propData.IntegerValue.HasValue)
- {
- ids = new[] { propData.IntegerValue.Value };
- }
-
- //if there are INT ids, convert them to values based on the configured pre-values
- if (ids != null && ids.Length > 0)
- {
- //map the ids to values
- var vals = new List();
- var canConvert = true;
- foreach (var id in ids)
- {
- var val = config.Items.FirstOrDefault(x => x.Id == id);
- if (val != null)
- vals.Add(val.Value);
- else
- {
- Logger.Warn(
- "Could not find associated data type configuration for stored Id {DataTypeId}", id);
- canConvert = false;
- }
- }
- if (canConvert)
- {
- propData.VarcharValue = string.Join(",", vals);
- propData.TextValue = null;
- propData.IntegerValue = null;
- return true;
- }
- }
-
- return false;
- }
-
- private int[] ConvertStringValues(string val)
- {
- var splitVals = val.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
-
- var intVals = splitVals
- .Select(x => int.TryParse(x, out var i) ? i : int.MinValue)
- .Where(x => x != int.MinValue)
- .ToArray();
-
- //only return if the number of values are the same (i.e. All INTs)
- if (splitVals.Length == intVals.Length)
- return intVals;
-
- return null;
- }
}
}
diff --git a/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/DropMigrationsTable.cs b/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/DropMigrationsTable.cs
index 26668361bd..def6a93400 100644
--- a/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/DropMigrationsTable.cs
+++ b/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/DropMigrationsTable.cs
@@ -8,7 +8,8 @@
public override void Migrate()
{
- Delete.Table("umbracoMigration").Do();
+ if (TableExists("umbracoMigration"))
+ Delete.Table("umbracoMigration").Do();
}
}
}
diff --git a/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/DropPreValueTable.cs b/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/DropPreValueTable.cs
index fa6e47fac7..918510d13c 100644
--- a/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/DropPreValueTable.cs
+++ b/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/DropPreValueTable.cs
@@ -3,8 +3,7 @@
public class DropPreValueTable : MigrationBase
{
public DropPreValueTable(IMigrationContext context) : base(context)
- {
- }
+ { }
public override void Migrate()
{
diff --git a/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/FixLanguageIsoCodeLength.cs b/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/FixLanguageIsoCodeLength.cs
new file mode 100644
index 0000000000..8de06c9a6f
--- /dev/null
+++ b/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/FixLanguageIsoCodeLength.cs
@@ -0,0 +1,21 @@
+namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0
+{
+ public class FixLanguageIsoCodeLength : MigrationBase
+ {
+ public FixLanguageIsoCodeLength(IMigrationContext context)
+ : base(context)
+ { }
+
+ public override void Migrate()
+ {
+ // there is some confusion here when upgrading from v7
+ // it should be 14 already but that's not always the case
+
+ Alter.Table("umbracoLanguage")
+ .AlterColumn("languageISOCode")
+ .AsString(14)
+ .Nullable()
+ .Do();
+ }
+ }
+}
diff --git a/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/FixLockTablePrimaryKey.cs b/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/FixLockTablePrimaryKey.cs
deleted file mode 100644
index fbb233927b..0000000000
--- a/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/FixLockTablePrimaryKey.cs
+++ /dev/null
@@ -1,23 +0,0 @@
-using System.Linq;
-
-namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0
-{
- public class FixLockTablePrimaryKey : MigrationBase
- {
- public FixLockTablePrimaryKey(IMigrationContext context)
- : base(context)
- { }
-
- public override void Migrate()
- {
- // at some point, the KeyValueService dropped the PK and failed to re-create it,
- // so the PK is gone - make sure we have one, and create if needed
-
- var constraints = SqlSyntax.GetConstraintsPerTable(Database);
- var exists = constraints.Any(x => x.Item2 == "PK_umbracoLock");
-
- if (!exists)
- Create.PrimaryKey("PK_umbracoLock").OnTable(Constants.DatabaseSchema.Tables.Lock).Column("id").Do();
- }
- }
-}
diff --git a/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/MakeRedirectUrlVariant.cs b/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/MakeRedirectUrlVariant.cs
index 2e366c7c14..651c95e6bd 100644
--- a/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/MakeRedirectUrlVariant.cs
+++ b/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/MakeRedirectUrlVariant.cs
@@ -11,19 +11,6 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0
public override void Migrate()
{
AddColumn("culture");
-
- Delete.Index("IX_umbracoRedirectUrl").OnTable(Constants.DatabaseSchema.Tables.RedirectUrl).Do();
- Create.Index("IX_umbracoRedirectUrl").OnTable(Constants.DatabaseSchema.Tables.RedirectUrl)
- .OnColumn("urlHash")
- .Ascending()
- .OnColumn("contentKey")
- .Ascending()
- .OnColumn("culture")
- .Ascending()
- .OnColumn("createDateUtc")
- .Ascending()
- .WithOptions().Unique()
- .Do();
}
}
}
diff --git a/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/MakeTagsVariant.cs b/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/MakeTagsVariant.cs
index 9ccd6d5e76..c898187884 100644
--- a/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/MakeTagsVariant.cs
+++ b/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/MakeTagsVariant.cs
@@ -11,17 +11,6 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0
public override void Migrate()
{
AddColumn("languageId");
-
- Delete.Index($"IX_{Constants.DatabaseSchema.Tables.Tag}").OnTable(Constants.DatabaseSchema.Tables.Tag).Do();
- Create.Index($"IX_{Constants.DatabaseSchema.Tables.Tag}").OnTable(Constants.DatabaseSchema.Tables.Tag)
- .OnColumn("group")
- .Ascending()
- .OnColumn("tag")
- .Ascending()
- .OnColumn("languageId")
- .Ascending()
- .WithOptions().Unique()
- .Do();
}
}
}
diff --git a/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/PropertyEditorsMigrationBase.cs b/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/PropertyEditorsMigrationBase.cs
new file mode 100644
index 0000000000..605f8a9eed
--- /dev/null
+++ b/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/PropertyEditorsMigrationBase.cs
@@ -0,0 +1,97 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Newtonsoft.Json;
+using Umbraco.Core.Logging;
+using Umbraco.Core.Persistence;
+using Umbraco.Core.Persistence.Dtos;
+using Umbraco.Core.PropertyEditors;
+
+namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0
+{
+ public abstract class PropertyEditorsMigrationBase : MigrationBase
+ {
+ protected PropertyEditorsMigrationBase(IMigrationContext context)
+ : base(context)
+ { }
+
+ internal List GetDataTypes(string editorAlias, bool strict = true)
+ {
+ var sql = Sql()
+ .Select()
+ .From();
+
+ sql = strict
+ ? sql.Where(x => x.EditorAlias == editorAlias)
+ : sql.Where(x => x.EditorAlias.Contains(editorAlias));
+
+ return Database.Fetch(sql);
+ }
+
+ protected int[] ConvertStringValues(string val)
+ {
+ var splitVals = val.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
+
+ var intVals = splitVals
+ .Select(x => int.TryParse(x, out var i) ? i : int.MinValue)
+ .Where(x => x != int.MinValue)
+ .ToArray();
+
+ //only return if the number of values are the same (i.e. All INTs)
+ if (splitVals.Length == intVals.Length)
+ return intVals;
+
+ return null;
+ }
+
+ internal bool UpdatePropertyDataDto(PropertyDataDto propData, ValueListConfiguration config, bool isMultiple)
+ {
+ //Get the INT ids stored for this property/drop down
+ int[] ids = null;
+ if (!propData.VarcharValue.IsNullOrWhiteSpace())
+ {
+ ids = ConvertStringValues(propData.VarcharValue);
+ }
+ else if (!propData.TextValue.IsNullOrWhiteSpace())
+ {
+ ids = ConvertStringValues(propData.TextValue);
+ }
+ else if (propData.IntegerValue.HasValue)
+ {
+ ids = new[] { propData.IntegerValue.Value };
+ }
+
+ // if there are INT ids, convert them to values based on the configuration
+ if (ids == null || ids.Length <= 0) return false;
+
+ // map ids to values
+ var values = new List();
+ var canConvert = true;
+
+ foreach (var id in ids)
+ {
+ var val = config.Items.FirstOrDefault(x => x.Id == id);
+ if (val != null)
+ {
+ values.Add(val.Value);
+ continue;
+ }
+
+ Logger.Warn(GetType(), "Could not find PropertyData {PropertyDataId} value '{PropertyValue}' in the datatype configuration: {Values}.",
+ propData.Id, id, string.Join(", ", config.Items.Select(x => x.Id + ":" + x.Value)));
+ canConvert = false;
+ }
+
+ if (!canConvert) return false;
+
+ propData.VarcharValue = isMultiple ? JsonConvert.SerializeObject(values) : values[0];
+ propData.TextValue = null;
+ propData.IntegerValue = null;
+ return true;
+ }
+
+ // dummy editor for deserialization
+ protected class ValueListConfigurationEditor : ConfigurationEditor
+ { }
+ }
+}
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
deleted file mode 100644
index 1944c8079f..0000000000
--- a/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/RadioAndCheckboxAndDropdownPropertyEditorsMigration.cs
+++ /dev/null
@@ -1,183 +0,0 @@
-using System;
-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;
-using Umbraco.Core.PropertyEditors;
-
-namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0
-{
- public class RadioAndCheckboxAndDropdownPropertyEditorsMigration : MigrationBase
- {
- public RadioAndCheckboxAndDropdownPropertyEditorsMigration(IMigrationContext context)
- : base(context)
- {
- }
-
- public override void Migrate()
- {
- var refreshCache = false;
-
- refreshCache |= Migrate(Constants.PropertyEditors.Aliases.RadioButtonList, (dto, configuration) => UpdateRadioOrCheckboxPropertyDataDto(dto, configuration, true));
- refreshCache |= Migrate(Constants.PropertyEditors.Aliases.CheckBoxList, (dto, configuration) => UpdateRadioOrCheckboxPropertyDataDto(dto, configuration, false));
- refreshCache |= Migrate(Constants.PropertyEditors.Aliases.DropDownListFlexible, UpdateDropDownPropertyDataDto);
-
- if (refreshCache)
- {
- Context.AddPostMigration();
- }
- }
-
- private bool Migrate(string editorAlias, Func updateRadioPropertyDataFunc)
- {
- var refreshCache = false;
- var dataTypes = GetDataTypes(editorAlias);
-
- foreach (var dataType in dataTypes)
- {
- ValueListConfiguration config;
-
- if (dataType.Configuration.IsNullOrWhiteSpace())
- continue;
-
- // parse configuration, and update everything accordingly
- try
- {
- config = (ValueListConfiguration) new ValueListConfigurationEditor().FromDatabase(
- dataType.Configuration);
- }
- catch (Exception ex)
- {
- Logger.Error(
- ex,
- "Invalid property editor configuration detected: \"{Configuration}\", cannot convert editor, values will be cleared",
- dataType.Configuration);
-
- continue;
- }
-
- // get property data dtos
- var propertyDataDtos = Database.Fetch(Sql()
- .Select()
- .From()
- .InnerJoin()
- .On((pt, pd) => pt.Id == pd.PropertyTypeId)
- .InnerJoin()
- .On((dt, pt) => dt.NodeId == pt.DataTypeId)
- .Where(x => x.DataTypeId == dataType.NodeId));
-
- // update dtos
- var updatedDtos = propertyDataDtos.Where(x => updateRadioPropertyDataFunc(x, config));
-
- // persist changes
- foreach (var propertyDataDto in updatedDtos) Database.Update(propertyDataDto);
-
- UpdateDataType(dataType);
- refreshCache = true;
- }
-
- return refreshCache;
- }
-
- private List GetDataTypes(string editorAlias)
- {
- //need to convert the old drop down data types to use the new one
- var dataTypes = Database.Fetch(Sql()
- .Select()
- .From()
- .Where(x => x.EditorAlias == editorAlias));
- return dataTypes;
- }
-
- private void UpdateDataType(DataTypeDto dataType)
- {
- dataType.DbType = ValueStorageType.Nvarchar.ToString();
- Database.Update(dataType);
- }
-
- private bool UpdateRadioOrCheckboxPropertyDataDto(PropertyDataDto propData, ValueListConfiguration config, bool singleValue)
- {
- //Get the INT ids stored for this property/drop down
- int[] ids = null;
- if (!propData.VarcharValue.IsNullOrWhiteSpace())
- {
- ids = ConvertStringValues(propData.VarcharValue);
- }
- else if (!propData.TextValue.IsNullOrWhiteSpace())
- {
- ids = ConvertStringValues(propData.TextValue);
- }
- else if (propData.IntegerValue.HasValue)
- {
- ids = new[] {propData.IntegerValue.Value};
- }
-
- //if there are INT ids, convert them to values based on the configuration
- if (ids == null || ids.Length <= 0) return false;
-
- //map the ids to values
- var values = new List();
- var canConvert = true;
-
- foreach (var id in ids)
- {
- var val = config.Items.FirstOrDefault(x => x.Id == id);
- if (val != null)
- values.Add(val.Value);
- else
- {
- Logger.Warn(
- "Could not find associated data type configuration for stored Id {DataTypeId}", id);
- canConvert = false;
- }
- }
-
- if (!canConvert) return false;
-
- //The radio button only supports selecting a single value, so if there are multiple for some insane reason we can only use the first
- propData.VarcharValue = singleValue ? values[0] : JsonConvert.SerializeObject(values);
- propData.TextValue = null;
- propData.IntegerValue = null;
- return true;
- }
-
- private bool UpdateDropDownPropertyDataDto(PropertyDataDto propData, ValueListConfiguration config)
- {
- //Get the INT ids stored for this property/drop down
- var values = propData.VarcharValue.Split(new []{","}, StringSplitOptions.RemoveEmptyEntries);
-
- //if there are INT ids, convert them to values based on the configuration
- if (values == null || values.Length <= 0) return false;
-
- //The radio button only supports selecting a single value, so if there are multiple for some insane reason we can only use the first
- propData.VarcharValue = JsonConvert.SerializeObject(values);
- propData.TextValue = null;
- propData.IntegerValue = null;
- return true;
- }
-
- private int[] ConvertStringValues(string val)
- {
- var splitVals = val.Split(new[] {','}, StringSplitOptions.RemoveEmptyEntries);
-
- var intVals = splitVals
- .Select(x => int.TryParse(x, out var i) ? i : int.MinValue)
- .Where(x => x != int.MinValue)
- .ToArray();
-
- //only return if the number of values are the same (i.e. All INTs)
- if (splitVals.Length == intVals.Length)
- return intVals;
-
- return null;
- }
-
- private class ValueListConfigurationEditor : ConfigurationEditor
- {
- }
- }
-}
diff --git a/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/RadioAndCheckboxPropertyEditorsMigration.cs b/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/RadioAndCheckboxPropertyEditorsMigration.cs
new file mode 100644
index 0000000000..e96fa1f7e9
--- /dev/null
+++ b/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/RadioAndCheckboxPropertyEditorsMigration.cs
@@ -0,0 +1,88 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Umbraco.Core.Logging;
+using Umbraco.Core.Migrations.PostMigrations;
+using Umbraco.Core.Models;
+using Umbraco.Core.Persistence;
+using Umbraco.Core.Persistence.Dtos;
+using Umbraco.Core.PropertyEditors;
+
+namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0
+{
+ public class RadioAndCheckboxPropertyEditorsMigration : PropertyEditorsMigrationBase
+ {
+ public RadioAndCheckboxPropertyEditorsMigration(IMigrationContext context)
+ : base(context)
+ { }
+
+ public override void Migrate()
+ {
+ var refreshCache = false;
+
+ refreshCache |= Migrate(GetDataTypes(Constants.PropertyEditors.Aliases.RadioButtonList), false);
+ refreshCache |= Migrate(GetDataTypes(Constants.PropertyEditors.Aliases.CheckBoxList), true);
+
+ // if some data types have been updated directly in the database (editing DataTypeDto and/or PropertyDataDto),
+ // bypassing the services, then we need to rebuild the cache entirely, including the umbracoContentNu table
+ if (refreshCache)
+ Context.AddPostMigration();
+ }
+
+ private bool Migrate(IEnumerable dataTypes, bool isMultiple)
+ {
+ var refreshCache = false;
+ ConfigurationEditor configurationEditor = null;
+
+ foreach (var dataType in dataTypes)
+ {
+ ValueListConfiguration config;
+
+ if (dataType.Configuration.IsNullOrWhiteSpace())
+ continue;
+
+ // parse configuration, and update everything accordingly
+ if (configurationEditor == null)
+ configurationEditor = new ValueListConfigurationEditor();
+ try
+ {
+ config = (ValueListConfiguration) configurationEditor.FromDatabase(dataType.Configuration);
+ }
+ catch (Exception ex)
+ {
+ Logger.Error(
+ ex, "Invalid configuration: \"{Configuration}\", cannot convert editor.",
+ dataType.Configuration);
+
+ continue;
+ }
+
+ // get property data dtos
+ var propertyDataDtos = Database.Fetch(Sql()
+ .Select()
+ .From()
+ .InnerJoin().On((pt, pd) => pt.Id == pd.PropertyTypeId)
+ .InnerJoin().On((dt, pt) => dt.NodeId == pt.DataTypeId)
+ .Where(x => x.DataTypeId == dataType.NodeId));
+
+ // update dtos
+ var updatedDtos = propertyDataDtos.Where(x => UpdatePropertyDataDto(x, config, isMultiple));
+
+ // persist changes
+ foreach (var propertyDataDto in updatedDtos)
+ Database.Update(propertyDataDto);
+
+ UpdateDataType(dataType);
+ refreshCache = true;
+ }
+
+ return refreshCache;
+ }
+
+ private void UpdateDataType(DataTypeDto dataType)
+ {
+ dataType.DbType = ValueStorageType.Nvarchar.ToString();
+ Database.Update(dataType);
+ }
+ }
+}
diff --git a/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/RefactorXmlColumns.cs b/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/RefactorXmlColumns.cs
deleted file mode 100644
index c683940f60..0000000000
--- a/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/RefactorXmlColumns.cs
+++ /dev/null
@@ -1,69 +0,0 @@
-using System.Collections.Generic;
-using System.Linq;
-using Umbraco.Core.Logging;
-using Umbraco.Core.Persistence;
-
-namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0
-{
- public class RefactorXmlColumns : MigrationBase
- {
- public RefactorXmlColumns(IMigrationContext context)
- : base(context)
- { }
-
- public override void Migrate()
- {
- if (ColumnExists("cmsContentXml", "Rv") == false)
- Alter.Table("cmsContentXml").AddColumn("Rv").AsInt64().NotNullable().WithDefaultValue(0).Do();
-
- if (ColumnExists("cmsPreviewXml", "Rv") == false)
- Alter.Table("cmsPreviewXml").AddColumn("Rv").AsInt64().NotNullable().WithDefaultValue(0).Do();
-
- // remove the any PK_ and the FK_ to cmsContentVersion.VersionId
- var constraints = SqlSyntax.GetConstraintsPerColumn(Context.Database).Distinct().ToArray();
- var dups = new List();
- foreach (var c in constraints.Where(x => x.Item1.InvariantEquals("cmsPreviewXml") && x.Item3.InvariantStartsWith("PK_")))
- {
- var keyName = c.Item3.ToLowerInvariant();
- if (dups.Contains(keyName))
- {
- Logger.Warn("Duplicate constraint '{Constraint}'", c.Item3);
- continue;
- }
- dups.Add(keyName);
- Delete.PrimaryKey(c.Item3).FromTable(c.Item1).Do();
- }
- foreach (var c in constraints.Where(x => x.Item1.InvariantEquals("cmsPreviewXml") && x.Item3.InvariantStartsWith("FK_cmsPreviewXml_cmsContentVersion")))
- {
- Delete.ForeignKey().FromTable("cmsPreviewXml").ForeignColumn("VersionId")
- .ToTable("cmsContentVersion").PrimaryColumn("VersionId")
- .Do();
- }
-
- if (ColumnExists("cmsPreviewXml", "Timestamp"))
- Delete.Column("Timestamp").FromTable("cmsPreviewXml").Do();
-
- if (ColumnExists("cmsPreviewXml", "VersionId"))
- {
- RemoveDuplicates();
- Delete.Column("VersionId").FromTable("cmsPreviewXml").Do();
- }
-
- // re-create the primary key
- Create.PrimaryKey("PK_cmsPreviewXml")
- .OnTable("cmsPreviewXml")
- .Columns(new[] { "nodeId" })
- .Do();
- }
-
- private void RemoveDuplicates()
- {
- const string sql = @"delete from cmsPreviewXml where versionId in (
-select cmsPreviewXml.versionId from cmsPreviewXml
-join cmsDocument on cmsPreviewXml.versionId=cmsDocument.versionId
-where cmsDocument.newest <> 1)";
-
- Context.Database.Execute(sql);
- }
- }
-}
diff --git a/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/RenameMediaVersionTable.cs b/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/RenameMediaVersionTable.cs
new file mode 100644
index 0000000000..b60923fcba
--- /dev/null
+++ b/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/RenameMediaVersionTable.cs
@@ -0,0 +1,46 @@
+using Umbraco.Core.Persistence.Dtos;
+
+namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0
+{
+ public class RenameMediaVersionTable : MigrationBase
+ {
+ public RenameMediaVersionTable(IMigrationContext context)
+ : base(context)
+ { }
+
+ public override void Migrate()
+ {
+ Rename.Table("cmsMedia").To(Constants.DatabaseSchema.Tables.MediaVersion).Do();
+
+ // that is not supported on SqlCE
+ //Rename.Column("versionId").OnTable(Constants.DatabaseSchema.Tables.MediaVersion).To("id").Do();
+
+ AddColumn("id", out var sqls);
+
+ // SQLCE does not support UPDATE...FROM
+ var temp2 = Database.Fetch($@"SELECT v.versionId, v.id
+FROM cmsContentVersion v
+JOIN umbracoNode n on v.contentId=n.id
+WHERE n.nodeObjectType='{Constants.ObjectTypes.Media}'");
+ foreach (var t in temp2)
+ Execute.Sql($"UPDATE {Constants.DatabaseSchema.Tables.MediaVersion} SET id={t.id} WHERE versionId='{t.versionId}'").Do();
+
+ foreach (var sql in sqls)
+ Execute.Sql(sql).Do();
+
+ AddColumn("path", out sqls);
+
+ Execute.Sql($"UPDATE {Constants.DatabaseSchema.Tables.MediaVersion} SET path=mediaPath").Do();
+
+ foreach (var sql in sqls)
+ Execute.Sql(sql).Do();
+
+ // we had to run sqls to get the NULL constraints, but we need to get rid of most
+ Delete.KeysAndIndexes(Constants.DatabaseSchema.Tables.MediaVersion).Do();
+
+ Delete.Column("mediaPath").FromTable(Constants.DatabaseSchema.Tables.MediaVersion).Do();
+ Delete.Column("versionId").FromTable(Constants.DatabaseSchema.Tables.MediaVersion).Do();
+ Delete.Column("nodeId").FromTable(Constants.DatabaseSchema.Tables.MediaVersion).Do();
+ }
+ }
+}
diff --git a/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/RenameUmbracoDomainsTable.cs b/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/RenameUmbracoDomainsTable.cs
index 9bbccf368c..0543b57fcc 100644
--- a/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/RenameUmbracoDomainsTable.cs
+++ b/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/RenameUmbracoDomainsTable.cs
@@ -2,7 +2,9 @@
{
public class RenameUmbracoDomainsTable : MigrationBase
{
- public RenameUmbracoDomainsTable(IMigrationContext context) : base(context) { }
+ public RenameUmbracoDomainsTable(IMigrationContext context)
+ : base(context)
+ { }
public override void Migrate()
{
diff --git a/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/SuperZero.cs b/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/SuperZero.cs
index ba29880e79..64ac20d175 100644
--- a/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/SuperZero.cs
+++ b/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/SuperZero.cs
@@ -11,20 +11,27 @@
var exists = Database.Fetch("select id from umbracoUser where id=-1;").Count > 0;
if (exists) return;
- Database.Execute("update umbracoUser set userLogin = userLogin + '__' where userId=0");
+ Database.Execute("update umbracoUser set userLogin = userLogin + '__' where id=0");
Database.Execute("set identity_insert umbracoUser on;");
Database.Execute(@"
- insert into umbracoUser select -1,
- userDisabled, userNoConsole, userName, substring(userLogin, 1, len(userLogin) - 2), userPassword, passwordConfig,
+ insert into umbracoUser (id,
+ userDisabled, userNoConsole, userName, userLogin, userPassword, passwordConfig,
+ userEmail, userLanguage, securityStampToken, failedLoginAttempts, lastLockoutDate,
+ lastPasswordChangeDate, lastLoginDate, emailConfirmedDate, invitedDate,
+ createDate, updateDate, avatar, tourData)
+ select
+ -1 id,
+ userDisabled, userNoConsole, userName, substring(userLogin, 1, len(userLogin) - 2) userLogin, userPassword, passwordConfig,
userEmail, userLanguage, securityStampToken, failedLoginAttempts, lastLockoutDate,
lastPasswordChangeDate, lastLoginDate, emailConfirmedDate, invitedDate,
- createDate, updateDate, avatar
+ createDate, updateDate, avatar, tourData
from umbracoUser where id=0;");
Database.Execute("set identity_insert umbracoUser off;");
Database.Execute("update umbracoUser2UserGroup set userId=-1 where userId=0;");
Database.Execute("update umbracoNode set nodeUser=-1 where nodeUser=0;");
+ Database.Execute("update umbracoUserLogin set userId=-1 where userId=0;");
Database.Execute($"update {Constants.DatabaseSchema.Tables.ContentVersion} set userId=-1 where userId=0;");
Database.Execute("delete from umbracoUser where id=0;");
}
diff --git a/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/TablesForScheduledPublishing.cs b/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/TablesForScheduledPublishing.cs
index cd4de179bd..70dbe3d29e 100644
--- a/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/TablesForScheduledPublishing.cs
+++ b/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/TablesForScheduledPublishing.cs
@@ -24,7 +24,7 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0
Delete.Column("releaseDate").FromTable("umbracoDocument").Do();
Delete.Column("expireDate").FromTable("umbracoDocument").Do();
//add new table
- Create.Table().Do();
+ Create.Table(true).Do();
//migrate the schedule
foreach(var s in schedules)
diff --git a/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/TagsMigration.cs b/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/TagsMigration.cs
index 5dc5e0b6fe..d6a5380e31 100644
--- a/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/TagsMigration.cs
+++ b/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/TagsMigration.cs
@@ -1,4 +1,5 @@
-using Umbraco.Core.Persistence.Dtos;
+using System.Linq;
+using Umbraco.Core.Persistence.Dtos;
namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0
{
@@ -14,13 +15,8 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0
AlterColumn(Constants.DatabaseSchema.Tables.Tag, "group");
AlterColumn(Constants.DatabaseSchema.Tables.Tag, "tag");
- //AddColumn(Constants.DatabaseSchema.Tables.Tag, "key");
-
// kill unused parentId column
- Delete.ForeignKey("FK_cmsTags_cmsTags").OnTable(Constants.DatabaseSchema.Tables.Tag).Do();
Delete.Column("ParentId").FromTable(Constants.DatabaseSchema.Tables.Tag).Do();
}
}
-
- // fixes TagsMigration that... originally failed to properly drop the ParentId column
}
diff --git a/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/UpdatePickerIntegerValuesToUdi.cs b/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/UpdatePickerIntegerValuesToUdi.cs
index 2e37c79632..7f7cf8474c 100644
--- a/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/UpdatePickerIntegerValuesToUdi.cs
+++ b/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/UpdatePickerIntegerValuesToUdi.cs
@@ -2,6 +2,7 @@
using System.Linq;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
+using Umbraco.Core.Composing;
using Umbraco.Core.Persistence;
using Umbraco.Core.Persistence.Dtos;
diff --git a/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/UserForeignKeys.cs b/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/UserForeignKeys.cs
index 68a68ec53e..f16c9cd761 100644
--- a/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/UserForeignKeys.cs
+++ b/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/UserForeignKeys.cs
@@ -1,6 +1,4 @@
-using NPoco;
-using Umbraco.Core.Persistence.DatabaseAnnotations;
-using Umbraco.Core.Persistence.Dtos;
+using Umbraco.Core.Persistence.Dtos;
namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0
{
@@ -15,24 +13,19 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0
public override void Migrate()
{
- //first allow NULL-able
+ // first allow NULL-able
Alter.Table(ContentVersionCultureVariationDto.TableName).AlterColumn("availableUserId").AsInt32().Nullable().Do();
Alter.Table(ContentVersionDto.TableName).AlterColumn("userId").AsInt32().Nullable().Do();
Alter.Table(Constants.DatabaseSchema.Tables.Log).AlterColumn("userId").AsInt32().Nullable().Do();
Alter.Table(NodeDto.TableName).AlterColumn("nodeUser").AsInt32().Nullable().Do();
- //then we can update any non existing users to NULL
+ // then we can update any non existing users to NULL
Execute.Sql($"UPDATE {ContentVersionCultureVariationDto.TableName} SET availableUserId = NULL WHERE availableUserId NOT IN (SELECT id FROM {UserDto.TableName})").Do();
Execute.Sql($"UPDATE {ContentVersionDto.TableName} SET userId = NULL WHERE userId NOT IN (SELECT id FROM {UserDto.TableName})").Do();
Execute.Sql($"UPDATE {Constants.DatabaseSchema.Tables.Log} SET userId = NULL WHERE userId NOT IN (SELECT id FROM {UserDto.TableName})").Do();
Execute.Sql($"UPDATE {NodeDto.TableName} SET nodeUser = NULL WHERE nodeUser NOT IN (SELECT id FROM {UserDto.TableName})").Do();
- //now NULL-able with FKs
- Alter.Table(ContentVersionCultureVariationDto.TableName).AlterColumn("availableUserId").AsInt32().Nullable().ForeignKey(UserDto.TableName, "id").Do();
- Alter.Table(ContentVersionDto.TableName).AlterColumn("userId").AsInt32().Nullable().ForeignKey(UserDto.TableName, "id").Do();
- Alter.Table(Constants.DatabaseSchema.Tables.Log).AlterColumn("userId").AsInt32().Nullable().ForeignKey(UserDto.TableName, "id").Do();
- Alter.Table(NodeDto.TableName).AlterColumn("nodeUser").AsInt32().Nullable().ForeignKey(UserDto.TableName, "id").Do();
+ // FKs will be created after migrations
}
-
}
}
diff --git a/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/VariantsMigration.cs b/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/VariantsMigration.cs
index c193fdeb1f..8c60d30680 100644
--- a/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/VariantsMigration.cs
+++ b/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/VariantsMigration.cs
@@ -18,9 +18,6 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0
public override void Migrate()
{
- // delete *all* keys and indexes - because of FKs
- Delete.KeysAndIndexes().Do();
-
MigratePropertyData();
MigrateContentAndPropertyTypes();
MigrateContent();
@@ -46,10 +43,6 @@ HAVING COUNT(v2.id) <> 1").Any())
Debugger.Break();
throw new Exception("Migration failed: missing or duplicate 'current' content versions.");
}
-
- // re-create *all* keys and indexes
- foreach (var x in DatabaseSchemaCreator.OrderedTables)
- Create.KeysAndIndexes(x).Do();
}
private void MigratePropertyData()
@@ -220,8 +213,10 @@ WHERE versionId NOT IN (SELECT (versionId) FROM {PreTables.ContentVersion} WHERE
Delete.Column("text").FromTable(PreTables.Document).Do();
Delete.Column("templateId").FromTable(PreTables.Document).Do();
Delete.Column("documentUser").FromTable(PreTables.Document).Do();
+ Delete.DefaultConstraint().OnTable(PreTables.Document).OnColumn("updateDate").Do();
Delete.Column("updateDate").FromTable(PreTables.Document).Do();
Delete.Column("versionId").FromTable(PreTables.Document).Do();
+ Delete.DefaultConstraint().OnTable(PreTables.Document).OnColumn("newest").Do();
Delete.Column("newest").FromTable(PreTables.Document).Do();
// add and populate edited column
@@ -320,7 +315,7 @@ WHERE v1.propertyTypeId=v2.propertyTypeId AND v1.languageId=v2.languageId AND v1
public const string Tag = "cmsTags";
public const string TagRelationship = "cmsTagRelationship";
-
+
// ReSharper restore UnusedMember.Local
}
}
diff --git a/src/Umbraco.Core/Migrations/Upgrade/V_8_1_0/ChangeNuCacheJsonFormat.cs b/src/Umbraco.Core/Migrations/Upgrade/V_8_1_0/ChangeNuCacheJsonFormat.cs
deleted file mode 100644
index 0ceb366e1c..0000000000
--- a/src/Umbraco.Core/Migrations/Upgrade/V_8_1_0/ChangeNuCacheJsonFormat.cs
+++ /dev/null
@@ -1,16 +0,0 @@
-using Umbraco.Core.Migrations.PostMigrations;
-
-namespace Umbraco.Core.Migrations.Upgrade.V_8_1_0
-{
- public class ChangeNuCacheJsonFormat : MigrationBase
- {
- public ChangeNuCacheJsonFormat(IMigrationContext context) : base(context)
- { }
-
- public override void Migrate()
- {
- // nothing - just adding the post-migration
- Context.AddPostMigration();
- }
- }
-}
diff --git a/src/Umbraco.Core/Migrations/Upgrade/V_8_1_0/ConvertTinyMceAndGridMediaUrlsToLocalLink.cs b/src/Umbraco.Core/Migrations/Upgrade/V_8_1_0/ConvertTinyMceAndGridMediaUrlsToLocalLink.cs
index 50c7daf65d..bf048bf2bd 100644
--- a/src/Umbraco.Core/Migrations/Upgrade/V_8_1_0/ConvertTinyMceAndGridMediaUrlsToLocalLink.cs
+++ b/src/Umbraco.Core/Migrations/Upgrade/V_8_1_0/ConvertTinyMceAndGridMediaUrlsToLocalLink.cs
@@ -1,4 +1,4 @@
-using System;
+using System;
using System.Linq;
using System.Text.RegularExpressions;
using Newtonsoft.Json;
@@ -26,8 +26,7 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_1_0
RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace);
var sqlPropertyData = Sql()
- .Select(x => x.Id, x => x.TextValue)
- .AndSelect(x => x.EditorAlias)
+ .Select(r => r.Select(x => x.PropertyTypeDto, r1 => r1.Select(x => x.DataTypeDto)))
.From()
.InnerJoin().On((left, right) => left.PropertyTypeId == right.Id)
.InnerJoin().On((left, right) => left.DataTypeId == right.NodeId)
@@ -63,7 +62,7 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_1_0
property.TextValue = UpdateMediaUrls(mediaLinkPattern, value);
}
- Database.Update(property, x => x.TextValue);
+ Database.Update(property);
}
Context.AddPostMigration();
diff --git a/src/Umbraco.Core/Migrations/Upgrade/V_8_1_0/FixContentNuCascade.cs b/src/Umbraco.Core/Migrations/Upgrade/V_8_1_0/FixContentNuCascade.cs
new file mode 100644
index 0000000000..09ea941742
--- /dev/null
+++ b/src/Umbraco.Core/Migrations/Upgrade/V_8_1_0/FixContentNuCascade.cs
@@ -0,0 +1,17 @@
+using Umbraco.Core.Persistence.Dtos;
+
+namespace Umbraco.Core.Migrations.Upgrade.V_8_1_0
+{
+ public class FixContentNuCascade : MigrationBase
+ {
+ public FixContentNuCascade(IMigrationContext context)
+ : base(context)
+ { }
+
+ public override void Migrate()
+ {
+ Delete.KeysAndIndexes().Do();
+ Create.KeysAndIndexes().Do();
+ }
+ }
+}
diff --git a/src/Umbraco.Core/Migrations/Upgrade/V_8_1_0/RenameUserLoginDtoDateIndex.cs b/src/Umbraco.Core/Migrations/Upgrade/V_8_1_0/RenameUserLoginDtoDateIndex.cs
new file mode 100644
index 0000000000..c0b9c8f2db
--- /dev/null
+++ b/src/Umbraco.Core/Migrations/Upgrade/V_8_1_0/RenameUserLoginDtoDateIndex.cs
@@ -0,0 +1,36 @@
+using Umbraco.Core.Persistence.Dtos;
+
+namespace Umbraco.Core.Migrations.Upgrade.V_8_1_0
+{
+ public class RenameUserLoginDtoDateIndex : MigrationBase
+ {
+ public RenameUserLoginDtoDateIndex(IMigrationContext context)
+ : base(context)
+ { }
+
+ public override void Migrate()
+ {
+ // there has been some confusion with an index name, resulting in
+ // different names depending on which migration path was followed,
+ // and discrepancies between an upgraded or an installed database.
+ // better normalize
+
+ if (IndexExists("IX_umbracoUserLogin_lastValidatedUtc"))
+ return;
+
+ if (IndexExists("IX_userLoginDto_lastValidatedUtc"))
+ Delete
+ .Index("IX_userLoginDto_lastValidatedUtc")
+ .OnTable(UserLoginDto.TableName)
+ .Do();
+
+ Create
+ .Index("IX_umbracoUserLogin_lastValidatedUtc")
+ .OnTable(UserLoginDto.TableName)
+ .OnColumn("lastValidatedUtc")
+ .Ascending()
+ .WithOptions().NonClustered()
+ .Do();
+ }
+ }
+}
diff --git a/src/Umbraco.Core/Models/DataType.cs b/src/Umbraco.Core/Models/DataType.cs
index 8745e6dbec..c237f6381c 100644
--- a/src/Umbraco.Core/Models/DataType.cs
+++ b/src/Umbraco.Core/Models/DataType.cs
@@ -48,7 +48,16 @@ namespace Umbraco.Core.Models
var configuration = Configuration;
var json = JsonConvert.SerializeObject(configuration);
_editor = value;
- Configuration = _editor.GetConfigurationEditor().FromDatabase(json);
+
+ try
+ {
+ Configuration = _editor.GetConfigurationEditor().FromDatabase(json);
+ }
+ catch (Exception e)
+ {
+ throw new InvalidOperationException($"The configuration for data type {Id} : {EditorAlias} is invalid (see inner exception)."
+ + " Please fix the configuration and ensure it is valid. The site may fail to start and / or load data types and run.", e);
+ }
}
}
@@ -76,7 +85,16 @@ namespace Umbraco.Core.Models
if (_hasConfiguration) return _configuration;
- _configuration = _editor.GetConfigurationEditor().FromDatabase(_configurationJson);
+ try
+ {
+ _configuration = _editor.GetConfigurationEditor().FromDatabase(_configurationJson);
+ }
+ catch (Exception e)
+ {
+ throw new InvalidOperationException($"The configuration for data type {Id} : {EditorAlias} is invalid (see inner exception)."
+ + " Please fix the configuration and ensure it is valid. The site may fail to start and / or load data types and run.", e);
+ }
+
_hasConfiguration = true;
_configurationJson = null;
@@ -158,7 +176,18 @@ namespace Umbraco.Core.Models
// else, create a Lazy de-serializer
var capturedConfiguration = _configurationJson;
var capturedEditor = _editor;
- return new Lazy
[Column("lastValidatedUtc")]
[NullSetting(NullSetting = NullSettings.NotNull)]
- [Index(IndexTypes.NonClustered, Name = "IX_userLoginDto_lastValidatedUtc")]
+ [Index(IndexTypes.NonClustered, Name = "IX_umbracoUserLogin_lastValidatedUtc")]
public DateTime LastValidatedUtc { get; set; }
///
diff --git a/src/Umbraco.Core/Persistence/Factories/DataTypeFactory.cs b/src/Umbraco.Core/Persistence/Factories/DataTypeFactory.cs
index f5144e34eb..f189d38d05 100644
--- a/src/Umbraco.Core/Persistence/Factories/DataTypeFactory.cs
+++ b/src/Umbraco.Core/Persistence/Factories/DataTypeFactory.cs
@@ -15,7 +15,8 @@ namespace Umbraco.Core.Persistence.Factories
{
if (!editors.TryGet(dto.EditorAlias, out var editor))
{
- logger.Warn(typeof(DataTypeFactory), "Could not find an editor with alias {EditorAlias}, converting to label", dto.EditorAlias);
+ logger.Warn(typeof(DataType), "Could not find an editor with alias {EditorAlias}, treating as Label."
+ +" The site may fail to boot and / or load data types and run.", dto.EditorAlias);
//convert to label
editor = new LabelPropertyEditor(logger);
}
diff --git a/src/Umbraco.Core/Persistence/Factories/UserFactory.cs b/src/Umbraco.Core/Persistence/Factories/UserFactory.cs
index dae70d502f..c64eb14bb7 100644
--- a/src/Umbraco.Core/Persistence/Factories/UserFactory.cs
+++ b/src/Umbraco.Core/Persistence/Factories/UserFactory.cs
@@ -36,6 +36,13 @@ namespace Umbraco.Core.Persistence.Factories
user.InvitedDate = dto.InvitedDate;
user.TourData = dto.TourData;
+ // we should never get user with ID zero from database, except
+ // when upgrading from v7 - mark that user so that we do not
+ // save it back to database (as that would create a *new* user)
+ // see also: UserRepository.PersistNewItem
+ if (dto.Id == 0)
+ user.AdditionalData["IS_V7_ZERO"] = true;
+
// reset dirty initial properties (U4-1946)
user.ResetDirtyProperties(false);
diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/UserRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/UserRepository.cs
index 9027e9269c..91a20c5bdd 100644
--- a/src/Umbraco.Core/Persistence/Repositories/Implement/UserRepository.cs
+++ b/src/Umbraco.Core/Persistence/Repositories/Implement/UserRepository.cs
@@ -434,6 +434,17 @@ ORDER BY colName";
protected override void PersistNewItem(IUser entity)
{
+ // the use may have no identity, ie ID is zero, and be v7 super
+ // user - then it has been marked - and we must not persist it
+ // as new, as we do not want to create a new user - instead, persist
+ // it as updated
+ // see also: UserFactory.BuildEntity
+ if (((User) entity).AdditionalData.ContainsKey("IS_V7_ZERO"))
+ {
+ PersistUpdatedItem(entity);
+ return;
+ }
+
((User) entity).AddingEntity();
// ensure security stamp if missing
diff --git a/src/Umbraco.Core/Persistence/SqlSyntax/ISqlSyntaxProvider.cs b/src/Umbraco.Core/Persistence/SqlSyntax/ISqlSyntaxProvider.cs
index c352e312ac..55625ff04e 100644
--- a/src/Umbraco.Core/Persistence/SqlSyntax/ISqlSyntaxProvider.cs
+++ b/src/Umbraco.Core/Persistence/SqlSyntax/ISqlSyntaxProvider.cs
@@ -44,7 +44,7 @@ namespace Umbraco.Core.Persistence.SqlSyntax
string TruncateTable { get; }
string CreateConstraint { get; }
string DeleteConstraint { get; }
-
+
string DeleteDefaultConstraint { get; }
string FormatDateTime(DateTime date, bool includeTime = true);
string Format(TableDefinition table);
@@ -106,5 +106,20 @@ namespace Umbraco.Core.Persistence.SqlSyntax
/// A Tuple containing: TableName, IndexName, ColumnName, IsUnique
///
IEnumerable> GetDefinedIndexes(IDatabase db);
+
+ ///
+ /// Tries to gets the name of the default constraint on a column.
+ ///
+ /// The database.
+ /// The table name.
+ /// The column name.
+ /// The constraint name.
+ /// A value indicating whether a default constraint was found.
+ ///
+ /// Some database engines (e.g. SqlCe) may not have names for default constraints,
+ /// in which case the function may return true, but is
+ /// unspecified.
+ ///
+ bool TryGetDefaultConstraint(IDatabase db, string tableName, string columnName, out string constraintName);
}
}
diff --git a/src/Umbraco.Core/Persistence/SqlSyntax/SqlCeSyntaxProvider.cs b/src/Umbraco.Core/Persistence/SqlSyntax/SqlCeSyntaxProvider.cs
index 8f39e36fb9..cb4b7a5176 100644
--- a/src/Umbraco.Core/Persistence/SqlSyntax/SqlCeSyntaxProvider.cs
+++ b/src/Umbraco.Core/Persistence/SqlSyntax/SqlCeSyntaxProvider.cs
@@ -132,6 +132,17 @@ ORDER BY TABLE_NAME, INDEX_NAME");
item => new Tuple(item.TABLE_NAME, item.INDEX_NAME, item.COLUMN_NAME, item.UNIQUE));
}
+ ///
+ public override bool TryGetDefaultConstraint(IDatabase db, string tableName, string columnName, out string constraintName)
+ {
+ // cannot return a true default constraint name (does not exist on SqlCe)
+ // but we won't really need it anyways - just check whether there is a constraint
+ constraintName = null;
+ var hasDefault = db.Fetch(@"select column_hasdefault from information_schema.columns
+where table_name=@0 and column_name=@1", tableName, columnName).FirstOrDefault();
+ return hasDefault;
+ }
+
public override bool DoesTableExist(IDatabase db, string tableName)
{
var result =
@@ -175,7 +186,7 @@ ORDER BY TABLE_NAME, INDEX_NAME");
{
get
{
- return "ALTER TABLE [{0}] ALTER COLUMN [{1}] DROP DEFAULT";
+ return "ALTER TABLE {0} ALTER COLUMN {1} DROP DEFAULT";
}
}
diff --git a/src/Umbraco.Core/Persistence/SqlSyntax/SqlServerSyntaxProvider.cs b/src/Umbraco.Core/Persistence/SqlSyntax/SqlServerSyntaxProvider.cs
index e51aa547b8..fab7526a6b 100644
--- a/src/Umbraco.Core/Persistence/SqlSyntax/SqlServerSyntaxProvider.cs
+++ b/src/Umbraco.Core/Persistence/SqlSyntax/SqlServerSyntaxProvider.cs
@@ -225,6 +225,18 @@ order by T.name, I.name");
}
+ ///
+ public override bool TryGetDefaultConstraint(IDatabase db, string tableName, string columnName, out string constraintName)
+ {
+ constraintName = db.Fetch(@"select con.[name] as [constraintName]
+from sys.default_constraints con
+join sys.columns col on con.object_id=col.default_object_id
+join sys.tables tbl on col.object_id=tbl.object_id
+where tbl.[name]=@0 and col.[name]=@1;", tableName, columnName)
+ .FirstOrDefault();
+ return !constraintName.IsNullOrWhiteSpace();
+ }
+
public override bool DoesTableExist(IDatabase db, string tableName)
{
var result =
@@ -276,7 +288,7 @@ order by T.name, I.name");
return null;
}
- public override string DeleteDefaultConstraint => "ALTER TABLE [{0}] DROP CONSTRAINT [DF_{0}_{1}]";
+ public override string DeleteDefaultConstraint => "ALTER TABLE {0} DROP CONSTRAINT {2}";
public override string DropIndex => "DROP INDEX {0} ON {1}";
diff --git a/src/Umbraco.Core/Persistence/SqlSyntax/SqlSyntaxProviderBase.cs b/src/Umbraco.Core/Persistence/SqlSyntax/SqlSyntaxProviderBase.cs
index 5b6a9afb04..0c27ac2d50 100644
--- a/src/Umbraco.Core/Persistence/SqlSyntax/SqlSyntaxProviderBase.cs
+++ b/src/Umbraco.Core/Persistence/SqlSyntax/SqlSyntaxProviderBase.cs
@@ -223,6 +223,8 @@ namespace Umbraco.Core.Persistence.SqlSyntax
public abstract IEnumerable> GetDefinedIndexes(IDatabase db);
+ public abstract bool TryGetDefaultConstraint(IDatabase db, string tableName, string columnName, out string constraintName);
+
public virtual bool DoesTableExist(IDatabase db, string tableName)
{
return false;
@@ -552,6 +554,7 @@ namespace Umbraco.Core.Persistence.SqlSyntax
public virtual string CreateConstraint => "ALTER TABLE {0} ADD CONSTRAINT {1} {2} ({3})";
public virtual string DeleteConstraint => "ALTER TABLE {0} DROP CONSTRAINT {1}";
public virtual string CreateForeignKeyConstraint => "ALTER TABLE {0} ADD CONSTRAINT {1} FOREIGN KEY ({2}) REFERENCES {3} ({4}){5}{6}";
+ public virtual string CreateDefaultConstraint => "ALTER TABLE {0} ADD CONSTRAINT {1} DEFAULT ({2}) FOR {3}";
public virtual string ConvertIntegerToOrderableString => "REPLACE(STR({0}, 8), SPACE(1), '0')";
public virtual string ConvertDateToOrderableString => "CONVERT(nvarchar, {0}, 102)";
diff --git a/src/Umbraco.Core/PropertyEditors/ConfigurationEditorOfTConfiguration.cs b/src/Umbraco.Core/PropertyEditors/ConfigurationEditorOfTConfiguration.cs
index 9d1193ac82..1654bb3f20 100644
--- a/src/Umbraco.Core/PropertyEditors/ConfigurationEditorOfTConfiguration.cs
+++ b/src/Umbraco.Core/PropertyEditors/ConfigurationEditorOfTConfiguration.cs
@@ -113,7 +113,7 @@ namespace Umbraco.Core.PropertyEditors
}
catch (Exception e)
{
- throw new Exception($"Failed to parse configuration \"{configuration}\" as \"{typeof(TConfiguration).Name}\" (see inner exception).", e);
+ throw new InvalidOperationException($"Failed to parse configuration \"{configuration}\" as \"{typeof(TConfiguration).Name}\" (see inner exception).", e);
}
}
diff --git a/src/Umbraco.Core/Services/Implement/ContentService.cs b/src/Umbraco.Core/Services/Implement/ContentService.cs
index bd77daffbe..5cc1a584b1 100644
--- a/src/Umbraco.Core/Services/Implement/ContentService.cs
+++ b/src/Umbraco.Core/Services/Implement/ContentService.cs
@@ -757,6 +757,11 @@ namespace Umbraco.Core.Services.Implement
if (publishedState != PublishedState.Published && publishedState != PublishedState.Unpublished)
throw new InvalidOperationException("Cannot save (un)publishing content, use the dedicated SavePublished method.");
+ if (content.Name != null && content.Name.Length > 255)
+ {
+ throw new InvalidOperationException("Name cannot be more than 255 characters in length.");
+ }
+
var evtMsgs = EventMessagesFactory.Get();
using (var scope = ScopeProvider.CreateScope())
@@ -870,6 +875,11 @@ namespace Umbraco.Core.Services.Implement
throw new NotSupportedException($"Culture \"{culture}\" is not supported by invariant content types.");
}
+ if(content.Name != null && content.Name.Length > 255)
+ {
+ throw new InvalidOperationException("Name cannot be more than 255 characters in length.");
+ }
+
using (var scope = ScopeProvider.CreateScope())
{
scope.WriteLock(Constants.Locks.ContentTree);
@@ -900,6 +910,11 @@ namespace Umbraco.Core.Services.Implement
if (content == null) throw new ArgumentNullException(nameof(content));
if (cultures == null) throw new ArgumentNullException(nameof(cultures));
+ if (content.Name != null && content.Name.Length > 255)
+ {
+ throw new InvalidOperationException("Name cannot be more than 255 characters in length.");
+ }
+
using (var scope = ScopeProvider.CreateScope())
{
scope.WriteLock(Constants.Locks.ContentTree);
diff --git a/src/Umbraco.Core/Services/Implement/KeyValueService.cs b/src/Umbraco.Core/Services/Implement/KeyValueService.cs
index eb68cea25c..b3f3f2468d 100644
--- a/src/Umbraco.Core/Services/Implement/KeyValueService.cs
+++ b/src/Umbraco.Core/Services/Implement/KeyValueService.cs
@@ -28,7 +28,6 @@ namespace Umbraco.Core.Services.Implement
{
if (_initialized) return;
Initialize();
- _initialized = true;
}
}
@@ -41,7 +40,10 @@ namespace Umbraco.Core.Services.Implement
// then everything should be ok (the table should exist, etc)
if (UmbracoVersion.LocalVersion != null && UmbracoVersion.LocalVersion.Major >= 8)
+ {
+ _initialized = true;
return;
+ }
// else we are upgrading from 7, we can assume that the locks table
// exists, but we need to create everything for key/value
@@ -53,6 +55,10 @@ namespace Umbraco.Core.Services.Implement
initMigration.Migrate();
scope.Complete();
}
+
+ // but don't assume we are initializing
+ // we are upgrading from v7 and if anything goes wrong,
+ // the table and everything will be rolled back
}
///
diff --git a/src/Umbraco.Core/Services/LocalizedTextServiceExtensions.cs b/src/Umbraco.Core/Services/LocalizedTextServiceExtensions.cs
index 51fdb7e8e3..ce5b3ef8c4 100644
--- a/src/Umbraco.Core/Services/LocalizedTextServiceExtensions.cs
+++ b/src/Umbraco.Core/Services/LocalizedTextServiceExtensions.cs
@@ -83,10 +83,10 @@ namespace Umbraco.Core.Services
internal static string UmbracoDictionaryTranslate(this ILocalizedTextService manager, string text)
{
var cultureDictionary = CultureDictionary;
- return UmbracoDictionaryTranslate(text, cultureDictionary);
+ return manager.UmbracoDictionaryTranslate(text, cultureDictionary);
}
- private static string UmbracoDictionaryTranslate(string text, ICultureDictionary cultureDictionary)
+ private static string UmbracoDictionaryTranslate(this ILocalizedTextService manager, string text, ICultureDictionary cultureDictionary)
{
if (text == null)
return null;
@@ -95,7 +95,14 @@ namespace Umbraco.Core.Services
return text;
text = text.Substring(1);
- return cultureDictionary[text].IfNullOrWhiteSpace(text);
+ var value = cultureDictionary[text];
+ if (value.IsNullOrWhiteSpace() == false)
+ {
+ return value;
+ }
+
+ value = manager.Localize(text.Replace('_', '/'));
+ return value.StartsWith("[") ? text : value;
}
private static ICultureDictionary CultureDictionary
diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj
index 2acffe7afa..ae1c643b2b 100755
--- a/src/Umbraco.Core/Umbraco.Core.csproj
+++ b/src/Umbraco.Core/Umbraco.Core.csproj
@@ -219,13 +219,35 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -389,23 +411,6 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
@@ -418,14 +423,13 @@
-
-
+
@@ -435,6 +439,7 @@
+
@@ -707,7 +712,6 @@
-
@@ -1141,30 +1145,7 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/Umbraco.Tests/Migrations/AdvancedMigrationTests.cs b/src/Umbraco.Tests/Migrations/AdvancedMigrationTests.cs
index 5ff0dcffc1..c13d141fa5 100644
--- a/src/Umbraco.Tests/Migrations/AdvancedMigrationTests.cs
+++ b/src/Umbraco.Tests/Migrations/AdvancedMigrationTests.cs
@@ -217,7 +217,11 @@ namespace Umbraco.Tests.Migrations
//Execute.DropKeysAndIndexes("umbracoUser");
// drops *all* tables keys and indexes
- Delete.KeysAndIndexes().Do();
+ var tables = SqlSyntax.GetTablesInSchema(Context.Database).ToList();
+ foreach (var table in tables)
+ Delete.KeysAndIndexes(table, false, true).Do();
+ foreach (var table in tables)
+ Delete.KeysAndIndexes(table, true, false).Do();
}
}
@@ -262,7 +266,7 @@ namespace Umbraco.Tests.Migrations
public override void Migrate()
{
// cannot delete the column without this, of course
- Delete.KeysAndIndexes().Do();
+ Delete.KeysAndIndexes("umbracoUser").Do();
Delete.Column("id").FromTable("umbracoUser").Do();
diff --git a/src/Umbraco.Tests/Migrations/MigrationPlanTests.cs b/src/Umbraco.Tests/Migrations/MigrationPlanTests.cs
index add278f9eb..ab065eb0a9 100644
--- a/src/Umbraco.Tests/Migrations/MigrationPlanTests.cs
+++ b/src/Umbraco.Tests/Migrations/MigrationPlanTests.cs
@@ -119,7 +119,7 @@ namespace Umbraco.Tests.Migrations
.To("bbb")
.From("ccc")
.To("ddd");
- Assert.Throws(() => plan.Validate());
+ Assert.Throws(() => plan.Validate());
}
[Test]
@@ -131,7 +131,7 @@ namespace Umbraco.Tests.Migrations
.To("bbb")
.To("ccc")
.To("aaa");
- Assert.Throws(() => plan.Validate());
+ Assert.Throws(() => plan.Validate());
}
[Test]
diff --git a/src/Umbraco.Web.UI.Client/lib/bootstrap/less/scaffolding.less b/src/Umbraco.Web.UI.Client/lib/bootstrap/less/scaffolding.less
index f17e8cadb4..2c01fb771c 100644
--- a/src/Umbraco.Web.UI.Client/lib/bootstrap/less/scaffolding.less
+++ b/src/Umbraco.Web.UI.Client/lib/bootstrap/less/scaffolding.less
@@ -28,6 +28,11 @@ a:focus {
color: @linkColorHover;
text-decoration: underline;
}
+a[ng-click],
+a[data-ng-click],
+a[x-ng-click] {
+ cursor: pointer;
+}
// Images
diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/application/umbsections.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/application/umbsections.directive.js
index 14c9878839..b8ee797c82 100644
--- a/src/Umbraco.Web.UI.Client/src/common/directives/components/application/umbsections.directive.js
+++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/application/umbsections.directive.js
@@ -42,7 +42,7 @@ function sectionsDirective($timeout, $window, navigationService, treeService, se
function calculateWidth() {
$timeout(function () {
//total width minus room for avatar, search, and help icon
- var windowWidth = $(window).width() - 200;
+ var windowWidth = $(window).width() - 150;
var sectionsWidth = 0;
scope.totalSections = scope.sections.length;
scope.maxSections = maxSections;
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 f7704ab870..3a874f83c6 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
@@ -67,16 +67,12 @@
//We fetch all ancestors of the node to generate the footer breadcrumb navigation
if (!$scope.page.isNew) {
if (content.parentId && content.parentId !== -1) {
- entityResource.getAncestors(content.id, "document", $scope.culture)
- .then(function (anc) {
- $scope.ancestors = anc;
- });
+ loadBreadcrumb();
$scope.$watch('culture',
function (value, oldValue) {
- entityResource.getAncestors(content.id, "document", value)
- .then(function (anc) {
- $scope.ancestors = anc;
- });
+ if (value !== oldValue) {
+ loadBreadcrumb();
+ }
});
}
}
@@ -86,6 +82,12 @@
resetVariantFlags();
}
+ function loadBreadcrumb() {
+ entityResource.getAncestors($scope.content.id, "document", $scope.culture)
+ .then(function (anc) {
+ $scope.ancestors = anc;
+ });
+ }
/**
* This will reset isDirty flags if save is true.
diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/events/events.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/events/events.directive.js
index 77f2ffb54a..eb5fd055eb 100644
--- a/src/Umbraco.Web.UI.Client/src/common/directives/components/events/events.directive.js
+++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/events/events.directive.js
@@ -101,14 +101,8 @@ angular.module('umbraco.directives')
var eventBindings = [];
function oneTimeClick(event) {
- var el = event.target.nodeName;
-
- //ignore link and button clicks
- var els = ["INPUT","A","BUTTON"];
- if(els.indexOf(el) >= 0){return;}
-
// ignore clicks on new overlay
- var parents = $(event.target).parents("a,button,.umb-overlay,.umb-tour");
+ var parents = $(event.target).parents(".umb-overlay,.umb-tour");
if(parents.length > 0){
return;
}
diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/umbgroupsbuilder.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/umbgroupsbuilder.directive.js
index da51528bd2..396699866c 100644
--- a/src/Umbraco.Web.UI.Client/src/common/directives/components/umbgroupsbuilder.directive.js
+++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/umbgroupsbuilder.directive.js
@@ -3,7 +3,7 @@
function GroupsBuilderDirective(contentTypeHelper, contentTypeResource, mediaTypeResource,
dataTypeHelper, dataTypeResource, $filter, iconHelper, $q, $timeout, notificationsService,
- localizationService, editorService, eventsService) {
+ localizationService, editorService, eventsService, overlayService) {
function link(scope, el, attr, ctrl) {
@@ -474,10 +474,11 @@
if (!property.inherited) {
var oldPropertyModel = angular.copy(property);
+ var propertyModel = angular.copy(property);
var propertySettings = {
title: "Property settings",
- property: property,
+ property: propertyModel,
contentType: scope.contentType,
contentTypeName: scope.model.name,
contentTypeAllowCultureVariant: scope.model.allowCultureVariant,
@@ -487,7 +488,25 @@
property.inherited = false;
property.dialogIsOpen = false;
-
+ property.propertyState = "active";
+
+ // apply all property changes
+ property.label = propertyModel.label;
+ property.alias = propertyModel.alias;
+ property.description = propertyModel.description;
+ property.config = propertyModel.config;
+ property.editor = propertyModel.editor;
+ property.view = propertyModel.view;
+ property.dataTypeId = propertyModel.dataTypeId;
+ property.dataTypeIcon = propertyModel.dataTypeIcon;
+ property.dataTypeName = propertyModel.dataTypeName;
+ property.validation.mandatory = propertyModel.validation.mandatory;
+ property.validation.pattern = propertyModel.validation.pattern;
+ property.showOnMemberProfile = propertyModel.showOnMemberProfile;
+ property.memberCanEdit = propertyModel.memberCanEdit;
+ property.isSensitiveValue = propertyModel.isSensitiveValue;
+ property.allowCultureVariant = propertyModel.allowCultureVariant;
+
// update existing data types
if(model.updateSameDataTypes) {
updateSameDataTypes(property);
@@ -508,43 +527,38 @@
},
close: function() {
+ if(_.isEqual(oldPropertyModel, propertyModel) === false) {
+ localizationService.localizeMany(["general_confirm", "contentTypeEditor_propertyHasChanges", "general_cancel", "general_ok"]).then(function (data) {
+ const overlay = {
+ title: data[0],
+ content: data[1],
+ closeButtonLabel: data[2],
+ submitButtonLabel: data[3],
+ submitButtonStyle: "danger",
+ close: function () {
+ overlayService.close();
+ },
+ submit: function () {
+ // close the confirmation
+ overlayService.close();
+ // close the editor
+ editorService.close();
+ }
+ };
- // reset all property changes
- property.label = oldPropertyModel.label;
- property.alias = oldPropertyModel.alias;
- property.description = oldPropertyModel.description;
- property.config = oldPropertyModel.config;
- property.editor = oldPropertyModel.editor;
- property.view = oldPropertyModel.view;
- property.dataTypeId = oldPropertyModel.dataTypeId;
- property.dataTypeIcon = oldPropertyModel.dataTypeIcon;
- property.dataTypeName = oldPropertyModel.dataTypeName;
- property.validation.mandatory = oldPropertyModel.validation.mandatory;
- property.validation.pattern = oldPropertyModel.validation.pattern;
- property.showOnMemberProfile = oldPropertyModel.showOnMemberProfile;
- property.memberCanEdit = oldPropertyModel.memberCanEdit;
- property.isSensitiveValue = oldPropertyModel.isSensitiveValue;
-
- // because we set state to active, to show a preview, we have to check if has been filled out
- // label is required so if it is not filled we know it is a placeholder
- if(oldPropertyModel.editor === undefined || oldPropertyModel.editor === null || oldPropertyModel.editor === "") {
- property.propertyState = "init";
- } else {
- property.propertyState = oldPropertyModel.propertyState;
+ overlayService.open(overlay);
+ });
+ }
+ else {
+ // remove the editor
+ editorService.close();
}
-
- // remove the editor
- editorService.close();
-
}
};
// open property settings editor
editorService.open(propertySettings);
- // set state to active to access the preview
- property.propertyState = "active";
-
// set property states
property.dialogIsOpen = true;
diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/util/noPasswordManager.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/util/noPasswordManager.directive.js
index 190c504aa6..2c52506f42 100644
--- a/src/Umbraco.Web.UI.Client/src/common/directives/util/noPasswordManager.directive.js
+++ b/src/Umbraco.Web.UI.Client/src/common/directives/util/noPasswordManager.directive.js
@@ -1,6 +1,6 @@
/**
* @ngdoc directive
-* @name umbraco.directives.directive:no-password-manager
+* @name umbraco.directives.directive:noPasswordManager
* @attribte
* @function
* @description
diff --git a/src/Umbraco.Web.UI.Client/src/common/services/contenteditinghelper.service.js b/src/Umbraco.Web.UI.Client/src/common/services/contenteditinghelper.service.js
index 1efcf84dcb..1b2be5f635 100644
--- a/src/Umbraco.Web.UI.Client/src/common/services/contenteditinghelper.service.js
+++ b/src/Umbraco.Web.UI.Client/src/common/services/contenteditinghelper.service.js
@@ -197,6 +197,8 @@ function contentEditingHelper(fileManager, $q, $location, $routeParams, notifica
letter: ch,
labelKey: "buttons_schedulePublish",
handler: args.methods.schedulePublish,
+ hotKey: "alt+shift+s",
+ hotKeyWhenHidden: true,
alias: "schedulePublish",
addEllipsis: "true"
};
@@ -207,6 +209,8 @@ function contentEditingHelper(fileManager, $q, $location, $routeParams, notifica
letter: ch,
labelKey: "buttons_publishDescendants",
handler: args.methods.publishDescendants,
+ hotKey: "alt+shift+p",
+ hotKeyWhenHidden: true,
alias: "publishDescendant",
addEllipsis: "true"
};
diff --git a/src/Umbraco.Web.UI.Client/src/common/services/menuactions.service.js b/src/Umbraco.Web.UI.Client/src/common/services/menuactions.service.js
index 57c86cba90..7856714ccd 100644
--- a/src/Umbraco.Web.UI.Client/src/common/services/menuactions.service.js
+++ b/src/Umbraco.Web.UI.Client/src/common/services/menuactions.service.js
@@ -71,7 +71,9 @@ function umbracoMenuActions(treeService, $location, navigationService, appState,
if (treeRoot && treeRoot.root) {
var treeNode = treeService.getDescendantNode(treeRoot.root, args.entity.id, args.treeAlias);
if (treeNode) {
- treeService.loadNodeChildren({ node: treeNode, section: args.section });
+ treeService.loadNodeChildren({ node: treeNode, section: args.section }).then(function () {
+ navigationService.hideMenu();
+ });
}
}
diff --git a/src/Umbraco.Web.UI.Client/src/common/services/tinymce.service.js b/src/Umbraco.Web.UI.Client/src/common/services/tinymce.service.js
index 61f96fed28..555e276485 100644
--- a/src/Umbraco.Web.UI.Client/src/common/services/tinymce.service.js
+++ b/src/Umbraco.Web.UI.Client/src/common/services/tinymce.service.js
@@ -360,7 +360,11 @@ function tinyMceService($rootScope, $q, imageHelper, $locale, $http, $timeout, s
icon: "code",
tooltip: "View Source Code",
onclick: function(){
- callback();
+ if (callback) {
+ angularHelper.safeApply($rootScope, function() {
+ callback();
+ });
+ }
}
});
diff --git a/src/Umbraco.Web.UI.Client/src/less/application/animations.less b/src/Umbraco.Web.UI.Client/src/less/application/animations.less
index 91e2213775..e081c4919a 100644
--- a/src/Umbraco.Web.UI.Client/src/less/application/animations.less
+++ b/src/Umbraco.Web.UI.Client/src/less/application/animations.less
@@ -40,10 +40,6 @@
// TREE ANIMATION
-.umb-tree-item.ng-animate {
- display: none;
-}
-
.umb-tree-item--deleted.ng-leave {
animation: leave 600ms cubic-bezier(0.445, 0.050, 0.550, 0.950);
display: block;
diff --git a/src/Umbraco.Web.UI.Client/src/less/components/application/umb-backdrop.less b/src/Umbraco.Web.UI.Client/src/less/components/application/umb-backdrop.less
index 1d9aaabd44..18e331756e 100644
--- a/src/Umbraco.Web.UI.Client/src/less/components/application/umb-backdrop.less
+++ b/src/Umbraco.Web.UI.Client/src/less/components/application/umb-backdrop.less
@@ -2,7 +2,7 @@
height: 100%;
width: 100%;
position: fixed;
- z-index: @zindexOverlayBackdrop;
+ z-index: @zindexUmbOverlay;
top: 0;
left: 0;
pointer-events: none;
diff --git a/src/Umbraco.Web.UI.Client/src/less/components/application/umb-search.less b/src/Umbraco.Web.UI.Client/src/less/components/application/umb-search.less
index a8fc9c7f8e..70e4f3d372 100644
--- a/src/Umbraco.Web.UI.Client/src/less/components/application/umb-search.less
+++ b/src/Umbraco.Web.UI.Client/src/less/components/application/umb-search.less
@@ -4,7 +4,7 @@
*/
.umb-search {
position: fixed;
- z-index: @zindexUmbOverlay;
+ z-index: @zindexSearchBox;
width: 660px;
max-width: 90%;
transform: translate(-50%, 0);
diff --git a/src/Umbraco.Web.UI.Client/src/less/components/prevalues/multivalues.less b/src/Umbraco.Web.UI.Client/src/less/components/prevalues/multivalues.less
index 0dbc4c381c..9947c793c2 100644
--- a/src/Umbraco.Web.UI.Client/src/less/components/prevalues/multivalues.less
+++ b/src/Umbraco.Web.UI.Client/src/less/components/prevalues/multivalues.less
@@ -1,5 +1,5 @@
.umb-prevalues-multivalues {
- width: 400px;
+ width: 425px;
max-width: 100%;
.umb-overlay & {
diff --git a/src/Umbraco.Web.UI.Client/src/less/components/umb-confirm-action.less b/src/Umbraco.Web.UI.Client/src/less/components/umb-confirm-action.less
index 1f0808a592..f972633bf4 100644
--- a/src/Umbraco.Web.UI.Client/src/less/components/umb-confirm-action.less
+++ b/src/Umbraco.Web.UI.Client/src/less/components/umb-confirm-action.less
@@ -102,6 +102,7 @@
border-radius: 40px;
box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.26);
font-size: 18px;
+ cursor: pointer;
}
.umb_confirm-action__overlay-action:hover {
diff --git a/src/Umbraco.Web.UI.Client/src/less/forms.less b/src/Umbraco.Web.UI.Client/src/less/forms.less
index 966fc1fb11..cfbb8b78ab 100644
--- a/src/Umbraco.Web.UI.Client/src/less/forms.less
+++ b/src/Umbraco.Web.UI.Client/src/less/forms.less
@@ -809,6 +809,7 @@ legend + .control-group {
// Labels on own row
.form-horizontal .control-label {
+ float:none;
width: 100%;
}
.form-horizontal .controls {
diff --git a/src/Umbraco.Web.UI.Client/src/less/hacks.less b/src/Umbraco.Web.UI.Client/src/less/hacks.less
index 726b3fa5ed..0b6d1b7a60 100644
--- a/src/Umbraco.Web.UI.Client/src/less/hacks.less
+++ b/src/Umbraco.Web.UI.Client/src/less/hacks.less
@@ -221,3 +221,12 @@ pre {
border: 0;
}
}
+
+/* Styling for content/media sort order dialog */
+.sort-order {
+ td.tree-icon {
+ font-size:20px;
+ width:20px;
+ padding-right:0;
+ }
+}
diff --git a/src/Umbraco.Web.UI.Client/src/less/property-editors.less b/src/Umbraco.Web.UI.Client/src/less/property-editors.less
index 435b64ad34..9e8dd37ab9 100644
--- a/src/Umbraco.Web.UI.Client/src/less/property-editors.less
+++ b/src/Umbraco.Web.UI.Client/src/less/property-editors.less
@@ -165,6 +165,8 @@
.sp-replacer {
display: inline-flex;
margin-right: 18px;
+ border: solid 1px @gray-8;
+ border-radius: 3px;
}
label {
diff --git a/src/Umbraco.Web.UI.Client/src/less/rte.less b/src/Umbraco.Web.UI.Client/src/less/rte.less
index ccf52acc53..a13dbaeb43 100644
--- a/src/Umbraco.Web.UI.Client/src/less/rte.less
+++ b/src/Umbraco.Web.UI.Client/src/less/rte.less
@@ -5,10 +5,6 @@
position: relative;
.umb-property-editor--limit-width();
-
- .-loading {
- position: absolute;
- }
}
.umb-rte .mce-tinymce {
diff --git a/src/Umbraco.Web.UI.Client/src/less/sections.less b/src/Umbraco.Web.UI.Client/src/less/sections.less
index 5a1de02617..ef6c5f5046 100644
--- a/src/Umbraco.Web.UI.Client/src/less/sections.less
+++ b/src/Umbraco.Web.UI.Client/src/less/sections.less
@@ -57,16 +57,17 @@ ul.sections>li.current>a::after {
opacity: 1;
transform: translateY(0px);
}
-ul.sections>li.current>a .section__name,
-ul.sections>li>a:hover .section__name,
-ul.sections>li>a:focus .section__name {
- opacity: 1;
+ul.sections > li.current > a .section__name,
+ul.sections > li > a:hover .section__name {
+ opacity: 1;
-webkit-font-smoothing: subpixel-antialiased;
}
-ul.sections>li>a:focus .section__name {
+ul.sections > li > a:focus .section__name {
.tabbing-active & {
- box-shadow: 0 0 2px @pinkLight, inset 0 0 2px 1px @pinkLight;
+
+ border: 1px solid;
+ border-color: @gray-9;
}
}
diff --git a/src/Umbraco.Web.UI.Client/src/less/variables.less b/src/Umbraco.Web.UI.Client/src/less/variables.less
index cc9dced7df..a1dc0ba187 100644
--- a/src/Umbraco.Web.UI.Client/src/less/variables.less
+++ b/src/Umbraco.Web.UI.Client/src/less/variables.less
@@ -426,7 +426,7 @@
@zindexFixedNavbar: 1030;
@zindexModalBackdrop: 1040;
@zindexModal: 1050;
-
+@zindexSearchBox: 8000;
@zindexUmbOverlay: 7500;
@zindexOverlayBackdrop: 2000;
diff --git a/src/Umbraco.Web.UI.Client/src/routes.js b/src/Umbraco.Web.UI.Client/src/routes.js
index 001888f3ca..e2a2cfe938 100644
--- a/src/Umbraco.Web.UI.Client/src/routes.js
+++ b/src/Umbraco.Web.UI.Client/src/routes.js
@@ -39,10 +39,14 @@ app.config(function ($routeProvider) {
$route.current.params.section = "content";
}
+ var found = _.find(user.allowedSections, function (s) {
+ return s.localeCompare($route.current.params.section, undefined, { sensitivity: 'accent' }) === 0;
+ })
+
// U4-5430, Benjamin Howarth
// We need to change the current route params if the user only has access to a single section
// To do this we need to grab the current user's allowed sections, then reject the promise with the correct path.
- if (user.allowedSections.indexOf($route.current.params.section) > -1) {
+ if (found) {
//this will resolve successfully so the route will continue
return $q.when(true);
} else {
@@ -119,7 +123,7 @@ app.config(function ($routeProvider) {
sectionService.getSectionsForUser().then(function(sections) {
//find the one we're requesting
var found = _.find(sections, function(s) {
- return s.alias === $routeParams.section;
+ return s.alias.localeCompare($routeParams.section, undefined, { sensitivity: 'accent' }) === 0;
})
if (found && found.routePath) {
//there's a custom route path so redirect
diff --git a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/linkpicker/linkpicker.controller.js b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/linkpicker/linkpicker.controller.js
index 029f765985..fb93df28f9 100644
--- a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/linkpicker/linkpicker.controller.js
+++ b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/linkpicker/linkpicker.controller.js
@@ -1,6 +1,6 @@
//used for the media picker dialog
angular.module("umbraco").controller("Umbraco.Editors.LinkPickerController",
- function ($scope, eventsService, entityResource, contentResource, mediaResource, mediaHelper, udiParser, userService, localizationService, tinyMceService, editorService) {
+ function ($scope, eventsService, entityResource, contentResource, mediaResource, mediaHelper, udiParser, userService, localizationService, tinyMceService, editorService, contentEditingHelper) {
var vm = this;
var dialogOptions = $scope.model;
@@ -94,8 +94,7 @@ angular.module("umbraco").controller("Umbraco.Editors.LinkPickerController",
options.ignoreUserStartNodes = dialogOptions.ignoreUserStartNodes;
contentResource.getById(id, options).then(function (resp) {
- $scope.anchorValues = tinyMceService.getAnchorNames(JSON.stringify(resp.properties));
- $scope.model.target.url = resp.urls[0].text;
+ handleContentTarget(resp);
});
}
} else if ($scope.model.target.url.length) {
@@ -148,8 +147,7 @@ angular.module("umbraco").controller("Umbraco.Editors.LinkPickerController",
options.ignoreUserStartNodes = dialogOptions.ignoreUserStartNodes;
contentResource.getById(args.node.id, options).then(function (resp) {
- $scope.anchorValues = tinyMceService.getAnchorNames(JSON.stringify(resp.properties));
- $scope.model.target.url = resp.urls[0].text;
+ handleContentTarget(resp);
});
}
@@ -158,6 +156,11 @@ angular.module("umbraco").controller("Umbraco.Editors.LinkPickerController",
}
}
+ function handleContentTarget(content) {
+ $scope.anchorValues = tinyMceService.getAnchorNames(JSON.stringify(contentEditingHelper.getAllProps(content.variants[0])));
+ $scope.model.target.url = content.urls.filter(item => item.culture === $scope.currentNode.metaData.culture)[0].text;
+ }
+
function nodeExpandedHandler(args) {
// open mini list view for list views
if (args.node.metaData.isContainer) {
diff --git a/src/Umbraco.Web.UI.Client/src/views/components/application/umb-app-header.html b/src/Umbraco.Web.UI.Client/src/views/components/application/umb-app-header.html
index a14e930b8a..ac919d3e41 100644
--- a/src/Umbraco.Web.UI.Client/src/views/components/application/umb-app-header.html
+++ b/src/Umbraco.Web.UI.Client/src/views/components/application/umb-app-header.html
@@ -20,7 +20,7 @@