diff --git a/src/Umbraco.Core/Persistence/Migrations/ILocalMigration.cs b/src/Umbraco.Core/Persistence/Migrations/ILocalMigration.cs index ef0d9dcbce..f06368e59f 100644 --- a/src/Umbraco.Core/Persistence/Migrations/ILocalMigration.cs +++ b/src/Umbraco.Core/Persistence/Migrations/ILocalMigration.cs @@ -2,6 +2,7 @@ using Umbraco.Core.Persistence.Migrations.Syntax.Create; using Umbraco.Core.Persistence.Migrations.Syntax.Delete; using Umbraco.Core.Persistence.Migrations.Syntax.Execute; +using Umbraco.Core.Persistence.Migrations.Syntax.Update; namespace Umbraco.Core.Persistence.Migrations { @@ -9,6 +10,7 @@ namespace Umbraco.Core.Persistence.Migrations { IExecuteBuilder Execute { get; } IDeleteBuilder Delete { get; } + IUpdateBuilder Update { get; } IAlterSyntaxBuilder Alter { get; } ICreateBuilder Create { get; } string GetSql(); diff --git a/src/Umbraco.Core/Persistence/Migrations/Initial/BaseDataCreation.cs b/src/Umbraco.Core/Persistence/Migrations/Initial/BaseDataCreation.cs index 13fc723553..accd8379ca 100644 --- a/src/Umbraco.Core/Persistence/Migrations/Initial/BaseDataCreation.cs +++ b/src/Umbraco.Core/Persistence/Migrations/Initial/BaseDataCreation.cs @@ -49,14 +49,19 @@ namespace Umbraco.Core.Persistence.Migrations.Initial CreateUmbracoUserData(); } - if (tableName.Equals("umbracoUserType")) + if (tableName.Equals("umbracoUserGroup")) { - CreateUmbracoUserTypeData(); + CreateUmbracoUserGroupData(); } - if (tableName.Equals("umbracoUser2app")) + if (tableName.Equals("umbracoUser2UserGroup")) { - CreateUmbracoUser2AppData(); + CreateUmbracoUser2UserGroupData(); + } + + if (tableName.Equals("umbracoUserGroup2App")) + { + CreateUmbracoUserGroup2AppData(); } if (tableName.Equals("cmsPropertyTypeGroup")) @@ -172,27 +177,34 @@ namespace Umbraco.Core.Persistence.Migrations.Initial private void CreateUmbracoUserData() { - _database.Insert("umbracoUser", "id", false, new UserDto { Id = 0, Disabled = false, NoConsole = false, Type = 1, ContentStartId = -1, MediaStartId = -1, UserName = "Administrator", Login = "admin", Password = "default", Email = "", UserLanguage = "en" }); - //_database.Update("SET id = @IdAfter WHERE id = @IdBefore AND userLogin = @Login", new { IdAfter = 0, IdBefore = 1, Login = "admin" }); + _database.Insert("umbracoUser", "id", false, new UserDto { Id = 0, Disabled = false, NoConsole = false, UserName = "Administrator", Login = "admin", Password = "default", Email = "", UserLanguage = "en", CreateDate = DateTime.Now, UpdateDate = DateTime.Now }); } - private void CreateUmbracoUserTypeData() + private void CreateUmbracoUserGroupData() { - _database.Insert("umbracoUserType", "id", false, new UserTypeDto { Id = 1, Alias = "admin", Name = "Administrators", DefaultPermissions = "CADMOSKTPIURZ:5F7" }); - _database.Insert("umbracoUserType", "id", false, new UserTypeDto { Id = 2, Alias = "writer", Name = "Writer", DefaultPermissions = "CAH:F" }); - _database.Insert("umbracoUserType", "id", false, new UserTypeDto { Id = 3, Alias = "editor", Name = "Editors", DefaultPermissions = "CADMOSKTPUZ:5F" }); - _database.Insert("umbracoUserType", "id", false, new UserTypeDto { Id = 4, Alias = "translator", Name = "Translator", DefaultPermissions = "AF" }); + _database.Insert("umbracoUserGroup", "id", false, new UserGroupDto { Id = 1, StartMediaId = -1, StartContentId = -1, Alias = Constants.Security.AdminGroupAlias, Name = "Administrators", DefaultPermissions = "CADMOSKTPIURZ:5F7ï", CreateDate = DateTime.Now, UpdateDate = DateTime.Now, Icon = "icon-medal" }); + _database.Insert("umbracoUserGroup", "id", false, new UserGroupDto { Id = 2, StartMediaId = -1, StartContentId = -1, Alias = "writer", Name = "Writers", DefaultPermissions = "CAH:F", CreateDate = DateTime.Now, UpdateDate = DateTime.Now, Icon = "icon-edit" }); + _database.Insert("umbracoUserGroup", "id", false, new UserGroupDto { Id = 3, StartMediaId = -1, StartContentId = -1, Alias = "editor", Name = "Editors", DefaultPermissions = "CADMOSKTPUZ:5Fï", CreateDate = DateTime.Now, UpdateDate = DateTime.Now, Icon = "icon-tools" }); + _database.Insert("umbracoUserGroup", "id", false, new UserGroupDto { Id = 4, StartMediaId = -1, StartContentId = -1, Alias = "translator", Name = "Translators", DefaultPermissions = "AF", CreateDate = DateTime.Now, UpdateDate = DateTime.Now, Icon = "icon-globe" }); } - private void CreateUmbracoUser2AppData() + private void CreateUmbracoUser2UserGroupData() { - _database.Insert("umbracoUser2app", "user", false, new User2AppDto { UserId = 0, AppAlias = Constants.Applications.Content }); - _database.Insert("umbracoUser2app", "user", false, new User2AppDto { UserId = 0, AppAlias = Constants.Applications.Developer }); - _database.Insert("umbracoUser2app", "user", false, new User2AppDto { UserId = 0, AppAlias = Constants.Applications.Media }); - _database.Insert("umbracoUser2app", "user", false, new User2AppDto { UserId = 0, AppAlias = Constants.Applications.Members }); - _database.Insert("umbracoUser2app", "user", false, new User2AppDto { UserId = 0, AppAlias = Constants.Applications.Settings }); - _database.Insert("umbracoUser2app", "user", false, new User2AppDto { UserId = 0, AppAlias = Constants.Applications.Users }); - _database.Insert("umbracoUser2app", "user", false, new User2AppDto { UserId = 0, AppAlias = Constants.Applications.Forms }); + _database.Insert(new User2UserGroupDto { UserGroupId = 1, UserId = 0 }); + } + + private void CreateUmbracoUserGroup2AppData() + { + _database.Insert(new UserGroup2AppDto { UserGroupId = 1, AppAlias = Constants.Applications.Content }); + _database.Insert(new UserGroup2AppDto { UserGroupId = 1, AppAlias = Constants.Applications.Media }); + _database.Insert(new UserGroup2AppDto { UserGroupId = 1, AppAlias = Constants.Applications.Settings }); + _database.Insert(new UserGroup2AppDto { UserGroupId = 1, AppAlias = Constants.Applications.Developer }); + _database.Insert(new UserGroup2AppDto { UserGroupId = 1, AppAlias = Constants.Applications.Users }); + _database.Insert(new UserGroup2AppDto { UserGroupId = 1, AppAlias = Constants.Applications.Members }); + _database.Insert(new UserGroup2AppDto { UserGroupId = 2, AppAlias = Constants.Applications.Content }); + _database.Insert(new UserGroup2AppDto { UserGroupId = 3, AppAlias = Constants.Applications.Content }); + _database.Insert(new UserGroup2AppDto { UserGroupId = 3, AppAlias = Constants.Applications.Media }); + _database.Insert(new UserGroup2AppDto { UserGroupId = 4, AppAlias = Constants.Applications.Translation }); _database.Insert("umbracoUser2app", "user", false, new User2AppDto { UserId = 0, AppAlias = Constants.Applications.Translation }); } diff --git a/src/Umbraco.Core/Persistence/Migrations/Initial/DatabaseSchemaCreation.cs b/src/Umbraco.Core/Persistence/Migrations/Initial/DatabaseSchemaCreation.cs index 57057c97ab..e5f476772c 100644 --- a/src/Umbraco.Core/Persistence/Migrations/Initial/DatabaseSchemaCreation.cs +++ b/src/Umbraco.Core/Persistence/Migrations/Initial/DatabaseSchemaCreation.cs @@ -71,15 +71,15 @@ namespace Umbraco.Core.Persistence.Migrations.Initial {29, typeof (TagRelationshipDto)}, //removed: {30... - {31, typeof (UserTypeDto)}, + //removed in 7.6: {31, typeof (UserTypeDto)}, {32, typeof (UserDto)}, {33, typeof (TaskTypeDto)}, {34, typeof (TaskDto)}, {35, typeof (ContentType2ContentTypeDto)}, {36, typeof (ContentTypeAllowedContentTypeDto)}, - {37, typeof (User2AppDto)}, + //removed in 7.6: {37, typeof (User2AppDto)}, {38, typeof (User2NodeNotifyDto)}, - {39, typeof (User2NodePermissionDto)}, + //removed in 7.6: {39, typeof (User2NodePermissionDto)}, {40, typeof (ServerRegistrationDto)}, {41, typeof (AccessDto)}, @@ -92,7 +92,12 @@ namespace Umbraco.Core.Persistence.Migrations.Initial {48, typeof (RedirectUrlDto) }, {49, typeof (LockDto) }, - {50, typeof (ContentNuDto) } + {50, typeof (UserGroupDto) }, + {51, typeof (User2UserGroupDto) }, + {52, typeof (UserGroup2NodePermissionDto) }, + {53, typeof (UserGroup2AppDto) }, + {54, typeof (UserStartNodeDto) }, + {55, typeof (ContentNuDto) } }; #endregion diff --git a/src/Umbraco.Core/Persistence/Migrations/Initial/DatabaseSchemaResult.cs b/src/Umbraco.Core/Persistence/Migrations/Initial/DatabaseSchemaResult.cs index 7e439c6dcd..a2bfd0e443 100644 --- a/src/Umbraco.Core/Persistence/Migrations/Initial/DatabaseSchemaResult.cs +++ b/src/Umbraco.Core/Persistence/Migrations/Initial/DatabaseSchemaResult.cs @@ -150,6 +150,12 @@ namespace Umbraco.Core.Persistence.Migrations.Initial return new Version(7, 5, 0); } + //if the error is for umbracoUserGroup it must be the previous version to 7.7 since that is when it is added + if (Errors.Any(x => x.Item1.Equals("Table") && (x.Item2.InvariantEquals("umbracoUserStartNode")))) + { + return new Version(7, 6, 0); + } + return UmbracoVersion.Current; } diff --git a/src/Umbraco.Core/Persistence/Migrations/LocalMigration.cs b/src/Umbraco.Core/Persistence/Migrations/LocalMigration.cs index c6509c1a3b..a3e34e0ed1 100644 --- a/src/Umbraco.Core/Persistence/Migrations/LocalMigration.cs +++ b/src/Umbraco.Core/Persistence/Migrations/LocalMigration.cs @@ -5,6 +5,7 @@ using Umbraco.Core.Persistence.Migrations.Syntax.Alter; using Umbraco.Core.Persistence.Migrations.Syntax.Create; using Umbraco.Core.Persistence.Migrations.Syntax.Delete; using Umbraco.Core.Persistence.Migrations.Syntax.Execute; +using Umbraco.Core.Persistence.Migrations.Syntax.Update; namespace Umbraco.Core.Persistence.Migrations { @@ -18,6 +19,8 @@ namespace Umbraco.Core.Persistence.Migrations public IDeleteBuilder Delete => new DeleteBuilder(this); + public IUpdateBuilder Update => new UpdateBuilder(this); + public IAlterSyntaxBuilder Alter => new AlterSyntaxBuilder(this); public ICreateBuilder Create => new CreateBuilder(this); diff --git a/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionFourNineZero/RemoveUmbracoAppConstraints.cs b/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionFourNineZero/RemoveUmbracoAppConstraints.cs deleted file mode 100644 index a2adbd863a..0000000000 --- a/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionFourNineZero/RemoveUmbracoAppConstraints.cs +++ /dev/null @@ -1,55 +0,0 @@ -using System.Data; -using System.Linq; -using Umbraco.Core.Configuration; -using Umbraco.Core.Persistence.SqlSyntax; - -namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionFourNineZero -{ - [MigrationAttribute("4.9.0", 0, Constants.System.UmbracoMigrationName)] - public class RemoveUmbracoAppConstraints : MigrationBase - { - public RemoveUmbracoAppConstraints(IMigrationContext context) - : base(context) - { } - - - public override void Up() - { - //This will work on mysql and should work on mssql however the old keys were not named consistently with how the keys are - // structured now. So we need to do a check and manually remove them based on their old aliases. - - if (DatabaseType.IsMySql()) - { - Delete.ForeignKey().FromTable("umbracoUser2app").ForeignColumn("app").ToTable("umbracoApp").PrimaryColumn("appAlias"); - Delete.ForeignKey().FromTable("umbracoAppTree").ForeignColumn("appAlias").ToTable("umbracoApp").PrimaryColumn("appAlias"); - } - else - { - //These are the old aliases, before removing them, check they exist - var constraints = SqlSyntax.GetConstraintsPerColumn(Context.Database).Distinct().ToArray(); - - if (constraints.Any(x => x.Item1.InvariantEquals("umbracoUser2app") && x.Item3.InvariantEquals("FK_umbracoUser2app_umbracoApp"))) - { - Delete.ForeignKey("FK_umbracoUser2app_umbracoApp").OnTable("umbracoUser2app"); - //name this migration, this is a hack for DeleteAppTables to ensure it's not executed twice - ((MigrationExpressionBase)Context.Expressions.Last()).Name = "FK_umbracoUser2app_umbracoApp"; - } - if (constraints.Any(x => x.Item1.InvariantEquals("umbracoUser2app") && x.Item3.InvariantEquals("FK_umbracoUser2app_umbracoUser"))) - { - Delete.ForeignKey("FK_umbracoUser2app_umbracoUser").OnTable("umbracoUser2app"); - } - - } - - } - - public override void Down() - { - Create.ForeignKey("FK_umbracoUser2app_umbracoApp").FromTable("umbracoUser2app").ForeignColumn("app") - .ToTable("umbracoApp").PrimaryColumn("appAlias").OnDeleteOrUpdate(Rule.None); - - Create.ForeignKey("FK_umbracoAppTree_umbracoApp").FromTable("umbracoAppTree").ForeignColumn("appAlias") - .ToTable("umbracoApp").PrimaryColumn("appAlias").OnDeleteOrUpdate(Rule.None); - } - } -} diff --git a/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionFourOneZero/AddPreviewXmlTable.cs b/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionFourOneZero/AddPreviewXmlTable.cs deleted file mode 100644 index 161f5780a6..0000000000 --- a/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionFourOneZero/AddPreviewXmlTable.cs +++ /dev/null @@ -1,31 +0,0 @@ -using System.Linq; -using Umbraco.Core.Configuration; -using Umbraco.Core.Persistence.SqlSyntax; - -namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionFourOneZero -{ - [Migration("4.1.0", 0, Constants.System.UmbracoMigrationName)] - public class AddPreviewXmlTable : MigrationBase - { - public AddPreviewXmlTable(IMigrationContext context) - : base(context) - { - } - - public override void Up() - { - var tableName = "cmsPreviewXml"; - var tables = SqlSyntax.GetTablesInSchema(Context.Database).ToArray(); - if (tables.InvariantContains(tableName)) return; - - Create.Table(tableName) - .WithColumn("nodeId").AsInt32().NotNullable() - .WithColumn("versionId").AsGuid().NotNullable() - .WithColumn("timestamp").AsDateTime().NotNullable() - .WithColumn("xml").AsString(); - } - - public override void Down() - { } - } -} diff --git a/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSevenThreeZero/AddRelationTypeForDocumentOnDelete.cs b/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSevenThreeZero/AddRelationTypeForDocumentOnDelete.cs index 5bd94ce016..8a8bbc068c 100644 --- a/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSevenThreeZero/AddRelationTypeForDocumentOnDelete.cs +++ b/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSevenThreeZero/AddRelationTypeForDocumentOnDelete.cs @@ -1,6 +1,7 @@ using System; using Umbraco.Core.Configuration; using Umbraco.Core.Models.Rdbms; +using Umbraco.Core.Persistence.DatabaseAnnotations; using Umbraco.Core.Persistence.SqlSyntax; namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSevenThreeZero @@ -14,7 +15,7 @@ namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSevenThreeZe public override void Up() { - var exists = Context.Database.FirstOrDefault("WHERE alias=@alias", new {alias = Constants.Conventions.RelationTypes.RelateParentDocumentOnDeleteAlias}); + var exists = Context.Database.FirstOrDefault("WHERE alias=@alias", new {alias = Constants.Conventions.RelationTypes.RelateParentDocumentOnDeleteAlias}); if (exists == null) { Insert.IntoTable("umbracoRelationType").Row(new @@ -26,13 +27,42 @@ namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSevenThreeZe alias = Constants.Conventions.RelationTypes.RelateParentDocumentOnDeleteAlias }); } - - - } public override void Down() + { } + + // need to capture the DTO as it is modified in later migrations + + [TableName("umbracoRelationType")] + [PrimaryKey("id")] + [ExplicitColumns] + internal class RelationTypeDtoCapture { + public const int NodeIdSeed = 3; + + [Column("id")] + [PrimaryKeyColumn(IdentitySeed = NodeIdSeed)] + public int Id { get; set; } + + [Column("dual")] + public bool Dual { get; set; } + + [Column("parentObjectType")] + public Guid ParentObjectType { get; set; } + + [Column("childObjectType")] + public Guid ChildObjectType { get; set; } + + [Column("name")] + [Index(IndexTypes.UniqueNonClustered, Name = "IX_umbracoRelationType_name")] + public string Name { get; set; } + + [Column("alias")] + [NullSetting(NullSetting = NullSettings.Null)] + [Length(100)] + [Index(IndexTypes.UniqueNonClustered, Name = "IX_umbracoRelationType_alias")] + public string Alias { get; set; } } } } diff --git a/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSevenThreeZero/UpdateUniqueIdToHaveCorrectIndexType.cs b/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSevenThreeZero/UpdateUniqueIdToHaveCorrectIndexType.cs index e3a3ce931f..d7023ec5df 100644 --- a/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSevenThreeZero/UpdateUniqueIdToHaveCorrectIndexType.cs +++ b/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSevenThreeZero/UpdateUniqueIdToHaveCorrectIndexType.cs @@ -1,5 +1,4 @@ using System.Linq; -using Umbraco.Core.Configuration; using Umbraco.Core.Persistence.DatabaseModelDefinitions; using Umbraco.Core.Persistence.SqlSyntax; @@ -14,12 +13,9 @@ namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSevenThreeZe : base(context) { } - public override void Up() { - - - var dbIndexes = SqlSyntax.GetDefinedIndexes(Context.Database) + var indexes = SqlSyntax.GetDefinedIndexes(Context.Database) .Select(x => new DbIndexDefinition() { TableName = x.Item1, @@ -28,24 +24,19 @@ namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSevenThreeZe IsUnique = x.Item4 }).ToArray(); - //must be non-nullable + // drop the index if it exists + if (indexes.Any(x => x.IndexName.InvariantEquals("IX_umbracoNodeUniqueID"))) + Delete.Index("IX_umbracoNodeUniqueID").OnTable("umbracoNode"); + + // set uniqueID to be non-nullable + // the index *must* be dropped else 'one or more objects access this column' exception Alter.Table("umbracoNode").AlterColumn("uniqueID").AsGuid().NotNullable(); - //make sure it already exists - if (dbIndexes.Any(x => x.IndexName.InvariantEquals("IX_umbracoNodeUniqueID"))) - { - Delete.Index("IX_umbracoNodeUniqueID").OnTable("umbracoNode"); - } - //make sure it doesn't already exist - if (dbIndexes.Any(x => x.IndexName.InvariantEquals("IX_umbracoNode_uniqueID")) == false) - { - //must be a uniqe index - Create.Index("IX_umbracoNode_uniqueID").OnTable("umbracoNode").OnColumn("uniqueID").Unique(); - } + // create the index + Create.Index("IX_umbracoNode_uniqueID").OnTable("umbracoNode").OnColumn("uniqueID").Unique(); } public override void Down() - { - } + { } } } diff --git a/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSix/DeleteAppTables.cs b/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSix/DeleteAppTables.cs deleted file mode 100644 index f67f7d7d3e..0000000000 --- a/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSix/DeleteAppTables.cs +++ /dev/null @@ -1,55 +0,0 @@ -using System.Linq; -using Umbraco.Core.Configuration; -using Umbraco.Core.Logging; -using Umbraco.Core.Persistence.SqlSyntax; - -namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSix -{ - - [Migration("6.0.0", 10, Constants.System.UmbracoMigrationName)] - public class DeleteAppTables : MigrationBase - { - public DeleteAppTables(IMigrationContext context) - : base(context) - { } - - - public override void Up() - { - Delete.Table("umbracoAppTree"); - - //NOTE: this is a hack since old umbraco versions might not have had their db's upgraded correctly so they are all quite inconsistent. - // This is actually done in migration: RemoveUmbracoAppConstraints to target 4.9.0 but we've found with some db's that are currently at 4.9.1, - // these upgrades did not run. So, now we not only have to check if these constraints exist, but we also have to check if the RemoveUmbracoAppConstraints - // has executed since we cannot drop the same foreign key twice or we'll get errors. - - //Here we'll do a dirty check to see if RemoveUmbracoAppConstraints has executed - if (Context.Expressions.Any(x => - { - var b = x as MigrationExpressionBase; - if (b == null) return false; - return b.Name == "FK_umbracoUser2app_umbracoApp"; - }) == false) - { - //These are the old aliases, before removing them, check they exist - var constraints = SqlSyntax.GetConstraintsPerColumn(Context.Database).Distinct().ToArray(); - if (constraints.Any(x => x.Item1.InvariantEquals("umbracoUser2app") && x.Item3.InvariantEquals("FK_umbracoUser2app_umbracoApp"))) - { - Delete.ForeignKey("FK_umbracoUser2app_umbracoApp").OnTable("umbracoUser2app"); - } - if (constraints.Any(x => x.Item1.InvariantEquals("umbracoUser2app") && x.Item3.InvariantEquals("FK_umbracoUser2app_umbracoUser"))) - { - Delete.ForeignKey("FK_umbracoUser2app_umbracoUser").OnTable("umbracoUser2app"); - } - } - - Delete.Table("umbracoApp"); - } - - public override void Down() - { - //This cannot be rolled back!! - throw new DataLossException("Cannot rollback migration " + typeof(DeleteAppTables) + " the db tables umbracoAppTree and umbracoApp have been droppped"); - } - } -} diff --git a/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSix/EnsureAppsTreesUpdated.cs b/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSix/EnsureAppsTreesUpdated.cs deleted file mode 100644 index cb949d8bfc..0000000000 --- a/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSix/EnsureAppsTreesUpdated.cs +++ /dev/null @@ -1,32 +0,0 @@ -using System; -using Umbraco.Core.Configuration; -using Umbraco.Core.Logging; -using Umbraco.Core.Persistence.SqlSyntax; - -namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSix -{ - [Migration("6.0.0", 9, Constants.System.UmbracoMigrationName)] - public class EnsureAppsTreesUpdated : MigrationBase - { - public EnsureAppsTreesUpdated(IMigrationContext context) - : base(context) - { } - - - public override void Up() - { - var e = new UpgradingEventArgs(); - - if (Upgrading != null) - Upgrading(this, e); - } - - public override void Down() - { - } - - public static event EventHandler Upgrading; - - public class UpgradingEventArgs : EventArgs { } - } -} diff --git a/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSix/MoveMasterContentTypeData.cs b/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSix/MoveMasterContentTypeData.cs deleted file mode 100644 index cd8112910b..0000000000 --- a/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSix/MoveMasterContentTypeData.cs +++ /dev/null @@ -1,36 +0,0 @@ -using Umbraco.Core.Configuration; -using Umbraco.Core.Logging; -using Umbraco.Core.Persistence.SqlSyntax; - -namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSix -{ - [Migration("6.0.0", 5, Constants.System.UmbracoMigrationName)] - public class MoveMasterContentTypeData : MigrationBase - { - public MoveMasterContentTypeData(IMigrationContext context) - : base(context) - { } - - - public override void Up() - { - //Reading entries from the cmsContentType table in order to update the parentID on the umbracoNode table. - //NOTE This is primarily done because of a shortcoming in sql ce, which has really bad support for updates (can't use FROM or subqueries with multiple results). - if (base.Context != null && base.Context.Database != null) - { - var list = base.Context.Database.Fetch("SELECT nodeId, masterContentType FROM cmsContentType WHERE not masterContentType is null AND masterContentType != 0"); - foreach (var item in list) - { - Update.Table("umbracoNode").Set(new { parentID = item.masterContentType }).Where(new { id = item.nodeId }); - } - } - - Execute.Sql( - "INSERT INTO cmsContentType2ContentType (parentContentTypeId, childContentTypeId) SELECT masterContentType, nodeId FROM cmsContentType WHERE not masterContentType is null and masterContentType != 0"); - } - - public override void Down() - { - } - } -} diff --git a/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSix/NewCmsContentType2ContentTypeTable.cs b/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSix/NewCmsContentType2ContentTypeTable.cs deleted file mode 100644 index d1f7732755..0000000000 --- a/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSix/NewCmsContentType2ContentTypeTable.cs +++ /dev/null @@ -1,33 +0,0 @@ -using Umbraco.Core.Configuration; -using Umbraco.Core.Logging; -using Umbraco.Core.Persistence.SqlSyntax; - -namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSix -{ - [Migration("6.0.0", 4, Constants.System.UmbracoMigrationName)] - public class NewCmsContentType2ContentTypeTable : MigrationBase - { - public NewCmsContentType2ContentTypeTable(IMigrationContext context) - : base(context) - { } - - - public override void Up() - { - Create.Table("cmsContentType2ContentType") - .WithColumn("parentContentTypeId").AsInt16().NotNullable() - .WithColumn("childContentTypeId").AsInt16().NotNullable(); - - Create.PrimaryKey("PK_cmsContentType2ContentType") - .OnTable("cmsContentType2ContentType") - .Columns(new[] { "parentContentTypeId", "childContentTypeId" }); - } - - public override void Down() - { - Delete.PrimaryKey("PK_cmsContentType2ContentType").FromTable("cmsContentType2ContentType"); - - Delete.Table("cmsContentType2ContentType"); - } - } -} diff --git a/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSix/RemoveMasterContentTypeColumn.cs b/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSix/RemoveMasterContentTypeColumn.cs deleted file mode 100644 index 4d46d7708b..0000000000 --- a/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSix/RemoveMasterContentTypeColumn.cs +++ /dev/null @@ -1,31 +0,0 @@ -using NPoco; -using Umbraco.Core.Configuration; -using Umbraco.Core.Logging; -using Umbraco.Core.Persistence.SqlSyntax; - -namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSix -{ - [Migration("6.0.0", 6, Constants.System.UmbracoMigrationName)] - public class RemoveMasterContentTypeColumn : MigrationBase - { - public RemoveMasterContentTypeColumn(IMigrationContext context) - : base(context) - { } - - public override void Up() - { - //NOTE Don't think we can remove this column yet as it seems to be used by some starterkits - IfDatabase(DatabaseType.SQLCe, DatabaseType.SqlServer2008) - .Delete.DefaultConstraint().OnTable("cmsContentType").OnColumn("masterContentType"); - - Delete.Column("masterContentType").FromTable("cmsContentType"); - } - - public override void Down() - { - Create.UniqueConstraint("DF_cmsContentType_masterContentType").OnTable("cmsContentType").Column("masterContentType"); - - Create.Column("masterContentType").OnTable("cmsContentType").AsInt16().Nullable().WithDefaultValue(0); - } - } -} diff --git a/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSix/RenameCmsTabTable.cs b/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSix/RenameCmsTabTable.cs deleted file mode 100644 index 980a0ce63d..0000000000 --- a/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSix/RenameCmsTabTable.cs +++ /dev/null @@ -1,25 +0,0 @@ -using Umbraco.Core.Configuration; -using Umbraco.Core.Logging; -using Umbraco.Core.Persistence.SqlSyntax; - -namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSix -{ - [Migration("6.0.0", 0, Constants.System.UmbracoMigrationName)] - public class RenameCmsTabTable : MigrationBase - { - public RenameCmsTabTable(IMigrationContext context) - : base(context) - { } - - - public override void Up() - { - Rename.Table("cmsTab").To("cmsPropertyTypeGroup"); - } - - public override void Down() - { - Rename.Table("cmsPropertyTypeGroup").To("cmsTab"); - } - } -} diff --git a/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSix/RenameTabIdColumn.cs b/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSix/RenameTabIdColumn.cs deleted file mode 100644 index dc84c065c9..0000000000 --- a/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSix/RenameTabIdColumn.cs +++ /dev/null @@ -1,82 +0,0 @@ -using System.Data; -using NPoco; -using Umbraco.Core.Configuration; -using Umbraco.Core.Logging; -using Umbraco.Core.Persistence.SqlSyntax; - -namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSix -{ - [Migration("6.0.0", 7, Constants.System.UmbracoMigrationName)] - public class RenameTabIdColumn : MigrationBase - { - public RenameTabIdColumn(IMigrationContext context) - : base(context) - { } - - public override void Up() - { - //Conditional Create-column for Sql Ce databases - IfDatabase(DatabaseType.SQLCe) - .Create.Column("propertyTypeGroupId").OnTable("cmsPropertyType").AsInt16().Nullable(); - - //Conditional Create-foreign for Sql Ce databases - IfDatabase(DatabaseType.SQLCe) - .Create.ForeignKey("FK_cmsPropertyType_cmsPropertyTypeGroup") - .FromTable("cmsPropertyType").ForeignColumn("propertyTypeGroupId") - .ToTable("cmsPropertyTypeGroup").PrimaryColumn("id").OnDeleteOrUpdate(Rule.None); - - //Conditional Delete-foreignkey for MySql databases - IfDatabase(DatabaseType.MySQL) - .Delete.ForeignKey().FromTable("cmsPropertyType").ForeignColumn("tabId").ToTable("cmsPropertyTypeGroup").PrimaryColumn("id"); - - Rename.Column("tabId").OnTable("cmsPropertyType").To("propertyTypeGroupId"); - - //Conditional Create-foreign for MySql databases - IfDatabase(DatabaseType.MySQL) - .Create.ForeignKey("FK_cmsPropertyType_cmsPropertyTypeGroup") - .FromTable("cmsPropertyType").ForeignColumn("propertyTypeGroupId") - .ToTable("cmsPropertyTypeGroup").PrimaryColumn("id").OnDeleteOrUpdate(Rule.None); - - //Conditional Delete-foreignkey for Sql Ce databases - IfDatabase(DatabaseType.SQLCe) - .Delete.ForeignKey("FK_cmsPropertyType_cmsTab").OnTable("cmsPropertyType"); - - //Conditional Delete-column for Sql Ce databases - IfDatabase(DatabaseType.SQLCe) - .Delete.Column("tabId").FromTable("cmsPropertyType"); - } - - public override void Down() - { - //Conditional Create-column for Sql Ce databases - IfDatabase(DatabaseType.SQLCe) - .Create.Column("tabId").OnTable("cmsPropertyType").AsInt16().Nullable(); - - //Conditional Create-foreign for Sql Ce databases - IfDatabase(DatabaseType.SQLCe) - .Create.ForeignKey("FK_cmsPropertyType_cmsTab") - .FromTable("cmsPropertyType").ForeignColumn("tabId") - .ToTable("cmsTab").PrimaryColumn("id").OnDeleteOrUpdate(Rule.None); - - //Conditional Delete-foreignkey for MySql databases - IfDatabase(DatabaseType.MySQL) - .Delete.ForeignKey().FromTable("cmsPropertyType").ForeignColumn("propertyTypeGroupId").ToTable("cmsPropertyTypeGroup").PrimaryColumn("id"); - - Rename.Column("propertyTypeGroupId").OnTable("cmsPropertyType").To("tabId"); - - //Conditional Create-foreign for MySql databases - IfDatabase(DatabaseType.MySQL) - .Create.ForeignKey("FK_cmsPropertyType_cmsPropertyTypeGroup") - .FromTable("cmsPropertyType").ForeignColumn("tabId") - .ToTable("cmsPropertyTypeGroup").PrimaryColumn("id").OnDeleteOrUpdate(Rule.None); - - //Conditional Delete-foreignkey for Sql Ce databases - IfDatabase(DatabaseType.SQLCe) - .Delete.ForeignKey("FK_cmsPropertyType_cmsPropertyTypeGroup").OnTable("cmsPropertyType"); - - //Conditional Delete-column for Sql Ce databases - IfDatabase(DatabaseType.SQLCe) - .Delete.Column("propertyTypeGroupId").FromTable("propertyTypeGroupId"); - } - } -} diff --git a/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSix/UpdateCmsContentTypeAllowedContentTypeTable.cs b/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSix/UpdateCmsContentTypeAllowedContentTypeTable.cs deleted file mode 100644 index 7c837f5dfe..0000000000 --- a/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSix/UpdateCmsContentTypeAllowedContentTypeTable.cs +++ /dev/null @@ -1,25 +0,0 @@ -using Umbraco.Core.Configuration; -using Umbraco.Core.Logging; -using Umbraco.Core.Persistence.SqlSyntax; - -namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSix -{ - [Migration("6.0.0", 3, Constants.System.UmbracoMigrationName)] - public class UpdateCmsContentTypeAllowedContentTypeTable : MigrationBase - { - public UpdateCmsContentTypeAllowedContentTypeTable(IMigrationContext context) - : base(context) - { } - - - public override void Up() - { - Alter.Table("cmsContentTypeAllowedContentType").AddColumn("sortOrder").AsInt16().NotNullable().WithDefaultValue(1); - } - - public override void Down() - { - Delete.Column("sortOrder").FromTable("cmsContentTypeAllowedContentType"); - } - } -} diff --git a/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSix/UpdateCmsContentTypeTable.cs b/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSix/UpdateCmsContentTypeTable.cs deleted file mode 100644 index 3b79dd0294..0000000000 --- a/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSix/UpdateCmsContentTypeTable.cs +++ /dev/null @@ -1,31 +0,0 @@ -using System.Linq; -using Umbraco.Core.Configuration; -using Umbraco.Core.Logging; -using Umbraco.Core.Persistence.DatabaseModelDefinitions; -using Umbraco.Core.Persistence.SqlSyntax; - -namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSix -{ - [Migration("6.0.0", 2, Constants.System.UmbracoMigrationName)] - public class UpdateCmsContentTypeTable : MigrationBase - { - public UpdateCmsContentTypeTable(IMigrationContext context) - : base(context) - { } - - - public override void Up() - { - Alter.Table("cmsContentType").AddColumn("isContainer").AsBoolean().NotNullable().WithDefaultValue(0); - - Alter.Table("cmsContentType").AddColumn("allowAtRoot").AsBoolean().NotNullable().WithDefaultValue(0); - } - - public override void Down() - { - Delete.Column("allowAtRoot").FromTable("cmsContentType"); - - Delete.Column("isContainer").FromTable("cmsContentType"); - } - } -} diff --git a/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSix/UpdateCmsContentVersionTable.cs b/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSix/UpdateCmsContentVersionTable.cs deleted file mode 100644 index 892531d0c0..0000000000 --- a/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSix/UpdateCmsContentVersionTable.cs +++ /dev/null @@ -1,25 +0,0 @@ -using Umbraco.Core.Configuration; -using Umbraco.Core.Logging; -using Umbraco.Core.Persistence.SqlSyntax; - -namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSix -{ - [Migration("6.0.0", 8, Constants.System.UmbracoMigrationName)] - public class UpdateCmsContentVersionTable : MigrationBase - { - public UpdateCmsContentVersionTable(IMigrationContext context) - : base(context) - { } - - - public override void Up() - { - Alter.Table("cmsContentVersion").AddColumn("LanguageLocale").AsString(10).Nullable(); - } - - public override void Down() - { - Delete.Column("LanguageLocale").FromTable("cmsContentVersion"); - } - } -} diff --git a/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSix/UpdateCmsPropertyTypeGroupTable.cs b/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSix/UpdateCmsPropertyTypeGroupTable.cs deleted file mode 100644 index 73986f3c0e..0000000000 --- a/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSix/UpdateCmsPropertyTypeGroupTable.cs +++ /dev/null @@ -1,32 +0,0 @@ -using System.Data; -using Umbraco.Core.Configuration; -using Umbraco.Core.Logging; -using Umbraco.Core.Persistence.SqlSyntax; - -namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSix -{ - [Migration("6.0.0", 1, Constants.System.UmbracoMigrationName)] - public class UpdateCmsPropertyTypeGroupTable : MigrationBase - { - public UpdateCmsPropertyTypeGroupTable(IMigrationContext context) - : base(context) - { } - - - public override void Up() - { - Alter.Table("cmsPropertyTypeGroup").AddColumn("parentGroupId").AsInt16().Nullable(); - - Create.ForeignKey("FK_cmsPropertyTypeGroup_cmsPropertyTypeGroup_id") - .FromTable("cmsPropertyTypeGroup").ForeignColumn("parentGroupId") - .ToTable("cmsPropertyTypeGroup").PrimaryColumn("id").OnDeleteOrUpdate(Rule.None); - } - - public override void Down() - { - Delete.ForeignKey().FromTable("cmsPropertyTypeGroup").ForeignColumn("parentGroupId").ToTable("cmsPropertyTypeGroup").PrimaryColumn("id"); - - Delete.Column("parentGroupId").FromTable("cmsPropertyTypeGroup"); - } - } -} diff --git a/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSixOneZero/CreateServerRegistryTable.cs b/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSixOneZero/CreateServerRegistryTable.cs deleted file mode 100644 index 75ef49cd8f..0000000000 --- a/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSixOneZero/CreateServerRegistryTable.cs +++ /dev/null @@ -1,34 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using Umbraco.Core.Configuration; -using Umbraco.Core.Logging; -using Umbraco.Core.Models.Rdbms; -using Umbraco.Core.Persistence.SqlSyntax; - -namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSixOneZero -{ - - [Migration("6.1.0", 0, Constants.System.UmbracoMigrationName)] - public class CreateServerRegistryTable : MigrationBase - { - public CreateServerRegistryTable(IMigrationContext context) - : base(context) - { } - - - public override void Up() - { - var schemaHelper = new DatabaseSchemaHelper(Context.Database, Logger); - - //NOTE: This isn't the correct way to do this but to manually create this table with the Create syntax is a pain in the arse - schemaHelper.CreateTable(); - } - - public override void Down() - { - Delete.Table("umbracoServer"); - } - } -} diff --git a/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSixTwoZero/AddChangeDocumentTypePermission.cs b/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSixTwoZero/AddChangeDocumentTypePermission.cs deleted file mode 100644 index 8a524422ca..0000000000 --- a/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSixTwoZero/AddChangeDocumentTypePermission.cs +++ /dev/null @@ -1,61 +0,0 @@ -using System.Linq; -using NPoco; -using Umbraco.Core.Configuration; -using Umbraco.Core.Logging; -using Umbraco.Core.Models.Rdbms; -using Umbraco.Core.Persistence.SqlSyntax; - -namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSixTwoZero -{ - [Migration("7.1.0", 3, Constants.System.UmbracoMigrationName)] - [Migration("6.2.0", 3, Constants.System.UmbracoMigrationName)] - public class AddChangeDocumentTypePermission : MigrationBase - { - public AddChangeDocumentTypePermission(IMigrationContext context) - : base(context) - { } - - - public override void Up() - { - Execute.Code(AddChangeDocumentTypePermissionDo); - } - - public override void Down() - { - Execute.Code(UndoChangeDocumentTypePermissionDo); - } - - private static string AddChangeDocumentTypePermissionDo(IDatabase database) - { - var adminUserType = database.Fetch("WHERE Id = 1").FirstOrDefault(); - - if (adminUserType != null) - { - if (adminUserType.DefaultPermissions.Contains("7") == false) - { - adminUserType.DefaultPermissions = adminUserType.DefaultPermissions + "7"; - database.Save(adminUserType); - } - } - - return string.Empty; - } - - private static string UndoChangeDocumentTypePermissionDo(IDatabase database) - { - var adminUserType = database.Fetch("WHERE Id = 1").FirstOrDefault(); - - if (adminUserType != null) - { - if (adminUserType.DefaultPermissions.Contains("7")) - { - adminUserType.DefaultPermissions = adminUserType.DefaultPermissions.Replace("7", ""); - database.Save(adminUserType); - } - } - - return string.Empty; - } - } -} diff --git a/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSixTwoZero/AdditionalIndexesAndKeys.cs b/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSixTwoZero/AdditionalIndexesAndKeys.cs deleted file mode 100644 index c7293dedce..0000000000 --- a/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSixTwoZero/AdditionalIndexesAndKeys.cs +++ /dev/null @@ -1,113 +0,0 @@ -using System; -using System.Linq; -using Umbraco.Core.Configuration; -using Umbraco.Core.Logging; -using Umbraco.Core.Persistence.DatabaseModelDefinitions; -using Umbraco.Core.Persistence.Migrations.Initial; -using Umbraco.Core.Persistence.SqlSyntax; - -namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSixTwoZero -{ - [Migration("7.1.0", 1, Constants.System.UmbracoMigrationName)] - [Migration("6.2.0", 1, Constants.System.UmbracoMigrationName)] - public class AdditionalIndexesAndKeys : MigrationBase - { - public AdditionalIndexesAndKeys(IMigrationContext context) - : base(context) - { } - - - public override void Up() - { - - var dbIndexes = SqlSyntax.GetDefinedIndexes(Context.Database) - .Select(x => new DbIndexDefinition() - { - TableName = x.Item1, - IndexName = x.Item2, - ColumnName = x.Item3, - IsUnique = x.Item4 - }).ToArray(); - - //do not create any indexes if they already exist in the database - - if (dbIndexes.Any(x => x.IndexName.InvariantEquals("IX_umbracoNodeTrashed")) == false) - { - Create.Index("IX_umbracoNodeTrashed").OnTable("umbracoNode").OnColumn("trashed").Ascending().WithOptions().NonClustered(); - } - if (dbIndexes.Any(x => x.IndexName.InvariantEquals("IX_cmsContentVersion_ContentId")) == false) - { - Create.Index("IX_cmsContentVersion_ContentId").OnTable("cmsContentVersion").OnColumn("ContentId").Ascending().WithOptions().NonClustered(); - } - if (dbIndexes.Any(x => x.IndexName.InvariantEquals("IX_cmsDocument_published")) == false) - { - Create.Index("IX_cmsDocument_published").OnTable("cmsDocument").OnColumn("published").Ascending().WithOptions().NonClustered(); - } - if (dbIndexes.Any(x => x.IndexName.InvariantEquals("IX_cmsDocument_newest")) == false) - { - Create.Index("IX_cmsDocument_newest").OnTable("cmsDocument").OnColumn("newest").Ascending().WithOptions().NonClustered(); - } - - // drop the umbracoUserLogins_Index index since it is named incorrectly - // and then re-create it so it follows the standard naming convention - var sqlServerSyntax = SqlSyntax as SqlServerSyntaxProvider; - if (sqlServerSyntax != null // if running sql server - && sqlServerSyntax.ServerVersion.IsAzure // on Azure - && sqlServerSyntax.ServerVersion.ProductVersion.StartsWith("11.")) // version 11.x - { - // SQL Azure v2 does not support dropping clustered indexes on a table - // see http://issues.umbraco.org/issue/U4-5673 - // and so we have to use a special method to do some manual work - if (dbIndexes.Any(x => x.IndexName.InvariantEquals("umbracoUserLogins_Index"))) - { - //It's the old version that doesn't support dropping a clustered index on a table, so we need to do some manual work. - ExecuteSqlAzureSqlForChangingIndex(); - } - } - else - { - // any other db can delete and recreate - - if (dbIndexes.Any(x => x.IndexName.InvariantEquals("umbracoUserLogins_Index"))) - { - Delete.Index("umbracoUserLogins_Index").OnTable("umbracoUserLogins"); - } - if (dbIndexes.Any(x => x.IndexName.InvariantEquals("IX_umbracoUserLogins_Index")) == false) - { - Create.Index("IX_umbracoUserLogins_Index").OnTable("umbracoUserLogins").OnColumn("contextID").Ascending().WithOptions().Clustered(); - } - } - } - - public override void Down() - { - Delete.Index("IX_umbracoNodeTrashed").OnTable("umbracoNode"); - Delete.Index("IX_cmsContentVersion_ContentId").OnTable("cmsContentVersion"); - Delete.Index("IX_cmsDocument_published").OnTable("cmsDocument"); - Delete.Index("IX_cmsDocument_newest").OnTable("cmsDocument"); - } - - private void ExecuteSqlAzureSqlForChangingIndex() - { - Context.Database.Execute(@"CREATE TABLE ""umbracoUserLogins_temp"" -( - contextID uniqueidentifier NOT NULL, - userID int NOT NULL, - [timeout] bigint NOT NULL -); -CREATE CLUSTERED INDEX ""IX_umbracoUserLogins_Index"" ON ""umbracoUserLogins_temp"" (""contextID""); -INSERT INTO ""umbracoUserLogins_temp"" SELECT * FROM ""umbracoUserLogins"" -DROP TABLE ""umbracoUserLogins"" -CREATE TABLE ""umbracoUserLogins"" -( - contextID uniqueidentifier NOT NULL, - userID int NOT NULL, - [timeout] bigint NOT NULL -); -CREATE CLUSTERED INDEX ""IX_umbracoUserLogins_Index"" ON ""umbracoUserLogins"" (""contextID""); -INSERT INTO ""umbracoUserLogins"" SELECT * FROM ""umbracoUserLogins_temp"" -DROP TABLE ""umbracoUserLogins_temp"""); - - } - } -} diff --git a/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSixTwoZero/AssignMissingPrimaryForMySqlKeys.cs b/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSixTwoZero/AssignMissingPrimaryForMySqlKeys.cs deleted file mode 100644 index 0ba18b65c0..0000000000 --- a/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSixTwoZero/AssignMissingPrimaryForMySqlKeys.cs +++ /dev/null @@ -1,89 +0,0 @@ -using System.Linq; -using System.Web.UI; -using Umbraco.Core.Configuration; -using Umbraco.Core.Logging; -using Umbraco.Core.Persistence.SqlSyntax; - -namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSixTwoZero -{ - - //see: http://issues.umbraco.org/issue/U4-4430 - [Migration("7.1.0", 0, Constants.System.UmbracoMigrationName)] - [Migration("6.2.0", 0, Constants.System.UmbracoMigrationName)] - public class AssignMissingPrimaryForMySqlKeys : MigrationBase - { - public AssignMissingPrimaryForMySqlKeys(IMigrationContext context) - : base(context) - { } - - - public override void Up() - { - if (DatabaseType.IsMySql()) - { - var constraints = SqlSyntax.GetConstraintsPerColumn(Context.Database).Distinct().ToArray(); - - //This should be 2 because this table has 2 keys - if (constraints.Count(x => x.Item1.InvariantEquals("cmsContentTypeAllowedContentType") && x.Item3.InvariantEquals("PRIMARY")) == 0) - { - Create.PrimaryKey("PK_cmsContentTypeAllowedContentType") - .OnTable("cmsContentTypeAllowedContentType") - .Columns(new[] { "Id", "AllowedId" }); - } - - //This should be 2 because this table has 2 keys - if (constraints.Count(x => x.Item1.InvariantEquals("cmsDocumentType") && x.Item3.InvariantEquals("PRIMARY")) == 0) - { - Create.PrimaryKey("PK_cmsDocumentType") - .OnTable("cmsDocumentType") - .Columns(new[] { "contentTypeNodeId", "templateNodeId" }); - } - - //This should be 2 because this table has 2 keys - if (constraints.Count(x => x.Item1.InvariantEquals("cmsMember2MemberGroup") && x.Item3.InvariantEquals("PRIMARY")) == 0) - { - Create.PrimaryKey("PK_cmsMember2MemberGroup") - .OnTable("cmsMember2MemberGroup") - .Columns(new[] { "Member", "MemberGroup" }); - } - - //This should be 2 because this table has 2 keys - if (constraints.Count(x => x.Item1.InvariantEquals("cmsPreviewXml") && x.Item3.InvariantEquals("PRIMARY")) == 0) - { - Create.PrimaryKey("PK_cmsContentPreviewXml") - .OnTable("cmsPreviewXml") - .Columns(new[] { "nodeId", "versionId" }); - } - - //This should be 2 because this table has 2 keys - if (constraints.Count(x => x.Item1.InvariantEquals("umbracoUser2app") && x.Item3.InvariantEquals("PRIMARY")) == 0) - { - Create.PrimaryKey("PK_user2app") - .OnTable("umbracoUser2app") - .Columns(new[] { "user", "app" }); - } - - //This should be 2 because this table has 3 keys - if (constraints.Count(x => x.Item1.InvariantEquals("umbracoUser2NodeNotify") && x.Item3.InvariantEquals("PRIMARY")) == 0) - { - Create.PrimaryKey("PK_umbracoUser2NodeNotify") - .OnTable("umbracoUser2NodeNotify") - .Columns(new[] { "userId", "nodeId", "action" }); - } - - //This should be 2 because this table has 3 keys - if (constraints.Count(x => x.Item1.InvariantEquals("umbracoUser2NodePermission") && x.Item3.InvariantEquals("PRIMARY")) == 0) - { - Create.PrimaryKey("PK_umbracoUser2NodePermission") - .OnTable("umbracoUser2NodePermission") - .Columns(new[] { "userId", "nodeId", "permission" }); - } - } - } - - public override void Down() - { - //don't do anything, these keys should have always existed! - } - } -} diff --git a/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSixTwoZero/AssignMissingPrimaryForMySqlKeys2.cs b/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSixTwoZero/AssignMissingPrimaryForMySqlKeys2.cs deleted file mode 100644 index 6b698a3f4b..0000000000 --- a/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSixTwoZero/AssignMissingPrimaryForMySqlKeys2.cs +++ /dev/null @@ -1,40 +0,0 @@ -using System.Linq; -using Umbraco.Core.Configuration; -using Umbraco.Core.Logging; -using Umbraco.Core.Persistence.SqlSyntax; - -namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSixTwoZero -{ - //We have to target this specifically to ensure this DOES NOT execute if upgrading from a version previous to 6.0, - // this is because when the 6.0.0 migrations are executed, this primary key get's created so if this migration is also executed - // we will get exceptions because it is trying to create the PK two times. - [Migration("6.0.0", "6.2.0", 0, Constants.System.UmbracoMigrationName)] - public class AssignMissingPrimaryForMySqlKeys2 : MigrationBase - { - public AssignMissingPrimaryForMySqlKeys2(IMigrationContext context) - : base(context) - { } - - - public override void Up() - { - if (DatabaseType.IsMySql()) - { - var constraints = SqlSyntax.GetConstraintsPerColumn(Context.Database).Distinct().ToArray(); - - //This should be 2 because this table has 2 keys - if (constraints.Count(x => x.Item1.InvariantEquals("cmsContentType2ContentType") && x.Item3.InvariantEquals("PRIMARY")) == 0) - { - Create.PrimaryKey("PK_cmsContentType2ContentType") - .OnTable("cmsContentType2ContentType") - .Columns(new[] { "parentContentTypeId", "childContentTypeId" }); - } - } - } - - public override void Down() - { - //don't do anything, these keys should have always existed! - } - } -} diff --git a/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSixTwoZero/ChangePasswordColumn.cs b/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSixTwoZero/ChangePasswordColumn.cs deleted file mode 100644 index e226cb0f68..0000000000 --- a/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSixTwoZero/ChangePasswordColumn.cs +++ /dev/null @@ -1,29 +0,0 @@ -using System; -using Umbraco.Core.Configuration; -using Umbraco.Core.Logging; -using Umbraco.Core.Persistence.SqlSyntax; - -namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSixTwoZero -{ - [Migration("7.1.0", 2, Constants.System.UmbracoMigrationName)] - [Migration("6.2.0", 2, Constants.System.UmbracoMigrationName)] - public class ChangePasswordColumn : MigrationBase - { - public ChangePasswordColumn(IMigrationContext context) - : base(context) - { } - - - public override void Up() - { - //up to 500 chars - Alter.Table("umbracoUser").AlterColumn("userPassword").AsString(500).NotNullable(); - } - - public override void Down() - { - //back to 125 chars - Alter.Table("umbracoUser").AlterColumn("userPassword").AsString(125).NotNullable(); - } - } -} diff --git a/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSixTwoZero/UpdateToNewMemberPropertyAliases.cs b/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSixTwoZero/UpdateToNewMemberPropertyAliases.cs deleted file mode 100644 index 788d9f6fa3..0000000000 --- a/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSixTwoZero/UpdateToNewMemberPropertyAliases.cs +++ /dev/null @@ -1,99 +0,0 @@ -using System; -using System.Collections.Generic; -using NPoco; -using Umbraco.Core.Configuration; -using Umbraco.Core.Logging; -using Umbraco.Core.Models.Rdbms; -using Umbraco.Core.Persistence.SqlSyntax; - -namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSixTwoZero -{ - [Migration("7.1.0", 4, Constants.System.UmbracoMigrationName)] - [Migration("6.2.0", 4, Constants.System.UmbracoMigrationName)] - public class UpdateToNewMemberPropertyAliases : MigrationBase - { - public UpdateToNewMemberPropertyAliases(IMigrationContext context) - : base(context) - { } - - public override void Up() - { - Execute.Code(Update); - } - - internal string Update(IDatabase database) - { - if (database != null) - { - var aliasMap = new Dictionary - { - {"umbracoPasswordRetrievalQuestionPropertyTypeAlias", Constants.Conventions.Member.PasswordQuestion}, - {"umbracoPasswordRetrievalAnswerPropertyTypeAlias", Constants.Conventions.Member.PasswordAnswer}, - {"umbracoCommentPropertyTypeAlias", Constants.Conventions.Member.Comments}, - {"umbracoApprovePropertyTypeAlias", Constants.Conventions.Member.IsApproved}, - {"umbracoLockPropertyTypeAlias", Constants.Conventions.Member.IsLockedOut}, - {"umbracoLastLoginPropertyTypeAlias", Constants.Conventions.Member.LastLoginDate}, - {"umbracoMemberLastPasswordChange", Constants.Conventions.Member.LastPasswordChangeDate}, - {"umbracoMemberLastLockout", Constants.Conventions.Member.LastLockoutDate}, - {"umbracoFailedPasswordAttemptsPropertyTypeAlias", Constants.Conventions.Member.FailedPasswordAttempts} - }; - - - //This query is structured to work with MySql, SQLCE and SqlServer: - // http://issues.umbraco.org/issue/U4-3876 - - const string propertyTypeUpdateSql = @"UPDATE cmsPropertyType -SET Alias = @newAlias -WHERE Alias = @oldAlias AND contentTypeId IN ( -SELECT nodeId FROM (SELECT DISTINCT cmsContentType.nodeId FROM cmsPropertyType -INNER JOIN cmsContentType ON cmsPropertyType.contentTypeId = cmsContentType.nodeId -INNER JOIN umbracoNode ON cmsContentType.nodeId = umbracoNode.id -WHERE umbracoNode.nodeObjectType = @objectType) x)"; - - const string xmlSelectSql = @"SELECT cmsContentXml.* FROM cmsContentXml -INNER JOIN umbracoNode ON cmsContentXml.nodeId = umbracoNode.id -WHERE umbracoNode.nodeObjectType = @objectType"; - - using (var trans = database.GetTransaction()) - { - try - { - - //Upate all of the property type aliases - foreach (var map in aliasMap) - { - database.Execute(propertyTypeUpdateSql, new { newAlias = map.Value, oldAlias = map.Key, objectType = Constants.ObjectTypes.MemberType }); - } - - //Update all of the XML - var items = database.Fetch(xmlSelectSql, new { objectType = Constants.ObjectTypes.Member }); - foreach (var item in items) - { - foreach (var map in aliasMap) - { - item.Xml = item.Xml.Replace("<" + map.Key + ">", "<" + map.Value + ">"); - item.Xml = item.Xml.Replace("", ""); - } - database.Update(item); - } - - trans.Complete(); - } - catch (Exception ex) - { - Logger.Error("Exception was thrown when trying to upgrade old member aliases to the new ones", ex); - throw; - } - } - - - } - return string.Empty; - } - - public override void Down() - { - throw new NotImplementedException(); - } - } -} diff --git a/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSixZeroOne/UpdatePropertyTypesAndGroups.cs b/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSixZeroOne/UpdatePropertyTypesAndGroups.cs deleted file mode 100644 index 3fd39d3e7a..0000000000 --- a/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSixZeroOne/UpdatePropertyTypesAndGroups.cs +++ /dev/null @@ -1,97 +0,0 @@ -using System; -using System.Linq; -using NPoco; -using Umbraco.Core.Configuration; -using Umbraco.Core.Logging; -using Umbraco.Core.Models.Rdbms; -using Umbraco.Core.Persistence.SqlSyntax; - -namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSixZeroOne -{ - [Migration("6.0.2", 0, Constants.System.UmbracoMigrationName)] - public class UpdatePropertyTypesAndGroups : MigrationBase - { - public UpdatePropertyTypesAndGroups(IMigrationContext context) - : base(context) - { } - - - public override void Up() - { - Execute.Code(UpdatePropertyTypesAndGroupsDo); - } - - public override void Down() - { - - } - - public static string UpdatePropertyTypesAndGroupsDo(IDatabase database) - { - if (database != null) - { - //Fetch all PropertyTypes that belongs to a PropertyTypeGroup - //NOTE: We are writing the full query because we've added a column to the PropertyTypeDto in later versions so one of the columns - // won't exist yet - var propertyTypes = database.Fetch("SELECT * FROM cmsPropertyType WHERE propertyTypeGroupId > 0"); - - // need to use dynamic, as PropertyTypeGroupDto has new properties - var propertyGroups = database.Fetch("SELECT * FROM cmsPropertyTypeGroup WHERE id > 0"); - - foreach (var propertyType in propertyTypes) - { - // get the PropertyTypeGroup of the current PropertyType, skip if not found - var propertyTypeGroup = propertyGroups.FirstOrDefault(x => x.id == propertyType.propertyTypeGroupId); - if (propertyTypeGroup == null) continue; - - // if the PropretyTypeGroup belongs to the same content type as the PropertyType, then fine - if (propertyTypeGroup.contenttypeNodeId == propertyType.contentTypeId) continue; - - // else we want to assign the PropertyType to a proper PropertyTypeGroup - // ie one that does belong to the same content - look for it - var okPropertyTypeGroup = propertyGroups.FirstOrDefault(x => - x.text == propertyTypeGroup.text && // same name - x.contenttypeNodeId == propertyType.contentTypeId); // but for proper content type - - if (okPropertyTypeGroup == null) - { - // does not exist, create a new PropertyTypeGroup - // cannot use a PropertyTypeGroupDto because of the new (not-yet-existing) uniqueID property - // cannot use a dynamic because database.Insert fails to set the value of property - var propertyGroup = new PropertyTypeGroupDtoTemp - { - id = 0, - contenttypeNodeId = propertyType.contentTypeId, - text = propertyTypeGroup.text, - sortorder = propertyTypeGroup.sortorder - }; - - // save + add to list of groups - int id = Convert.ToInt16(database.Insert("cmsPropertyTypeGroup", "id", propertyGroup)); - propertyGroup.id = id; - propertyGroups.Add(propertyGroup); - - // update the PropertyType to use the new PropertyTypeGroup - propertyType.propertyTypeGroupId = id; - } - else - { - // exists, update PropertyType to use the PropertyTypeGroup - propertyType.propertyTypeGroupId = okPropertyTypeGroup.id; - } - database.Update("cmsPropertyType", "id", propertyType); - } - } - - return string.Empty; - } - - private class PropertyTypeGroupDtoTemp - { - public int id { get; set; } - public int contenttypeNodeId { get; set; } - public string text { get; set; } - public int sortorder { get; set; } - } - } -} diff --git a/src/Umbraco.Core/Persistence/Migrations/Upgrades/Temp8/AddIndexToDictionaryKeyColumn.cs b/src/Umbraco.Core/Persistence/Migrations/Upgrades/Temp8/AddIndexToDictionaryKeyColumn.cs new file mode 100644 index 0000000000..d75a9165de --- /dev/null +++ b/src/Umbraco.Core/Persistence/Migrations/Upgrades/Temp8/AddIndexToDictionaryKeyColumn.cs @@ -0,0 +1,53 @@ +using System.Linq; +using Umbraco.Core.Persistence.SqlSyntax; + +namespace Umbraco.Core.Persistence.Migrations.Upgrades.Temp8 +{ + [Migration("7.7.0", 5, Constants.System.UmbracoMigrationName)] + public class AddIndexToDictionaryKeyColumn : MigrationBase + { + public AddIndexToDictionaryKeyColumn(IMigrationContext context) + : base(context) + { } + + public override void Up() + { + Execute.Code(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 = (SqlSyntax is MySqlSyntaxProvider) + ? database.ExecuteScalar(string.Format("select max(LENGTH({0})) from cmsDictionary", SqlSyntax.GetQuotedColumnName("key"))) + : database.ExecuteScalar(string.Format("select max(datalength({0})) from cmsDictionary", SqlSyntax.GetQuotedColumnName("key"))); + + if (colLen < 900 == false && colLen != null) + { + return null; + } + + var dbIndexes = SqlSyntax.GetDefinedIndexesDefinitions(Context.Database); + + //make sure it doesn't already exist + if (dbIndexes.Any(x => x.IndexName.InvariantEquals("IX_cmsDictionary_key")) == false) + { + var local = Context.GetLocalMigration(); + + //we can apply the index + local.Create.Index("IX_cmsDictionary_key").OnTable("cmsDictionary") + .OnColumn("key") + .Ascending() + .WithOptions() + .NonClustered(); + + return local.GetSql(); + } + + return null; + }); + } + + public override void Down() + { + Delete.Index("IX_cmsDictionary_key").OnTable("cmsDictionary"); + } + } +} diff --git a/src/Umbraco.Core/Persistence/Migrations/Upgrades/Temp8/AddUserGroupTables.cs b/src/Umbraco.Core/Persistence/Migrations/Upgrades/Temp8/AddUserGroupTables.cs new file mode 100644 index 0000000000..bee1d0e11e --- /dev/null +++ b/src/Umbraco.Core/Persistence/Migrations/Upgrades/Temp8/AddUserGroupTables.cs @@ -0,0 +1,174 @@ +using System; +using System.Linq; +using Umbraco.Core.Models.Rdbms; + +namespace Umbraco.Core.Persistence.Migrations.Upgrades.Temp8 +{ + [Migration("8.0.0", 1, Constants.System.UmbracoMigrationName)] + public class AddUserGroupTables : MigrationBase + { + public AddUserGroupTables(IMigrationContext context) + : base(context) + { } + + public override void Up() + { + var tables = SqlSyntax.GetTablesInSchema(Context.Database).ToArray(); + var constraints = SqlSyntax.GetConstraintsPerColumn(Context.Database).Distinct().ToArray(); + + if (AddNewTables(tables)) + { + MigrateUserPermissions(); + MigrateUserTypesToGroups(); + DeleteOldTables(tables, constraints); + SetDefaultIcons(); + } + } + + private void SetDefaultIcons() + { + Execute.Sql($"UPDATE umbracoUserGroup SET icon = \'\' WHERE userGroupAlias = \'{Constants.Security.AdminGroupAlias}\'"); + Execute.Sql("UPDATE umbracoUserGroup SET icon = \'icon-edit\' WHERE userGroupAlias = \'writer\'"); + Execute.Sql("UPDATE umbracoUserGroup SET icon = \'icon-tools\' WHERE userGroupAlias = \'editor\'"); + Execute.Sql("UPDATE umbracoUserGroup SET icon = \'icon-globe\' WHERE userGroupAlias = \'translator\'"); + } + + private bool AddNewTables(string[] tables) + { + var updated = false; + if (tables.InvariantContains("umbracoUserGroup") == false) + { + Create.Table(); + updated = true; + } + + if (tables.InvariantContains("umbracoUser2UserGroup") == false) + { + Create.Table(); + updated = true; + } + + if (tables.InvariantContains("umbracoUserGroup2App") == false) + { + Create.Table(); + updated = true; + } + + if (tables.InvariantContains("umbracoUserGroup2NodePermission") == false) + { + Create.Table(); + updated = true; + } + + return updated; + } + + private void MigrateUserTypesToGroups() + { + // Create a user group for each user type + Execute.Sql(@"INSERT INTO umbracoUserGroup (userGroupAlias, userGroupName, userGroupDefaultPermissions) + SELECT userTypeAlias, userTypeName, userTypeDefaultPermissions + FROM umbracoUserType"); + + // Add each user to the group created from their type + Execute.Sql(@"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 = ut.userTypeAlias"); + + // Add the built-in administrator account to all apps + Execute.Sql(@"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"); + + // Rename some groups for consistency (plural form) + Execute.Sql("UPDATE umbracoUserGroup SET userGroupName = 'Writers' WHERE userGroupAlias = 'writer'"); + Execute.Sql("UPDATE umbracoUserGroup SET userGroupName = 'Translators' WHERE userGroupAlias = 'translator'"); + + //Ensure all built in groups have a start node of -1 + Execute.Sql("UPDATE umbracoUserGroup SET startContentId = -1 WHERE userGroupAlias = 'editor'"); + Execute.Sql("UPDATE umbracoUserGroup SET startMediaId = -1 WHERE userGroupAlias = 'editor'"); + Execute.Sql("UPDATE umbracoUserGroup SET startContentId = -1 WHERE userGroupAlias = 'writer'"); + Execute.Sql("UPDATE umbracoUserGroup SET startMediaId = -1 WHERE userGroupAlias = 'writer'"); + Execute.Sql("UPDATE umbracoUserGroup SET startContentId = -1 WHERE userGroupAlias = 'translator'"); + Execute.Sql("UPDATE umbracoUserGroup SET startMediaId = -1 WHERE userGroupAlias = 'translator'"); + Execute.Sql("UPDATE umbracoUserGroup SET startContentId = -1 WHERE userGroupAlias = 'admin'"); + Execute.Sql("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 + Execute.Sql(@"INSERT INTO umbracoUserGroup(userGroupAlias, userGroupName) + SELECT userName + 'Group', 'Group for ' + userName + FROM umbracoUser + WHERE (id IN ( + SELECT " + SqlSyntax.GetQuotedColumnName("user") + @" + FROM umbracoUser2app + ) OR id IN ( + SELECT userid + FROM umbracoUser2NodePermission + )) + AND id > 0"); + + // Associate those groups with the users + Execute.Sql(@"INSERT INTO umbracoUser2UserGroup (userId, userGroupId) + SELECT u.id, ug.id + FROM umbracoUser u + INNER JOIN umbracoUserGroup ug ON ug.userGroupAlias = userName + 'Group'"); + + // Create node permissions on the groups + Execute.Sql(@"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 NOT IN ( + SELECT userTypeAlias + FROM umbracoUserType + )"); + + // Create app permissions on the groups + Execute.Sql(@"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 NOT IN ( + SELECT userTypeAlias + FROM umbracoUserType + )"); + } + + private void DeleteOldTables(string[] tables, Tuple[] constraints) + { + if (tables.InvariantContains("umbracoUser2App")) + { + Delete.Table("umbracoUser2App"); + } + + if (tables.InvariantContains("umbracoUser2NodePermission")) + { + Delete.Table("umbracoUser2NodePermission"); + } + + if (tables.InvariantContains("umbracoUserType") && tables.InvariantContains("umbracoUser")) + { + if (constraints.Any(x => x.Item1.InvariantEquals("umbracoUser") && x.Item3.InvariantEquals("FK_umbracoUser_umbracoUserType_id"))) + { + Delete.ForeignKey("FK_umbracoUser_umbracoUserType_id").OnTable("umbracoUser"); + } + + Delete.Column("userType").FromTable("umbracoUser"); + Delete.Table("umbracoUserType"); + } + } + } +} \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/Migrations/Upgrades/Temp8/AddUserStartNodeTable.cs b/src/Umbraco.Core/Persistence/Migrations/Upgrades/Temp8/AddUserStartNodeTable.cs new file mode 100644 index 0000000000..a542acbc3e --- /dev/null +++ b/src/Umbraco.Core/Persistence/Migrations/Upgrades/Temp8/AddUserStartNodeTable.cs @@ -0,0 +1,42 @@ +using System.Linq; +using Umbraco.Core.Models.Rdbms; + +namespace Umbraco.Core.Persistence.Migrations.Upgrades.Temp8 +{ + [Migration("8.0.0", 2, Constants.System.UmbracoMigrationName)] + public class AddUserStartNodeTable : MigrationBase + { + public AddUserStartNodeTable(IMigrationContext context) + : base(context) + { } + + public override void Up() + { + var tables = SqlSyntax.GetTablesInSchema(Context.Database).ToArray(); + + if (tables.InvariantContains("umbracoUserStartNode")) return; + + Create.Table(); + + MigrateUserStartNodes(); + + //now remove the old columns + + Delete.Column("startStructureID").FromTable("umbracoUser"); + Delete.Column("startMediaID").FromTable("umbracoUser"); + } + + private void MigrateUserStartNodes() + { + Execute.Sql(@"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 + "')"); + + Execute.Sql(@"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 + "')"); + } + } +} \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/Migrations/Upgrades/Temp8/EnsureContentTemplatePermissions.cs b/src/Umbraco.Core/Persistence/Migrations/Upgrades/Temp8/EnsureContentTemplatePermissions.cs new file mode 100644 index 0000000000..9f04ab8130 --- /dev/null +++ b/src/Umbraco.Core/Persistence/Migrations/Upgrades/Temp8/EnsureContentTemplatePermissions.cs @@ -0,0 +1,42 @@ +using System.Linq; +using Umbraco.Core.Models.Rdbms; + +namespace Umbraco.Core.Persistence.Migrations.Upgrades.Temp8 +{ + /// + /// Ensures the built-in user groups have the blueprint permission by default on upgrade + /// + [Migration("8.0.0", 6, Constants.System.UmbracoMigrationName)] + public class EnsureContentTemplatePermissions : MigrationBase + { + public EnsureContentTemplatePermissions(IMigrationContext context) + : base(context) + { } + + public override void Up() + { + Execute.Code(database => + { + var userGroups = database.Fetch( + Context.Sql().Select("*") + .From() + .Where(x => x.Alias == "admin" || x.Alias == "editor")); + + var local = Context.GetLocalMigration(); + + foreach (var userGroup in userGroups) + { + if (userGroup.DefaultPermissions.Contains('ï') == false) + { + userGroup.DefaultPermissions += "ï"; + local.Update.Table("umbracoUserGroup") + .Set(new { userGroupDefaultPermissions = userGroup.DefaultPermissions }) + .Where(new { id = userGroup.Id }); + } + } + + return local.GetSql(); + }); + } + } +} \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/Migrations/Upgrades/Temp8/ReduceDictionaryKeyColumnsSize.cs b/src/Umbraco.Core/Persistence/Migrations/Upgrades/Temp8/ReduceDictionaryKeyColumnsSize.cs new file mode 100644 index 0000000000..053a967dc0 --- /dev/null +++ b/src/Umbraco.Core/Persistence/Migrations/Upgrades/Temp8/ReduceDictionaryKeyColumnsSize.cs @@ -0,0 +1,45 @@ +using System.Linq; +using Umbraco.Core.Persistence.SqlSyntax; + +namespace Umbraco.Core.Persistence.Migrations.Upgrades.Temp8 +{ + [Migration("8.0.0", 4, Constants.System.UmbracoMigrationName)] + public class ReduceDictionaryKeyColumnsSize : MigrationBase + { + public ReduceDictionaryKeyColumnsSize(IMigrationContext context) + : base(context) + { } + + public override void Up() + { + //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 + + Execute.Code(database => + { + var dbIndexes = SqlSyntax.GetDefinedIndexesDefinitions(database); + + var colLen = SqlSyntax is MySqlSyntaxProvider + ? database.ExecuteScalar(string.Format("select max(LENGTH({0})) from cmsDictionary", SqlSyntax.GetQuotedColumnName("key"))) + : database.ExecuteScalar(string.Format("select max(datalength({0})) from cmsDictionary", SqlSyntax.GetQuotedColumnName("key"))); + + if (colLen < 900 == false) return null; + + var local = Context.GetLocalMigration(); + + //if it exists we need to drop it first + if (dbIndexes.Any(x => x.IndexName.InvariantEquals("IX_cmsDictionary_key"))) + { + local.Delete.Index("IX_cmsDictionary_key").OnTable("cmsDictionary"); + } + + //we can apply the col length change + local.Alter.Table("cmsDictionary") + .AlterColumn("key") + .AsString(450) + .NotNullable(); + + return local.GetSql(); + }); + } + } +} \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/Migrations/Upgrades/Temp8/UpdateUserTables.cs b/src/Umbraco.Core/Persistence/Migrations/Upgrades/Temp8/UpdateUserTables.cs new file mode 100644 index 0000000000..81459d851e --- /dev/null +++ b/src/Umbraco.Core/Persistence/Migrations/Upgrades/Temp8/UpdateUserTables.cs @@ -0,0 +1,46 @@ +using System.Linq; +using System.Web.Security; +using Newtonsoft.Json; +using Umbraco.Core.Persistence.DatabaseModelDefinitions; +using Umbraco.Core.Security; + +namespace Umbraco.Core.Persistence.Migrations.Upgrades.Temp8 +{ + [Migration("8.0.0", 0, Constants.System.UmbracoMigrationName)] + public class UpdateUserTables : MigrationBase + { + public UpdateUserTables(IMigrationContext context) + : base(context) + { } + + public override void Up() + { + //Don't exeucte 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); + + if (columns.Any(x => x.TableName.InvariantEquals("umbracoUser") && x.ColumnName.InvariantEquals("updateDate")) == false) + Create.Column("updateDate").OnTable("umbracoUser").AsDateTime().NotNullable().WithDefault(SystemMethods.CurrentDateTime); + + if (columns.Any(x => x.TableName.InvariantEquals("umbracoUser") && x.ColumnName.InvariantEquals("emailConfirmedDate")) == false) + Create.Column("emailConfirmedDate").OnTable("umbracoUser").AsDateTime().Nullable(); + + if (columns.Any(x => x.TableName.InvariantEquals("umbracoUser") && x.ColumnName.InvariantEquals("invitedDate")) == false) + Create.Column("invitedDate").OnTable("umbracoUser").AsDateTime().Nullable(); + + if (columns.Any(x => x.TableName.InvariantEquals("umbracoUser") && x.ColumnName.InvariantEquals("passwordConfig")) == false) + { + Create.Column("passwordConfig").OnTable("umbracoUser").AsString(500).Nullable(); + //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 }); + Execute.Sql("UPDATE umbracoUser SET passwordConfig = '" + json + "'"); + } + } + } + } +} \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/Repositories/UserRepository.cs b/src/Umbraco.Core/Persistence/Repositories/UserRepository.cs index b262cf56df..743361d7dc 100644 --- a/src/Umbraco.Core/Persistence/Repositories/UserRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/UserRepository.cs @@ -1,8 +1,11 @@ using System; using System.Collections.Generic; +using System.ComponentModel; using System.Linq; using System.Linq.Expressions; +using System.Text; using System.Web.Security; +using Newtonsoft.Json; using NPoco; using Umbraco.Core; using Umbraco.Core.Cache; @@ -12,7 +15,7 @@ using Umbraco.Core.Models; using Umbraco.Core.Models.EntityBase; using Umbraco.Core.Models.Membership; using Umbraco.Core.Models.Rdbms; - +using Umbraco.Core.Persistence.DatabaseModelDefinitions; using Umbraco.Core.Persistence.Factories; using Umbraco.Core.Persistence.Mappers; using Umbraco.Core.Persistence.Querying; @@ -20,6 +23,7 @@ using Umbraco.Core.Persistence.SqlSyntax; using Umbraco.Core.Persistence.UnitOfWork; using Umbraco.Core.Security; +#error the entire clads needs to be refactored for proper NPoco usage namespace Umbraco.Core.Persistence.Repositories { /// @@ -27,20 +31,26 @@ namespace Umbraco.Core.Persistence.Repositories /// internal class UserRepository : NPocoRepositoryBase, IUserRepository { - private readonly IUserTypeRepository _userTypeRepository; - private readonly CacheHelper _cacheHelper; private readonly IMapperCollection _mapperCollection; private readonly IDictionary _passwordConfig; private PermissionRepository _permissionRepository; - public UserRepository(IScopeUnitOfWork work, CacheHelper cacheHelper, ILogger logger, IUserTypeRepository userTypeRepository, IMapperCollection mapperCollection, IDictionary passwordConfig = null) + /// + /// Constructor + /// + /// + /// + /// + /// + /// A dictionary specifying the configuration for user passwords. If this is null then no password configuration will be persisted or read. + /// + #error password config, change: null will ??? + public UserRepository(IScopeUnitOfWork work, CacheHelper cacheHelper, ILogger logger, IMapperCollection mapperCollection, IDictionary passwordConfig = null) : base(work, cacheHelper, logger) { - _userTypeRepository = userTypeRepository; _mapperCollection = mapperCollection; - _cacheHelper = cacheHelper; - - if (passwordConfig == null) + + if (passwordConfig == null) // fixme this is bad bc we may want it to remain null?! { var userMembershipProvider = MembershipProviderExtensions.GetUsersMembershipProvider(); passwordConfig = userMembershipProvider == null || userMembershipProvider.PasswordFormat != MembershipPasswordFormat.Hashed @@ -58,49 +68,193 @@ namespace Umbraco.Core.Persistence.Repositories protected override IUser PerformGet(int id) { - var sql = GetBaseQuery(false); + var sql = GetQueryWithGroups(); sql.Where(GetBaseWhereClause(), new { Id = id }); + sql //must be included for relator to work + .OrderBy(d => d.Id, SqlSyntax) + .OrderBy(d => d.Id, SqlSyntax) + .OrderBy(d => d.Id, SqlSyntax); - var dto = Database - .FetchOneToMany(x => x.User2AppDtos, sql) + var dto = Database.Fetch(new UserGroupRelator().Map, sql) .FirstOrDefault(); if (dto == null) return null; - var userType = _userTypeRepository.Get(dto.Type); - var userFactory = new UserFactory(userType); - var user = userFactory.BuildEntity(dto); - + var user = UserFactory.BuildEntity(dto); return user; } + /// + /// Returns a user by username + /// + /// + /// + /// Can be used for slightly faster user lookups if the result doesn't require security data (i.e. groups, apps & start nodes). + /// This is really only used for a shim in order to upgrade to 7.6. + /// + /// + /// A non cached instance + /// + public IUser GetByUsername(string username, bool includeSecurityData) + { + UserDto dto; + if (includeSecurityData) + { + var sql = GetQueryWithGroups(); + sql.Where(userDto => userDto.Login == username, SqlSyntax); + sql //must be included for relator to work + .OrderBy(d => d.Id, SqlSyntax) + .OrderBy(d => d.Id, SqlSyntax) + .OrderBy(d => d.Id, SqlSyntax); + dto = Database + .Fetch( + new UserGroupRelator().Map, sql) + .FirstOrDefault(); + } + else + { + var sql = GetBaseQuery("umbracoUser.*"); + sql.Where(userDto => userDto.Login == username, SqlSyntax); + dto = Database.FirstOrDefault(sql); + } + + if (dto == null) + return null; + + var user = UserFactory.BuildEntity(dto); + return user; + } + + /// + /// Returns a user by id + /// + /// + /// + /// This is really only used for a shim in order to upgrade to 7.6 but could be used + /// for slightly faster user lookups if the result doesn't require security data (i.e. groups, apps & start nodes) + /// + /// + /// A non cached instance + /// + public IUser Get(int id, bool includeSecurityData) + { + UserDto dto; + if (includeSecurityData) + { + var sql = GetQueryWithGroups(); + sql.Where(GetBaseWhereClause(), new { Id = id }); + sql //must be included for relator to work + .OrderBy(d => d.Id, SqlSyntax) + .OrderBy(d => d.Id, SqlSyntax) + .OrderBy(d => d.Id, SqlSyntax); + dto = Database + .Fetch( + new UserGroupRelator().Map, sql) + .FirstOrDefault(); + } + else + { + var sql = GetBaseQuery("umbracoUser.*"); + sql.Where(GetBaseWhereClause(), new { Id = id }); + dto = Database.FirstOrDefault(sql); + } + + if (dto == null) + return null; + + var user = UserFactory.BuildEntity(dto); + return user; + } + + public IProfile GetProfile(string username) + { + var sql = GetBaseQuery(false).Where(userDto => userDto.UserName == username, SqlSyntax); + + var dto = Database.Fetch(sql) + .FirstOrDefault(); + + if (dto == null) + return null; + + return new UserProfile(dto.Id, dto.UserName); + } + + public IProfile GetProfile(int id) + { + var sql = GetBaseQuery(false).Where(userDto => userDto.Id == id, SqlSyntax); + + var dto = Database.Fetch(sql) + .FirstOrDefault(); + + if (dto == null) + return null; + + return new UserProfile(dto.Id, dto.UserName); + } + + public IDictionary GetUserStates() + { + var sql = @"SELECT '1CountOfAll' AS colName, COUNT(id) AS num FROM umbracoUser +UNION +SELECT '2CountOfActive' AS colName, COUNT(id) AS num FROM umbracoUser WHERE userDisabled = 0 AND userNoConsole = 0 AND lastLoginDate IS NOT NULL +UNION +SELECT '3CountOfDisabled' AS colName, COUNT(id) AS num FROM umbracoUser WHERE userDisabled = 1 +UNION +SELECT '4CountOfLockedOut' AS colName, COUNT(id) AS num FROM umbracoUser WHERE userNoConsole = 1 +UNION +SELECT '5CountOfInvited' AS colName, COUNT(id) AS num FROM umbracoUser WHERE lastLoginDate IS NULL AND userDisabled = 1 AND invitedDate IS NOT NULL +ORDER BY colName"; + + var result = Database.Fetch(sql); + + return new Dictionary + { + {UserState.All, result[0].num}, + {UserState.Active, result[1].num}, + {UserState.Disabled, result[2].num}, + {UserState.LockedOut, result[3].num}, + {UserState.Invited, result[4].num} + }; + } + protected override IEnumerable PerformGetAll(params int[] ids) { - var sql = GetBaseQuery(false); - + var sql = GetQueryWithGroups(); if (ids.Any()) { - sql.Where("umbracoUser.id in (@ids)", new {ids = ids}); + sql.Where("umbracoUser.id in (@ids)", new { ids = ids }); } + #error refactor with FetchOneToMany + sql //must be included for relator to work + .OrderBy(d => d.Id, SqlSyntax) + .OrderBy(d => d.Id, SqlSyntax) + .OrderBy(d => d.Id, SqlSyntax); - var dtos = Database - .FetchOneToMany(x => x.User2AppDtos, sql); + var users = ConvertFromDtos(Database.Fetch(new UserGroupRelator().Map, sql)) + .ToArray(); // important so we don't iterate twice, if we don't do this we can end up with null values in cache if we were caching. - return ConvertFromDtos(dtos).ToArray(); // do it now and do it once, else can end up with nulls in cache + return users; } protected override IEnumerable PerformGetByQuery(IQuery query) { - var sqlClause = GetBaseQuery(false); + var sqlClause = GetQueryWithGroups(); var translator = new SqlTranslator(sqlClause, query); var sql = translator.Translate(); + #error obviously refactor with FetchOneToMany! + sql //must be included for relator to work + .OrderBy(d => d.Id, SqlSyntax) + .OrderBy(d => d.Id, SqlSyntax) + .OrderBy(d => d.Id, SqlSyntax); - var dtos = Database - .FetchOneToMany(x => x.User2AppDtos, sql) + var dtos = Database.Fetch(new UserGroupRelator().Map, sql) .DistinctBy(x => x.Id); - return ConvertFromDtos(dtos).ToArray(); // do it now and do it once, else can end up with nulls in cache + var users = ConvertFromDtos(dtos) + .ToArray(); // important so we don't iterate twice, if we don't do this we can end up with null values in cache if we were caching. + + return users; } #endregion @@ -119,16 +273,39 @@ namespace Umbraco.Core.Persistence.Repositories .On(left => left.Id, right => right.UserId); } +#error prob needs to be refactored entirely + /// + /// A query to return a user with it's groups and with it's groups sections + /// + /// + private Sql GetQueryWithGroups() + { + //base query includes user groups + var sql = GetBaseQuery("umbracoUser.*, umbracoUserGroup.*, umbracoUserGroup2App.*, umbracoUserStartNode.*"); + AddGroupLeftJoin(sql); + return sql; + } + + private static void AddGroupLeftJoin(Sql sql) + { + sql + .LeftJoin() + .On(left => left.UserId, right => right.Id) + .LeftJoin() + .On(left => left.Id, right => right.UserGroupId) + .LeftJoin() + .On(left => left.UserGroupId, right => right.Id) + .LeftJoin() + .On(left => left.UserId, right => right.Id); + } + private Sql GetBaseQuery(string columns) { return Sql() .Select(columns) - .From() - .LeftJoin() - .On(left => left.Id, right => right.UserId); + .From(); } - protected override string GetBaseWhereClause() { return "umbracoUser.id = @Id"; @@ -137,43 +314,66 @@ namespace Umbraco.Core.Persistence.Repositories protected override IEnumerable GetDeleteClauses() { var list = new List - { - "DELETE FROM cmsTask WHERE userId = @Id", - "DELETE FROM cmsTask WHERE parentUserId = @Id", - "DELETE FROM umbracoUser2NodePermission WHERE userId = @Id", - "DELETE FROM umbracoUser2NodeNotify WHERE userId = @Id", - "DELETE FROM umbracoUser2app WHERE " + SqlSyntax.GetQuotedColumnName("user") + "=@Id", - "DELETE FROM umbracoUser WHERE id = @Id", - "DELETE FROM umbracoExternalLogin WHERE id = @Id" - }; + { + "DELETE FROM cmsTask WHERE userId = @Id", + "DELETE FROM cmsTask WHERE parentUserId = @Id", + "DELETE FROM umbracoUser2UserGroup WHERE userId = @Id", + "DELETE FROM umbracoUser2NodeNotify WHERE userId = @Id", + "DELETE FROM umbracoUser WHERE id = @Id", + "DELETE FROM umbracoExternalLogin WHERE id = @Id" + }; return list; } - protected override Guid NodeObjectTypeId - { - get { throw new NotImplementedException(); } - } + protected override Guid NodeObjectTypeId => throw new NotImplementedException(); protected override void PersistNewItem(IUser entity) { - var userFactory = new UserFactory(entity.UserType); + ((User) entity).AddingEntity(); - //ensure security stamp if non + // ensure security stamp if missing if (entity.SecurityStamp.IsNullOrWhiteSpace()) - { entity.SecurityStamp = Guid.NewGuid().ToString(); - } - var userDto = userFactory.BuildDto(entity); + var userDto = UserFactory.BuildDto(entity); + + // check if we have a known config, we only want to store config for hashing + //TODO: This logic will need to be updated when we do http://issues.umbraco.org/issue/U4-10089 + if (_passwordConfig != null && _passwordConfig.Count > 0) + { + var json = JsonConvert.SerializeObject(_passwordConfig); + userDto.PasswordConfig = json; + } var id = Convert.ToInt32(Database.Insert(userDto)); entity.Id = id; - foreach (var sectionDto in userDto.User2AppDtos) + if (entity.IsPropertyDirty("StartContentIds")) { - //need to set the id explicitly here - sectionDto.UserId = id; - Database.Insert(sectionDto); + AddingOrUpdateStartNodes(entity, Enumerable.Empty(), UserStartNodeDto.StartNodeTypeValue.Content, entity.StartContentIds); + } + + if (entity.IsPropertyDirty("StartMediaIds")) + { + AddingOrUpdateStartNodes(entity, Enumerable.Empty(), UserStartNodeDto.StartNodeTypeValue.Media, entity.StartMediaIds); + } + + if (entity.IsPropertyDirty("Groups")) + { + // lookup all assigned + var assigned = entity.Groups == null || entity.Groups.Any() == false + ? new List() + : Database.Fetch("SELECT * FROM umbracoUserGroup WHERE userGroupAlias IN (@aliases)", new { aliases = entity.Groups.Select(x => x.Alias) }); + + foreach (var groupDto in assigned) + { + var dto = new User2UserGroupDto + { + UserGroupId = groupDto.Id, + UserId = entity.Id + }; + Database.Insert(dto); + } } entity.ResetDirtyProperties(); @@ -181,25 +381,21 @@ namespace Umbraco.Core.Persistence.Repositories protected override void PersistUpdatedItem(IUser entity) { - var userFactory = new UserFactory(entity.UserType); + // updates Modified date + ((User) entity).UpdatingEntity(); - //ensure security stamp if non + // ensure security stamp if missing if (entity.SecurityStamp.IsNullOrWhiteSpace()) - { entity.SecurityStamp = Guid.NewGuid().ToString(); - } - var userDto = userFactory.BuildDto(entity); + var userDto = UserFactory.BuildDto(entity); - var dirtyEntity = (ICanBeDirty)entity; - - //build list of columns to check for saving - we don't want to save the password if it hasn't changed! - //List the columns to save, NOTE: would be nice to not have hard coded strings here but no real good way around that - var colsToSave = new Dictionary() + // build list of columns to check for saving - we don't want to save the password if it hasn't changed! + // list the columns to save, NOTE: would be nice to not have hard coded strings here but no real good way around that + var colsToSave = new Dictionary { {"userDisabled", "IsApproved"}, {"userNoConsole", "IsLockedOut"}, - {"userType", "UserType"}, {"startStructureID", "StartContentId"}, {"startMediaID", "StartMediaId"}, {"userName", "Name"}, @@ -211,27 +407,42 @@ namespace Umbraco.Core.Persistence.Repositories {"lastPasswordChangeDate", "LastPasswordChangeDate"}, {"lastLoginDate", "LastLoginDate"}, {"failedLoginAttempts", "FailedPasswordAttempts"}, + {"createDate", "CreateDate"}, + {"updateDate", "UpdateDate"}, + {"avatar", "Avatar"}, + {"emailConfirmedDate", "EmailConfirmedDate"}, + {"invitedDate", "InvitedDate"} }; - //create list of properties that have changed + // create list of properties that have changed var changedCols = colsToSave - .Where(col => dirtyEntity.IsPropertyDirty(col.Value)) + .Where(col => entity.IsPropertyDirty(col.Value)) .Select(col => col.Key) .ToList(); // DO NOT update the password if it has not changed or if it is null or empty - if (dirtyEntity.IsPropertyDirty("RawPasswordValue") && entity.RawPasswordValue.IsNullOrWhiteSpace() == false) + if (entity.IsPropertyDirty("RawPasswordValue") && entity.RawPasswordValue.IsNullOrWhiteSpace() == false) { changedCols.Add("userPassword"); - //special case - when using ASP.Net identity the user manager will take care of updating the security stamp, however + // special case - when using ASP.Net identity the user manager will take care of updating the security stamp, however // when not using ASP.Net identity (i.e. old membership providers), we'll need to take care of updating this manually // so we can just detect if that property is dirty, if it's not we'll set it manually - if (dirtyEntity.IsPropertyDirty("SecurityStamp") == false) + if (entity.IsPropertyDirty("SecurityStamp") == false) { userDto.SecurityStampToken = entity.SecurityStamp = Guid.NewGuid().ToString(); changedCols.Add("securityStampToken"); } + + // check if we have a known config, we only want to store config for hashing + //TODO: This logic will need to be updated when we do http://issues.umbraco.org/issue/U4-10089 + if (_passwordConfig != null && _passwordConfig.Count > 0) + { + var json = JsonConvert.SerializeObject(_passwordConfig); + userDto.PasswordConfig = json; + + changedCols.Add("passwordConfig"); + } } //only update the changed cols @@ -240,42 +451,66 @@ namespace Umbraco.Core.Persistence.Repositories Database.Update(userDto, changedCols); } - //update the sections if they've changed - var user = (User)entity; - if (user.IsPropertyDirty("AllowedSections")) + if (entity.IsPropertyDirty("StartContentIds") || entity.IsPropertyDirty("StartMediaIds")) { - //now we need to delete any applications that have been removed - foreach (var section in user.RemovedSections) + var assignedStartNodes = Database.Fetch("SELECT * FROM umbracoUserStartNode WHERE userId = @userId", new { userId = entity.Id }); + if (entity.IsPropertyDirty("StartContentIds")) { - //we need to manually delete thsi record because it has a composite key - Database.Delete("WHERE app=@Section AND " + SqlSyntax.GetQuotedColumnName("user") + "=@UserId", - new { Section = section, UserId = (int)user.Id }); + AddingOrUpdateStartNodes(entity, assignedStartNodes, UserStartNodeDto.StartNodeTypeValue.Content, entity.StartContentIds); } - - //for any that exist on the object, we need to determine if we need to update or insert - //NOTE: the User2AppDtos collection wil always be equal to the User.AllowedSections - foreach (var sectionDto in userDto.User2AppDtos) + if (entity.IsPropertyDirty("StartMediaIds")) { - //if something has been added then insert it - if (user.AddedSections.Contains(sectionDto.AppAlias)) - { - //we need to insert since this was added - Database.Insert(sectionDto); - } - else - { - //we need to manually update this record because it has a composite key - Database.Update("SET app=@Section WHERE app=@Section AND " + SqlSyntax.GetQuotedColumnName("user") + "=@UserId", - new { Section = sectionDto.AppAlias, UserId = sectionDto.UserId }); - } + AddingOrUpdateStartNodes(entity, assignedStartNodes, UserStartNodeDto.StartNodeTypeValue.Media, entity.StartMediaIds); } + } + if (entity.IsPropertyDirty("Groups")) + { + //lookup all assigned + var assigned = entity.Groups == null || entity.Groups.Any() == false + ? new List() + : Database.Fetch("SELECT * FROM umbracoUserGroup WHERE userGroupAlias IN (@aliases)", new { aliases = entity.Groups.Select(x => x.Alias) }); + //first delete all + //TODO: We could do this a nicer way instead of "Nuke and Pave" + Database.Delete("WHERE UserId = @UserId", new { UserId = entity.Id }); + + foreach (var groupDto in assigned) + { + var dto = new User2UserGroupDto + { + UserGroupId = groupDto.Id, + UserId = entity.Id + }; + Database.Insert(dto); + } } entity.ResetDirtyProperties(); } + private void AddingOrUpdateStartNodes(IEntity entity, IEnumerable current, UserStartNodeDto.StartNodeTypeValue startNodeType, int[] entityStartIds) + { + var assignedIds = current.Where(x => x.StartNodeType == (int)startNodeType).Select(x => x.StartNode).ToArray(); + + //remove the ones not assigned to the entity + var toDelete = assignedIds.Except(entityStartIds).ToArray(); + if (toDelete.Length > 0) + Database.Delete("WHERE UserId = @UserId AND startNode IN (@startNodes)", new { UserId = entity.Id, startNodes = toDelete }); + //add the ones not currently in the db + var toAdd = entityStartIds.Except(assignedIds).ToArray(); + foreach (var i in toAdd) + { + var dto = new UserStartNodeDto + { + StartNode = i, + StartNodeType = (int)startNodeType, + UserId = entity.Id + }; + Database.Insert(dto); + } + } + #endregion #region Implementation of IUserRepository @@ -302,47 +537,81 @@ namespace Umbraco.Core.Persistence.Repositories return Database.ExecuteScalar(sql) > 0; } - public IEnumerable GetUsersAssignedToSection(string sectionAlias) + /// + /// Gets a list of objects associated with a given group + /// + /// Id of group + public IEnumerable GetAllInGroup(int groupId) { - //Here we're building up a query that looks like this, a sub query is required because the resulting structure - // needs to still contain all of the section rows per user. + return GetAllInOrNotInGroup(groupId, true); + } - //SELECT * - //FROM [umbracoUser] - //LEFT JOIN [umbracoUser2app] - //ON [umbracoUser].[id] = [umbracoUser2app].[user] - //WHERE umbracoUser.id IN (SELECT umbracoUser.id - // FROM [umbracoUser] - // LEFT JOIN [umbracoUser2app] - // ON [umbracoUser].[id] = [umbracoUser2app].[user] - // WHERE umbracoUser2app.app = 'content') + /// + /// Gets a list of objects not associated with a given group + /// + /// Id of group + public IEnumerable GetAllNotInGroup(int groupId) + { + return GetAllInOrNotInGroup(groupId, false); + } - var sql = GetBaseQuery(false); - var innerSql = GetBaseQuery("umbracoUser.id"); - innerSql.Where("umbracoUser2app.app = " + SqlSyntax.GetQuotedValue(sectionAlias)); - sql.Where(string.Format("umbracoUser.id IN ({0})", innerSql.SQL)); + private IEnumerable GetAllInOrNotInGroup(int groupId, bool include) + { + #error this needs to be rewritten + var sql = new Sql(); + sql.Select("*") + .From(); - var dtos = Database - .FetchOneToMany(x => x.User2AppDtos, sql); + var innerSql = new Sql(); + innerSql.Select("umbracoUser.id") + .From() + .LeftJoin() + .On(left => left.Id, right => right.UserId) + .Where("umbracoUser2UserGroup.userGroupId = " + groupId); - return ConvertFromDtos(dtos); + sql.Where(string.Format("umbracoUser.id {0} ({1})", + include ? "IN" : "NOT IN", + innerSql.SQL)); + return ConvertFromDtos(Database.Fetch(sql)); + } + + [Obsolete("Use the overload with long operators instead")] + [EditorBrowsable(EditorBrowsableState.Never)] + public IEnumerable GetPagedResultsByQuery(IQuery query, int pageIndex, int pageSize, out int totalRecords, Expression> orderBy) + { + if (orderBy == null) throw new ArgumentNullException("orderBy"); + + // get the referenced column name and find the corresp mapped column name + var expressionMember = ExpressionHelper.GetMemberInfo(orderBy); + var mapper = MappingResolver.Current.ResolveMapperByType(typeof(IUser)); + var mappedField = mapper.Map(expressionMember.Name); + + if (mappedField.IsNullOrWhiteSpace()) + throw new ArgumentException("Could not find a mapping for the column specified in the orderBy clause"); + + long tr; + var results = GetPagedResultsByQuery(query, Convert.ToInt64(pageIndex), pageSize, out tr, mappedField, Direction.Ascending); + totalRecords = Convert.ToInt32(tr); + return results; } /// /// Gets paged user results /// - /// - /// The where clause, if this is null all records are queried - /// + /// /// /// /// /// + /// + /// Optional parameter to filter by specified user groups + /// Optional parameter to filter by specfied user state + /// /// /// /// The query supplied will ONLY work with data specifically on the umbracoUser table because we are using NPoco paging (SQL paging) /// - public IEnumerable GetPagedResultsByQuery(IQuery query, long pageIndex, int pageSize, out long totalRecords, Expression> orderBy) + public IEnumerable GetPagedResultsByQuery(IQuery query, long pageIndex, int pageSize, out long totalRecords, Expression> orderBy, Direction orderDirection, string[] userGroups = null, UserState[] userState = null, IQuery filter = null) { if (orderBy == null) throw new ArgumentNullException(nameof(orderBy)); @@ -354,29 +623,180 @@ namespace Umbraco.Core.Persistence.Repositories if (mappedField.IsNullOrWhiteSpace()) throw new ArgumentException("Could not find a mapping for the column specified in the orderBy clause"); - var sql = Sql() - .Select("umbracoUser.Id") - .From(); + return GetPagedResultsByQuery(query, pageIndex, pageSize, out totalRecords, mappedField, orderDirection, userGroups, userState, filter); + } - var idsQuery = query == null ? sql : new SqlTranslator(sql, query).Translate(); - // need to ensure the order by is in brackets, see: https://github.com/toptensoftware/PetaPoco/issues/177 - idsQuery.OrderBy("(" + mappedField + ")"); - var page = Database.Page(pageIndex + 1, pageSize, idsQuery); - totalRecords = Convert.ToInt32(page.TotalItems); - if (totalRecords == 0) - return Enumerable.Empty(); + private IEnumerable GetPagedResultsByQuery(IQuery query, long pageIndex, int pageSize, out long totalRecords, string orderBy, Direction orderDirection, + string[] userGroups = null, + UserState[] userState = null, + IQuery filter = null) + { + if (string.IsNullOrWhiteSpace(orderBy)) throw new ArgumentException("Value cannot be null or whitespace.", "orderBy"); - // now get the actual users and ensure they are ordered properly (same clause) - var ids = page.Items.ToArray(); - return ids.Length == 0 ? Enumerable.Empty() : GetAll(ids).OrderBy(orderBy.Compile()); + + Sql filterSql = null; + if (filter != null || (userGroups != null && userGroups.Length > 0) || (userState != null && userState.Length > 0 && userState.Contains(UserState.All) == false)) + filterSql = new Sql(); + + if (filter != null) + { + foreach (var filterClause in filter.GetWhereClauses()) + { + filterSql.Append(string.Format("AND ({0})", filterClause.Item1), filterClause.Item2); + } + } + if (userGroups != null && userGroups.Length > 0) + { + var subQuery = @"AND (umbracoUser.id IN (SELECT DISTINCT umbracoUser.id + FROM umbracoUser + INNER JOIN umbracoUser2UserGroup ON umbracoUser2UserGroup.userId = umbracoUser.id + INNER JOIN umbracoUserGroup ON umbracoUserGroup.id = umbracoUser2UserGroup.userGroupId + WHERE umbracoUserGroup.userGroupAlias IN (@userGroups)))"; + filterSql.Append(subQuery, new { userGroups = userGroups }); + } + if (userState != null && userState.Length > 0) + { + //the "ALL" state doesn't require any filtering so we ignore that, if it exists in the list we don't do any filtering + if (userState.Contains(UserState.All) == false) + { + var sb = new StringBuilder("("); + var appended = false; + + if (userState.Contains(UserState.Active)) + { + sb.Append("(userDisabled = 0 AND userNoConsole = 0 AND lastLoginDate IS NOT NULL)"); + appended = true; + } + if (userState.Contains(UserState.Disabled)) + { + if (appended) sb.Append(" OR "); + sb.Append("(userDisabled = 1)"); + } + if (userState.Contains(UserState.LockedOut)) + { + if (appended) sb.Append(" OR "); + sb.Append("(userNoConsole = 1)"); + } + if (userState.Contains(UserState.Invited)) + { + if (appended) sb.Append(" OR "); + sb.Append("(lastLoginDate IS NULL AND userDisabled = 1 AND invitedDate IS NOT NULL)"); + } + + sb.Append(")"); + + filterSql.Append("AND " + sb); + } + } + + // Get base query for returning IDs + var sqlBaseIds = GetBaseQuery("id"); + + if (query == null) query = new Query(); + var translatorIds = new SqlTranslator(sqlBaseIds, query); + var sqlQueryIds = translatorIds.Translate(); + + //get sorted and filtered sql + var sqlNodeIdsWithSort = GetSortedSqlForPagedResults( + GetFilteredSqlForPagedResults(sqlQueryIds, filterSql), + orderDirection, orderBy); + + // Get page of results and total count + var pagedResult = Database.Page(pageIndex + 1, pageSize, sqlNodeIdsWithSort); + totalRecords = Convert.ToInt32(pagedResult.TotalItems); + + //NOTE: We need to check the actual items returned, not the 'totalRecords', that is because if you request a page number + // that doesn't actually have any data on it, the totalRecords will still indicate there are records but there are none in + // the pageResult. + if (pagedResult.Items.Any()) + { + //Create the inner paged query that was used above to get the paged result, we'll use that as the inner sub query + var args = sqlNodeIdsWithSort.Arguments; + string sqlStringCount, sqlStringPage; + Database.BuildPageQueries(pageIndex * pageSize, pageSize, sqlNodeIdsWithSort.SQL, ref args, out sqlStringCount, out sqlStringPage); + + var sqlQueryFull = GetBaseQuery("umbracoUser.*, umbracoUserGroup.*, umbracoUserGroup2App.*, umbracoUserStartNode.*"); + + var fullQueryWithPagedInnerJoin = sqlQueryFull + .Append("INNER JOIN (") + //join the paged query with the paged query arguments + .Append(sqlStringPage, args) + .Append(") temp ") + .Append("ON umbracoUser.id = temp.id"); + + AddGroupLeftJoin(fullQueryWithPagedInnerJoin); + + //get sorted and filtered sql + var fullQuery = GetSortedSqlForPagedResults( + GetFilteredSqlForPagedResults(fullQueryWithPagedInnerJoin, filterSql), + orderDirection, orderBy); + + var users = ConvertFromDtos(Database.Fetch(new UserGroupRelator().Map, fullQuery)) + .ToArray(); // important so we don't iterate twice, if we don't do this we can end up with null values in cache if we were caching. + + return users; + } + + return Enumerable.Empty(); + } + + private Sql GetFilteredSqlForPagedResults(Sql sql, Sql filterSql) + { + Sql filteredSql; + + // Apply filter + if (filterSql != null) + { + var sqlFilter = " WHERE " + filterSql.SQL.TrimStart("AND "); + + //NOTE: this is certainly strange - NPoco handles this much better but we need to re-create the sql + // instance a couple of times to get the parameter order correct, for some reason the first + // time the arguments don't show up correctly but the SQL argument parameter names are actually updated + // accordingly - so we re-create it again. In v8 we don't need to do this and it's already taken care of. + + filteredSql = new Sql(sql.SQL, sql.Arguments); + var args = filteredSql.Arguments.Concat(filterSql.Arguments).ToArray(); + filteredSql = new Sql( + string.Format("{0} {1}", filteredSql.SQL, sqlFilter), + args); + filteredSql = new Sql(filteredSql.SQL, args); + } + else + { + //copy to var so that the original isn't changed + filteredSql = new Sql(sql.SQL, sql.Arguments); + } + return filteredSql; + } + + private Sql GetSortedSqlForPagedResults(Sql sql, Direction orderDirection, string orderBy) + { + //copy to var so that the original isn't changed + var sortedSql = new Sql(sql.SQL, sql.Arguments); + + // Apply order according to parameters + if (string.IsNullOrEmpty(orderBy) == false) + { + //each order by param needs to be in a bracket! see: https://github.com/toptensoftware/PetaPoco/issues/177 + var orderByParams = new[] { string.Format("({0})", orderBy) }; + if (orderDirection == Direction.Ascending) + { + sortedSql.OrderBy(orderByParams); + } + else + { + sortedSql.OrderByDescending(orderByParams); + } + } + return sortedSql; } internal IEnumerable GetNextUsers(int id, int count) { var idsQuery = Sql() - .Select("umbracoUser.Id") + .Select("umbracoUser.id") .From() .Where(x => x.Id >= id) .OrderBy(x => x.Id); @@ -388,54 +808,11 @@ namespace Umbraco.Core.Persistence.Repositories return ids.Length == 0 ? Enumerable.Empty() : GetAll(ids).OrderBy(x => x.Id); } - /// - /// Returns permissions for a given user for any number of nodes - /// - /// - /// - /// - public IEnumerable GetUserPermissionsForEntities(int userId, params int[] entityIds) - { - return PermissionRepository.GetUserPermissionsForEntities(userId, entityIds); - } - - /// - /// Replaces the same permission set for a single user to any number of entities - /// - /// - /// - /// - public void ReplaceUserPermissions(int userId, IEnumerable permissions, params int[] entityIds) - { - PermissionRepository.ReplaceUserPermissions(userId, permissions, entityIds); - } - - /// - /// Assigns the same permission set for a single user to any number of entities - /// - /// - /// - /// - public void AssignUserPermission(int userId, char permission, params int[] entityIds) - { - PermissionRepository.AssignUserPermission(userId, permission, entityIds); - } - #endregion private IEnumerable ConvertFromDtos(IEnumerable dtos) { - var userTypeIds = dtos.Select(x => Convert.ToInt32(x.Type)).ToArray(); - - var allUserTypes = userTypeIds.Length == 0 ? Enumerable.Empty() : _userTypeRepository.GetAll(userTypeIds); - - return dtos.Select(dto => - { - var userType = allUserTypes.Single(x => x.Id == dto.Type); - - var userFactory = new UserFactory(userType); - return userFactory.BuildEntity(dto); - }); + return dtos.Select(UserFactory.BuildEntity); } } } diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index d8a86e250e..7982c105bb 100644 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -1146,8 +1146,8 @@ + - @@ -1181,8 +1181,8 @@ + -