diff --git a/src/Umbraco.Core/Configuration/GlobalSettings.cs b/src/Umbraco.Core/Configuration/GlobalSettings.cs index 33b8443d11..060ecf5d17 100644 --- a/src/Umbraco.Core/Configuration/GlobalSettings.cs +++ b/src/Umbraco.Core/Configuration/GlobalSettings.cs @@ -23,6 +23,9 @@ namespace Umbraco.Core.Configuration // http://issues.umbraco.org/issue/U4-58 // http://issues.umbraco.org/issue/U4-115 + // TODO: There's a current task and branch to refactor this into interfaces and proper config: http://issues.umbraco.org/issue/U4-8861 + // PR https://github.com/umbraco/Umbraco-CMS/compare/dev-v8...temp-U4-8861?expand=1 + //TODO: Replace checking for if the app settings exist and returning an empty string, instead return the defaults! /// diff --git a/src/Umbraco.Core/Manifest/ManifestParser.cs b/src/Umbraco.Core/Manifest/ManifestParser.cs index 32070b3542..cad491aeb1 100644 --- a/src/Umbraco.Core/Manifest/ManifestParser.cs +++ b/src/Umbraco.Core/Manifest/ManifestParser.cs @@ -120,7 +120,12 @@ namespace Umbraco.Core.Manifest // gets all manifest files (recursively) private IEnumerable GetManifestFiles() - => Directory.GetFiles(_path, "package.manifest", SearchOption.AllDirectories); + { + if (Directory.Exists(_path) == false) + return new string[0]; + return Directory.GetFiles(_path, "package.manifest", SearchOption.AllDirectories); + } + private static string TrimPreamble(string text) { diff --git a/src/Umbraco.Core/Migrations/Expressions/Insert/Expressions/InsertDataExpression.cs b/src/Umbraco.Core/Migrations/Expressions/Insert/Expressions/InsertDataExpression.cs index d06a5a9bfe..7efe457402 100644 --- a/src/Umbraco.Core/Migrations/Expressions/Insert/Expressions/InsertDataExpression.cs +++ b/src/Umbraco.Core/Migrations/Expressions/Insert/Expressions/InsertDataExpression.cs @@ -32,12 +32,25 @@ namespace Umbraco.Core.Migrations.Expressions.Insert.Expressions { foreach (var item in Rows) { - var cols = string.Join(",", item.Select(x => x.Key)); - var vals = string.Join(",", item.Select(x => x.Value)); + var cols = new StringBuilder(); + var vals = new StringBuilder(); + var first = true; + foreach (var keyVal in item) + { + if (first) + { + first = false; + } + else + { + cols.Append(","); + vals.Append(","); + } + cols.Append(SqlSyntax.GetQuotedColumnName(keyVal.Key)); + vals.Append(GetQuotedValue(keyVal.Value)); + } - var sql = string.Format(SqlSyntax.InsertData, - SqlSyntax.GetQuotedTableName(TableName), - cols, vals); + var sql = string.Format(SqlSyntax.InsertData, SqlSyntax.GetQuotedTableName(TableName), cols, vals); stmts.Append(sql); AppendStatementSeparator(stmts); diff --git a/src/Umbraco.Core/Migrations/MigrationBase_Extra.cs b/src/Umbraco.Core/Migrations/MigrationBase_Extra.cs index 0f871abb5d..b1b405bcf4 100644 --- a/src/Umbraco.Core/Migrations/MigrationBase_Extra.cs +++ b/src/Umbraco.Core/Migrations/MigrationBase_Extra.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; using System.Linq; using Umbraco.Core.Persistence.DatabaseModelDefinitions; +using Umbraco.Core.Persistence.SqlSyntax; namespace Umbraco.Core.Migrations { @@ -14,31 +15,48 @@ namespace Umbraco.Core.Migrations protected void AddColumn(string columnName) { var table = DefinitionFactory.GetTableDefinition(typeof(T), SqlSyntax); - var column = table.Columns.First(x => x.Name == columnName); - var createSql = SqlSyntax.Format(column); - Database.Execute(string.Format(SqlSyntax.AddColumn, SqlSyntax.GetQuotedTableName(table.Name), createSql)); + AddColumn(table, table.Name, columnName); } protected void AddColumn(string tableName, string columnName) { - //if (ColumnExists(tableName, columnName)) - // throw new InvalidOperationException($"Column {tableName}.{columnName} already exists."); - var table = DefinitionFactory.GetTableDefinition(typeof(T), SqlSyntax); + AddColumn(table, tableName, columnName); + } + + private void AddColumn(TableDefinition table, string tableName, string columnName) + { + if (ColumnExists(tableName, columnName)) return; + var column = table.Columns.First(x => x.Name == columnName); var createSql = SqlSyntax.Format(column); - Database.Execute(string.Format(SqlSyntax.AddColumn, SqlSyntax.GetQuotedTableName(tableName), createSql)); + + Execute.Sql(string.Format(SqlSyntax.AddColumn, SqlSyntax.GetQuotedTableName(tableName), createSql)).Do(); + } + + protected void AddColumn(string columnName, out IEnumerable sqls) + { + var table = DefinitionFactory.GetTableDefinition(typeof(T), SqlSyntax); + AddColumn(table, table.Name, columnName, out sqls); } protected void AddColumn(string tableName, string columnName, out IEnumerable sqls) { - //if (ColumnExists(tableName, columnName)) - // throw new InvalidOperationException($"Column {tableName}.{columnName} already exists."); - var table = DefinitionFactory.GetTableDefinition(typeof(T), SqlSyntax); + AddColumn(table, tableName, columnName, out sqls); + } + + private void AddColumn(TableDefinition table, string tableName, string columnName, out IEnumerable sqls) + { + if (ColumnExists(tableName, columnName)) + { + sqls = Enumerable.Empty(); + return; + } + var column = table.Columns.First(x => x.Name == columnName); var createSql = SqlSyntax.Format(column, SqlSyntax.GetQuotedTableName(tableName), out sqls); - Database.Execute(string.Format(SqlSyntax.AddColumn, SqlSyntax.GetQuotedTableName(tableName), createSql)); + Execute.Sql(string.Format(SqlSyntax.AddColumn, SqlSyntax.GetQuotedTableName(tableName), createSql)).Do(); } protected void AlterColumn(string tableName, string columnName) @@ -47,14 +65,14 @@ namespace Umbraco.Core.Migrations var column = table.Columns.First(x => x.Name == columnName); SqlSyntax.Format(column, SqlSyntax.GetQuotedTableName(tableName), out var sqls); foreach (var sql in sqls) - Database.Execute(sql); + Execute.Sql(sql).Do(); } protected void ReplaceColumn(string tableName, string currentName, string newName) { AddColumn(tableName, newName, out var sqls); - Database.Execute($"UPDATE {SqlSyntax.GetQuotedTableName(tableName)} SET {SqlSyntax.GetQuotedColumnName(newName)}={SqlSyntax.GetQuotedColumnName(currentName)}"); - foreach (var sql in sqls) Database.Execute(sql); + Execute.Sql($"UPDATE {SqlSyntax.GetQuotedTableName(tableName)} SET {SqlSyntax.GetQuotedColumnName(newName)}={SqlSyntax.GetQuotedColumnName(currentName)}").Do(); + foreach (var sql in sqls) Execute.Sql(sql).Do(); Delete.Column(currentName).FromTable(tableName).Do(); } diff --git a/src/Umbraco.Core/Migrations/MigrationPlan.cs b/src/Umbraco.Core/Migrations/MigrationPlan.cs index 909415336b..f686ff283e 100644 --- a/src/Umbraco.Core/Migrations/MigrationPlan.cs +++ b/src/Umbraco.Core/Migrations/MigrationPlan.cs @@ -159,9 +159,8 @@ namespace Umbraco.Core.Migrations var nextState = transition.TargetState; origState = nextState; - - // ReSharper disable once AccessToModifiedClosure - _logger.Info("At \"{0}\".", () => origState); + + _logger.Info("At \"{0}\".", origState); if (!_transitions.TryGetValue(origState, out transition)) throw new Exception($"Unknown state \"{origState}\"."); diff --git a/src/Umbraco.Core/Migrations/Upgrade/UmbracoPlan.cs b/src/Umbraco.Core/Migrations/Upgrade/UmbracoPlan.cs index 3f676c78bf..8985fd436d 100644 --- a/src/Umbraco.Core/Migrations/Upgrade/UmbracoPlan.cs +++ b/src/Umbraco.Core/Migrations/Upgrade/UmbracoPlan.cs @@ -143,6 +143,7 @@ namespace Umbraco.Core.Migrations.Upgrade Chain("{139F26D7-7E08-48E3-81D9-E50A21A72F67}"); Chain("{CC1B1201-1328-443C-954A-E0BBB8CCC1B5}"); Chain("{CA7DB949-3EF4-403D-8464-F9BA36A52E87}"); + Chain("{7F0BF916-F64E-4B25-864A-170D6E6B68E5}"); // at this point of the chain, people started to work on v8, so whenever we // merge stuff from v7, we have to chain the migrations here so they also @@ -159,15 +160,10 @@ namespace Umbraco.Core.Migrations.Upgrade Chain("{89A728D1-FF4C-4155-A269-62CC09AD2131}"); Chain("{FD8631BC-0388-425C-A451-5F58574F6F05}"); Chain("{2821F53E-C58B-4812-B184-9CD240F990D7}"); - Chain("{8918450B-3DA0-4BB7-886A-6FA8B7E4186E}"); // final state + Chain("{8918450B-3DA0-4BB7-886A-6FA8B7E4186E}"); + Chain("FIXGUID NEW FINAL"); - // BEWARE! whenever changing the final state, update below! - - - // INSTALL - // - // when installing, the source state is empty, and the target state should be the final state. - // BEWARE! this MUST match the final state above! + // FINAL STATE - MUST MATCH LAST ONE ABOVE ! Add(string.Empty, "{8918450B-3DA0-4BB7-886A-6FA8B7E4186E}"); } diff --git a/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/DataTypeMigration.cs b/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/DataTypeMigration.cs index 08121df815..eb39f37112 100644 --- a/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/DataTypeMigration.cs +++ b/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/DataTypeMigration.cs @@ -29,18 +29,17 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0 Rename.Table("cmsDataType").To(Constants.DatabaseSchema.Tables.DataType).Do(); // create column - // fixme it is annoying that these are NOT written out to the log?! AddColumn(Constants.DatabaseSchema.Tables.DataType, "config"); - Database.Execute(Sql().Update(u => u.Set(x => x.Configuration, string.Empty))); + Execute.Sql(Sql().Update(u => u.Set(x => x.Configuration, string.Empty)).SQL).Do(); // re-create *all* keys and indexes foreach (var x in DatabaseSchemaCreator.OrderedTables) Create.KeysAndIndexes(x).Do(); // renames - Database.Execute(Sql() + Execute.Sql(Sql() .Update(u => u.Set(x => x.EditorAlias, "Umbraco.ColorPicker")) - .Where(x => x.EditorAlias == "Umbraco.ColorPickerAlias")); + .Where(x => x.EditorAlias == "Umbraco.ColorPickerAlias").SQL).Do(); // from preValues to configuration... var sql = Sql() diff --git a/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/LanguageColumns.cs b/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/LanguageColumns.cs new file mode 100644 index 0000000000..e8a1197d37 --- /dev/null +++ b/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/LanguageColumns.cs @@ -0,0 +1,17 @@ +using Umbraco.Core.Persistence.Dtos; + +namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0 +{ + public class LanguageColumns : MigrationBase + { + public LanguageColumns(IMigrationContext context) + : base(context) + { } + + public override void Migrate() + { + AddColumn(Constants.DatabaseSchema.Tables.Language, "isDefaultVariantLang"); + AddColumn(Constants.DatabaseSchema.Tables.Language, "mandatory"); + } + } +} diff --git a/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/SuperZero.cs b/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/SuperZero.cs index f9b1a959f8..ba29880e79 100644 --- a/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/SuperZero.cs +++ b/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/SuperZero.cs @@ -25,7 +25,7 @@ Database.Execute("update umbracoUser2UserGroup set userId=-1 where userId=0;"); Database.Execute("update umbracoNode set nodeUser=-1 where nodeUser=0;"); - Database.Execute("update uContentVersion set userId=-1 where userId=0;"); + Database.Execute($"update {Constants.DatabaseSchema.Tables.ContentVersion} set userId=-1 where userId=0;"); Database.Execute("delete from umbracoUser where id=0;"); } } diff --git a/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/VariantsMigration.cs b/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/VariantsMigration.cs index 72241fb496..174404b1b9 100644 --- a/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/VariantsMigration.cs +++ b/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/VariantsMigration.cs @@ -29,20 +29,20 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0 MigrateContent(); MigrateVersions(); - if (Database.Fetch(@"SELECT uContentVersion.nodeId, COUNT(uContentVersion.id) -FROM uContentVersion -JOIN uDocumentVersion ON uContentVersion.id=uDocumentVersion.id -WHERE uDocumentVersion.published=1 -GROUP BY uContentVersion.nodeId -HAVING COUNT(uContentVersion.id) > 1").Any()) + if (Database.Fetch($@"SELECT {Constants.DatabaseSchema.Tables.ContentVersion}.nodeId, COUNT({Constants.DatabaseSchema.Tables.ContentVersion}.id) +FROM {Constants.DatabaseSchema.Tables.ContentVersion} +JOIN {Constants.DatabaseSchema.Tables.DocumentVersion} ON {Constants.DatabaseSchema.Tables.ContentVersion}.id={Constants.DatabaseSchema.Tables.DocumentVersion}.id +WHERE {Constants.DatabaseSchema.Tables.DocumentVersion}.published=1 +GROUP BY {Constants.DatabaseSchema.Tables.ContentVersion}.nodeId +HAVING COUNT({Constants.DatabaseSchema.Tables.ContentVersion}.id) > 1").Any()) { Debugger.Break(); throw new Exception("Migration failed: duplicate 'published' document versions."); } - if (Database.Fetch(@"SELECT v1.nodeId, v1.id, COUNT(v2.id) -FROM uContentVersion v1 -LEFT JOIN uContentVersion v2 ON v1.nodeId=v2.nodeId AND v2.[current]=1 + if (Database.Fetch($@"SELECT v1.nodeId, v1.id, COUNT(v2.id) +FROM {Constants.DatabaseSchema.Tables.ContentVersion} v1 +LEFT JOIN {Constants.DatabaseSchema.Tables.ContentVersion} v2 ON v1.nodeId=v2.nodeId AND v2.[current]=1 GROUP BY v1.nodeId, v1.id HAVING COUNT(v2.id) <> 1").Any()) { diff --git a/src/Umbraco.Core/Models/ILanguage.cs b/src/Umbraco.Core/Models/ILanguage.cs index 8eb9063302..23cef54180 100644 --- a/src/Umbraco.Core/Models/ILanguage.cs +++ b/src/Umbraco.Core/Models/ILanguage.cs @@ -23,5 +23,15 @@ namespace Umbraco.Core.Models /// [IgnoreDataMember] CultureInfo CultureInfo { get; } + + /// + /// Defines if this language is the default variant language when language variants are in use + /// + bool IsDefaultVariantLanguage { get; set; } + + /// + /// If true, a variant node cannot be published unless this language variant is created + /// + bool Mandatory { get; set; } } } diff --git a/src/Umbraco.Core/Models/Language.cs b/src/Umbraco.Core/Models/Language.cs index 6dfe59778f..a143a8c457 100644 --- a/src/Umbraco.Core/Models/Language.cs +++ b/src/Umbraco.Core/Models/Language.cs @@ -17,6 +17,8 @@ namespace Umbraco.Core.Models private string _isoCode; private string _cultureName; + private bool _isDefaultVariantLanguage; + private bool _mandatory; public Language(string isoCode) { @@ -28,6 +30,8 @@ namespace Umbraco.Core.Models { public readonly PropertyInfo IsoCodeSelector = ExpressionHelper.GetPropertyInfo(x => x.IsoCode); public readonly PropertyInfo CultureNameSelector = ExpressionHelper.GetPropertyInfo(x => x.CultureName); + public readonly PropertyInfo IsDefaultVariantLanguageSelector = ExpressionHelper.GetPropertyInfo(x => x.IsDefaultVariantLanguage); + public readonly PropertyInfo MandatorySelector = ExpressionHelper.GetPropertyInfo(x => x.Mandatory); } /// @@ -55,5 +59,17 @@ namespace Umbraco.Core.Models /// [IgnoreDataMember] public CultureInfo CultureInfo => CultureInfo.GetCultureInfo(IsoCode); + + public bool IsDefaultVariantLanguage + { + get => _isDefaultVariantLanguage; + set => SetPropertyValueAndDetectChanges(value, ref _isDefaultVariantLanguage, Ps.Value.IsDefaultVariantLanguageSelector); + } + + public bool Mandatory + { + get => _mandatory; + set => SetPropertyValueAndDetectChanges(value, ref _mandatory, Ps.Value.MandatorySelector); + } } } diff --git a/src/Umbraco.Core/Persistence/Constants-DatabaseSchema.cs b/src/Umbraco.Core/Persistence/Constants-DatabaseSchema.cs index 59eee2fd80..a245f33dd8 100644 --- a/src/Umbraco.Core/Persistence/Constants-DatabaseSchema.cs +++ b/src/Umbraco.Core/Persistence/Constants-DatabaseSchema.cs @@ -5,7 +5,7 @@ namespace Umbraco.Core { public static class DatabaseSchema { - public const string TableNamePrefix = "u"; + public const string TableNamePrefix = "umbraco"; public static class Tables { diff --git a/src/Umbraco.Core/Persistence/Dtos/LanguageDto.cs b/src/Umbraco.Core/Persistence/Dtos/LanguageDto.cs index 83745a2bfe..78e5670830 100644 --- a/src/Umbraco.Core/Persistence/Dtos/LanguageDto.cs +++ b/src/Umbraco.Core/Persistence/Dtos/LanguageDto.cs @@ -22,5 +22,19 @@ namespace Umbraco.Core.Persistence.Dtos [NullSetting(NullSetting = NullSettings.Null)] [Length(100)] public string CultureName { get; set; } + + /// + /// Defines if this language is the default variant language when language variants are in use + /// + [Column("isDefaultVariantLang")] + [Constraint(Default = "0")] + public bool IsDefaultVariantLanguage { get; set; } + + /// + /// If true, a variant node cannot be published unless this language variant is created + /// + [Column("mandatory")] + [Constraint(Default = "0")] + public bool Mandatory { get; set; } } } diff --git a/src/Umbraco.Core/Persistence/Factories/LanguageFactory.cs b/src/Umbraco.Core/Persistence/Factories/LanguageFactory.cs index f15313622b..f79dab1bbd 100644 --- a/src/Umbraco.Core/Persistence/Factories/LanguageFactory.cs +++ b/src/Umbraco.Core/Persistence/Factories/LanguageFactory.cs @@ -8,7 +8,7 @@ namespace Umbraco.Core.Persistence.Factories { public ILanguage BuildEntity(LanguageDto dto) { - var lang = new Language(dto.IsoCode) { CultureName = dto.CultureName, Id = dto.Id }; + var lang = new Language(dto.IsoCode) { CultureName = dto.CultureName, Id = dto.Id, IsDefaultVariantLanguage = dto.IsDefaultVariantLanguage, Mandatory = dto.Mandatory }; // reset dirty initial properties (U4-1946) lang.ResetDirtyProperties(false); return lang; @@ -16,7 +16,7 @@ namespace Umbraco.Core.Persistence.Factories public LanguageDto BuildDto(ILanguage entity) { - var dto = new LanguageDto { CultureName = entity.CultureName, IsoCode = entity.IsoCode }; + var dto = new LanguageDto { CultureName = entity.CultureName, IsoCode = entity.IsoCode, IsDefaultVariantLanguage = entity.IsDefaultVariantLanguage, Mandatory = entity.Mandatory }; if (entity.HasIdentity) dto.Id = short.Parse(entity.Id.ToString(CultureInfo.InvariantCulture)); diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/ContentRepositoryBase.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/ContentRepositoryBase.cs index 95377af479..17e00b3e76 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Implement/ContentRepositoryBase.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Implement/ContentRepositoryBase.cs @@ -502,13 +502,13 @@ namespace Umbraco.Core.Persistence.Repositories.Implement { case "VERSIONDATE": case "UPDATEDATE": - return GetDatabaseFieldNameForOrderBy("uContentVersion", "versionDate"); + return GetDatabaseFieldNameForOrderBy(Constants.DatabaseSchema.Tables.ContentVersion, "versionDate"); case "CREATEDATE": return GetDatabaseFieldNameForOrderBy("umbracoNode", "createDate"); case "NAME": return GetDatabaseFieldNameForOrderBy("umbracoNode", "text"); case "PUBLISHED": - return GetDatabaseFieldNameForOrderBy("uDocument", "published"); + return GetDatabaseFieldNameForOrderBy(Constants.DatabaseSchema.Tables.Document, "published"); case "OWNER": //TODO: This isn't going to work very nicely because it's going to order by ID, not by letter return GetDatabaseFieldNameForOrderBy("umbracoNode", "nodeUser"); diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/ContentTypeRepositoryBase.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/ContentTypeRepositoryBase.cs index 3ce03f759a..d33980ac46 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Implement/ContentTypeRepositoryBase.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Implement/ContentTypeRepositoryBase.cs @@ -1091,11 +1091,11 @@ ORDER BY contentTypeId, id"; pt.contentTypeId AS contentTypeId, pt.id AS id, pt.uniqueID AS " + sqlSyntax.GetQuotedColumnName("key") + @", pt.propertyTypeGroupId AS groupId, - pt.Alias AS alias, pt." + sqlSyntax.GetQuotedColumnName("Description") + @" AS " + sqlSyntax.GetQuotedColumnName("desc") + @", pt.mandatory AS mandatory, + pt.Alias AS alias, pt." + sqlSyntax.GetQuotedColumnName("Description") + @" AS " + sqlSyntax.GetQuotedColumnName("desc") + $@", pt.mandatory AS mandatory, pt.Name AS name, pt.sortOrder AS sortOrder, pt.validationRegExp AS regexp, pt.variations as variations, dt.nodeId as dataTypeId, dt.dbType as dbType, dt.propertyEditorAlias as editorAlias FROM cmsPropertyType pt -INNER JOIN uDataType as dt ON pt.dataTypeId = dt.nodeId +INNER JOIN {Constants.DatabaseSchema.Tables.DataType} as dt ON pt.dataTypeId = dt.nodeId WHERE pt.contentTypeId IN (@ids) ORDER BY contentTypeId, groupId, id"; @@ -1238,9 +1238,9 @@ WHERE cmsContentType." + aliasColumn + @" LIKE @pattern", public bool HasContainerInPath(string contentPath) { var ids = contentPath.Split(',').Select(int.Parse); - var sql = new Sql(@"SELECT COUNT(*) FROM cmsContentType -INNER JOIN uContent ON cmsContentType.nodeId=uContent.contentTypeId -WHERE uContent.nodeId IN (@ids) AND cmsContentType.isContainer=@isContainer", new { ids, isContainer = true }); + var sql = new Sql($@"SELECT COUNT(*) FROM cmsContentType +INNER JOIN {Constants.DatabaseSchema.Tables.Content} ON cmsContentType.nodeId={Constants.DatabaseSchema.Tables.Content}.contentTypeId +WHERE {Constants.DatabaseSchema.Tables.Content}.nodeId IN (@ids) AND cmsContentType.isContainer=@isContainer", new { ids, isContainer = true }); return Database.ExecuteScalar(sql) > 0; } diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/DocumentRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/DocumentRepository.cs index 10620ee34d..084e8b6f59 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Implement/DocumentRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Implement/DocumentRepository.cs @@ -355,12 +355,12 @@ namespace Umbraco.Core.Persistence.Repositories.Implement entity.ResetDirtyProperties(); // troubleshooting - //if (Database.ExecuteScalar("SELECT COUNT(*) FROM uDocumentVersion JOIN uContentVersion ON uDocumentVersion.id=uContentVersion.id WHERE published=1 AND nodeId=" + content.Id) > 1) + //if (Database.ExecuteScalar($"SELECT COUNT(*) FROM {Constants.DatabaseSchema.Tables.DocumentVersion} JOIN {Constants.DatabaseSchema.Tables.ContentVersion} ON {Constants.DatabaseSchema.Tables.DocumentVersion}.id={Constants.DatabaseSchema.Tables.ContentVersion}.id WHERE published=1 AND nodeId=" + content.Id) > 1) //{ // Debugger.Break(); // throw new Exception("oops"); //} - //if (Database.ExecuteScalar("SELECT COUNT(*) FROM uDocumentVersion JOIN uContentVersion ON uDocumentVersion.id=uContentVersion.id WHERE [current]=1 AND nodeId=" + content.Id) > 1) + //if (Database.ExecuteScalar($"SELECT COUNT(*) FROM {Constants.DatabaseSchema.Tables.DocumentVersion} JOIN {Constants.DatabaseSchema.Tables.ContentVersion} ON {Constants.DatabaseSchema.Tables.DocumentVersion}.id={Constants.DatabaseSchema.Tables.ContentVersion}.id WHERE [current]=1 AND nodeId=" + content.Id) > 1) //{ // Debugger.Break(); // throw new Exception("oops"); @@ -500,12 +500,12 @@ namespace Umbraco.Core.Persistence.Repositories.Implement entity.ResetDirtyProperties(); // troubleshooting - //if (Database.ExecuteScalar("SELECT COUNT(*) FROM uDocumentVersion JOIN uContentVersion ON uDocumentVersion.id=uContentVersion.id WHERE published=1 AND nodeId=" + content.Id) > 1) + //if (Database.ExecuteScalar($"SELECT COUNT(*) FROM {Constants.DatabaseSchema.Tables.DocumentVersion} JOIN {Constants.DatabaseSchema.Tables.ContentVersion} ON {Constants.DatabaseSchema.Tables.DocumentVersion}.id={Constants.DatabaseSchema.Tables.ContentVersion}.id WHERE published=1 AND nodeId=" + content.Id) > 1) //{ // Debugger.Break(); // throw new Exception("oops"); //} - //if (Database.ExecuteScalar("SELECT COUNT(*) FROM uDocumentVersion JOIN uContentVersion ON uDocumentVersion.id=uContentVersion.id WHERE [current]=1 AND nodeId=" + content.Id) > 1) + //if (Database.ExecuteScalar($"SELECT COUNT(*) FROM {Constants.DatabaseSchema.Tables.DocumentVersion} JOIN {Constants.DatabaseSchema.Tables.ContentVersion} ON {Constants.DatabaseSchema.Tables.DocumentVersion}.id={Constants.DatabaseSchema.Tables.ContentVersion}.id WHERE [current]=1 AND nodeId=" + content.Id) > 1) //{ // Debugger.Break(); // throw new Exception("oops"); diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/DomainRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/DomainRepository.cs index 9f4785c620..f75d82bd4e 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Implement/DomainRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Implement/DomainRepository.cs @@ -91,7 +91,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement if (entity.RootContentId.HasValue) { - var contentExists = Database.ExecuteScalar("SELECT COUNT(*) FROM uContent WHERE nodeId = @id", new { id = entity.RootContentId.Value }); + var contentExists = Database.ExecuteScalar($"SELECT COUNT(*) FROM {Constants.DatabaseSchema.Tables.Content} WHERE nodeId = @id", new { id = entity.RootContentId.Value }); if (contentExists == 0) throw new NullReferenceException("No content exists with id " + entity.RootContentId.Value); } @@ -129,7 +129,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement if (entity.RootContentId.HasValue) { - var contentExists = Database.ExecuteScalar("SELECT COUNT(*) FROM uContent WHERE nodeId = @id", new { id = entity.RootContentId.Value }); + var contentExists = Database.ExecuteScalar($"SELECT COUNT(*) FROM {Constants.DatabaseSchema.Tables.Content} WHERE nodeId = @id", new { id = entity.RootContentId.Value }); if (contentExists == 0) throw new NullReferenceException("No content exists with id " + entity.RootContentId.Value); } diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/LanguageRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/LanguageRepository.cs index 784191279d..2d27479a95 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Implement/LanguageRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Implement/LanguageRepository.cs @@ -107,6 +107,14 @@ namespace Umbraco.Core.Persistence.Repositories.Implement { ((EntityBase)entity).AddingEntity(); + if (entity.IsDefaultVariantLanguage) + { + //if this entity is flagged as the default, we need to set all others to false + Database.Execute(Sql().Update(u => u.Set(x => x.IsDefaultVariantLanguage, false))); + //We need to clear the whole cache since all languages will be updated + IsolatedCache.ClearAllCache(); + } + var factory = new LanguageFactory(); var dto = factory.BuildDto(entity); @@ -114,12 +122,21 @@ namespace Umbraco.Core.Persistence.Repositories.Implement entity.Id = id; entity.ResetDirtyProperties(); + } protected override void PersistUpdatedItem(ILanguage entity) { ((EntityBase)entity).UpdatingEntity(); + if (entity.IsDefaultVariantLanguage) + { + //if this entity is flagged as the default, we need to set all others to false + Database.Execute(Sql().Update(u => u.Set(x => x.IsDefaultVariantLanguage, false))); + //We need to clear the whole cache since all languages will be updated + IsolatedCache.ClearAllCache(); + } + var factory = new LanguageFactory(); var dto = factory.BuildDto(entity); diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/MemberTypeRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/MemberTypeRepository.cs index 72f59c0d2a..3208cae41e 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Implement/MemberTypeRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Implement/MemberTypeRepository.cs @@ -149,7 +149,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement "cmsPropertyType.validationRegExp", "cmsPropertyType.dataTypeId", "cmsPropertyType.sortOrder AS PropertyTypeSortOrder", "cmsPropertyType.propertyTypeGroupId AS PropertyTypesGroupId", "cmsMemberType.memberCanEdit", "cmsMemberType.viewOnProfile", "cmsMemberType.isSensitive", - "uDataType.propertyEditorAlias", "uDataType.dbType", "cmsPropertyTypeGroup.id AS PropertyTypeGroupId", + $"{Constants.DatabaseSchema.Tables.DataType}.propertyEditorAlias", $"{Constants.DatabaseSchema.Tables.DataType}.dbType", "cmsPropertyTypeGroup.id AS PropertyTypeGroupId", "cmsPropertyTypeGroup.text AS PropertyGroupName", "cmsPropertyTypeGroup.uniqueID AS PropertyGroupUniqueID", "cmsPropertyTypeGroup.sortorder AS PropertyGroupSortOrder", "cmsPropertyTypeGroup.contenttypeNodeId") .From() diff --git a/src/Umbraco.Core/Services/Implement/KeyValueService.cs b/src/Umbraco.Core/Services/Implement/KeyValueService.cs index 6f911ceedc..cb1c423535 100644 --- a/src/Umbraco.Core/Services/Implement/KeyValueService.cs +++ b/src/Umbraco.Core/Services/Implement/KeyValueService.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Linq; using Umbraco.Core.Logging; using Umbraco.Core.Migrations; @@ -34,8 +35,9 @@ namespace Umbraco.Core.Services.Implement private void Initialize() { - // all this cannot be achieved via migrations since it needs to run - // before any migration, in order to figure out migrations + // all this cannot be achieved via an UmbracoPlan migration since it needs to + // run before any migration, in order to figure out the current plan's state. + // (does not prevent us from using a migration to do it, though) using (var scope = _scopeProvider.CreateScope()) { @@ -46,38 +48,48 @@ namespace Umbraco.Core.Services.Implement return; } - // drop the 'identity' on umbracoLock primary key - foreach (var sql in new[] - { - // create a temp. id column and copy values - "alter table umbracoLock add column nid int null;", - "update umbracoLock set nid = id;", - // drop the id column entirely (cannot just drop identity) - "alter table umbracoLock drop constraint PK_umbracoLock;", - "alter table umbracoLock drop column id;", - // recreate the id column without identity and copy values - "alter table umbracoLock add column id int null;", - "update umbracoLock set id = nid;", - // drop the temp. id column - "alter table umbracoLock drop column nid;", - // complete the primary key - "alter table umbracoLock alter column id int not null;", - "alter table umbracoLock add constraint PK_umbracoLock primary key (id);" - }) - scope.Database.Execute(sql); - - // insert the key-value lock - scope.Database.Execute($@"INSERT {scope.SqlContext.SqlSyntax.GetQuotedTableName(Constants.DatabaseSchema.Tables.Lock)} (id, name, value) -VALUES ({Constants.Locks.KeyValues}, 'KeyValues', 1);"); - - // create the key-value table var context = new MigrationContext(scope.Database, _logger); - new CreateBuilder(context).Table().Do(); + var initMigration = new InitializeMigration(context); + initMigration.Migrate(); scope.Complete(); } } + /// + /// A custom migration that executes standalone during the Initialize phase of this service. + /// + private class InitializeMigration : MigrationBase + { + public InitializeMigration(IMigrationContext context) + : base(context) + { } + + public override void Migrate() + { + // create a temp. id column and copy values + Alter.Table(Constants.DatabaseSchema.Tables.Lock).AddColumn("nid").AsInt32().Nullable().Do(); + Execute.Sql("update umbracoLock set nid = id").Do(); + // drop the id column entirely (cannot just drop identity) + Delete.PrimaryKey("PK_umbracoLock").FromTable(Constants.DatabaseSchema.Tables.Lock).Do(); + Delete.Column("id").FromTable(Constants.DatabaseSchema.Tables.Lock).Do(); + // recreate the id column without identity and copy values + Alter.Table(Constants.DatabaseSchema.Tables.Lock).AddColumn("id").AsInt32().Nullable().Do(); + Execute.Sql("update umbracoLock set id = nid").Do(); + // drop the temp. id column + Delete.Column("nid").FromTable(Constants.DatabaseSchema.Tables.Lock).Do(); + // complete the primary key + Alter.Table(Constants.DatabaseSchema.Tables.Lock).AlterColumn("id").AsInt32().NotNullable().PrimaryKey("PK_umbracoLock").Do(); + + // insert the key-value lock + Insert.IntoTable(Constants.DatabaseSchema.Tables.Lock).Row(new {id = Constants.Locks.KeyValues, name = "KeyValues", value = 1}).Do(); + + // create the key-value table if it's not there + if (TableExists(Constants.DatabaseSchema.Tables.KeyValue) == false) + Create.Table().Do(); + } + } + /// public string GetValue(string key) { diff --git a/src/Umbraco.Core/Services/Implement/LocalizationService.cs b/src/Umbraco.Core/Services/Implement/LocalizationService.cs index 70103d9a06..1af053b787 100644 --- a/src/Umbraco.Core/Services/Implement/LocalizationService.cs +++ b/src/Umbraco.Core/Services/Implement/LocalizationService.cs @@ -411,7 +411,7 @@ namespace Umbraco.Core.Services.Implement } } - #region Event Handlers + #region Events /// /// Occurs before Delete /// diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index 4bc4d81b75..2d8c7f2561 100644 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -336,6 +336,7 @@ + diff --git a/src/Umbraco.Tests/Persistence/Mappers/DataTypeMapperTest.cs b/src/Umbraco.Tests/Persistence/Mappers/DataTypeMapperTest.cs index 848a60641f..a65464a629 100644 --- a/src/Umbraco.Tests/Persistence/Mappers/DataTypeMapperTest.cs +++ b/src/Umbraco.Tests/Persistence/Mappers/DataTypeMapperTest.cs @@ -1,4 +1,5 @@ using NUnit.Framework; +using Umbraco.Core; using Umbraco.Core.Persistence.Mappers; using Umbraco.Core.Persistence.SqlSyntax; @@ -37,7 +38,7 @@ namespace Umbraco.Tests.Persistence.Mappers string column = new DataTypeMapper().Map(new SqlCeSyntaxProvider(), "DatabaseType"); // Assert - Assert.That(column, Is.EqualTo("[uDataType].[dbType]")); + Assert.That(column, Is.EqualTo($"[{Constants.DatabaseSchema.Tables.DataType}].[dbType]")); } [Test] @@ -48,7 +49,7 @@ namespace Umbraco.Tests.Persistence.Mappers string column = new DataTypeMapper().Map(new SqlCeSyntaxProvider(), "EditorAlias"); // Assert - Assert.That(column, Is.EqualTo("[uDataType].[propertyEditorAlias]")); + Assert.That(column, Is.EqualTo($"[{Constants.DatabaseSchema.Tables.DataType}].[propertyEditorAlias]")); } } } diff --git a/src/Umbraco.Tests/Persistence/Mappers/PropertyTypeMapperTest.cs b/src/Umbraco.Tests/Persistence/Mappers/PropertyTypeMapperTest.cs index 9b1baafd51..208b6e3749 100644 --- a/src/Umbraco.Tests/Persistence/Mappers/PropertyTypeMapperTest.cs +++ b/src/Umbraco.Tests/Persistence/Mappers/PropertyTypeMapperTest.cs @@ -1,4 +1,5 @@ using NUnit.Framework; +using Umbraco.Core; using Umbraco.Core.Persistence.Mappers; using Umbraco.Core.Persistence.SqlSyntax; @@ -54,7 +55,7 @@ namespace Umbraco.Tests.Persistence.Mappers string column = new PropertyTypeMapper().Map(new SqlCeSyntaxProvider(), "PropertyEditorAlias"); // Assert - Assert.That(column, Is.EqualTo("[uDataType].[propertyEditorAlias]")); + Assert.That(column, Is.EqualTo($"[{Constants.DatabaseSchema.Tables.DataType}].[propertyEditorAlias]")); } [Test] @@ -64,7 +65,7 @@ namespace Umbraco.Tests.Persistence.Mappers string column = new PropertyTypeMapper().Map(new SqlCeSyntaxProvider(), "ValueStorageType"); // Assert - Assert.That(column, Is.EqualTo("[uDataType].[dbType]")); + Assert.That(column, Is.EqualTo($"[{Constants.DatabaseSchema.Tables.DataType}].[dbType]")); } } } diff --git a/src/Umbraco.Tests/Persistence/NPocoTests/NPocoSqlTests.cs b/src/Umbraco.Tests/Persistence/NPocoTests/NPocoSqlTests.cs index 927324bfbd..a7b75cbd6d 100644 --- a/src/Umbraco.Tests/Persistence/NPocoTests/NPocoSqlTests.cs +++ b/src/Umbraco.Tests/Persistence/NPocoTests/NPocoSqlTests.cs @@ -1,5 +1,6 @@ using System.Diagnostics; using NUnit.Framework; +using Umbraco.Core; using Umbraco.Core.Persistence; using Umbraco.Core.Persistence.Dtos; using Umbraco.Core.Persistence.Querying; @@ -202,7 +203,7 @@ namespace Umbraco.Tests.Persistence.NPocoTests public void Can_Select_From_With_Type() { var expected = Sql(); - expected.SelectAll().From("[uContent]"); + expected.SelectAll().From($"[{Constants.DatabaseSchema.Tables.Content}]"); var sql = Sql(); sql.SelectAll().From(); @@ -217,9 +218,9 @@ namespace Umbraco.Tests.Persistence.NPocoTests { var expected = Sql(); expected.SelectAll() - .From("[uDocumentVersion]") - .InnerJoin("[uContentVersion]") - .On("[uDocumentVersion].[id] = [uContentVersion].[id]"); + .From($"[{Constants.DatabaseSchema.Tables.DocumentVersion}]") + .InnerJoin($"[{Constants.DatabaseSchema.Tables.ContentVersion}]") + .On($"[{Constants.DatabaseSchema.Tables.DocumentVersion}].[id] = [{Constants.DatabaseSchema.Tables.ContentVersion}].[id]"); var sql = Sql(); sql.SelectAll().From() @@ -235,7 +236,7 @@ namespace Umbraco.Tests.Persistence.NPocoTests public void Can_OrderBy_With_Type() { var expected = Sql(); - expected.SelectAll().From("[uContent]").OrderBy("([uContent].[contentTypeId])"); + expected.SelectAll().From($"[{Constants.DatabaseSchema.Tables.Content}]").OrderBy($"([{Constants.DatabaseSchema.Tables.Content}].[contentTypeId])"); var sql = Sql(); sql.SelectAll().From().OrderBy(x => x.ContentTypeId); @@ -249,7 +250,7 @@ namespace Umbraco.Tests.Persistence.NPocoTests public void Can_GroupBy_With_Type() { var expected = Sql(); - expected.SelectAll().From("[uContent]").GroupBy("[uContent].[contentTypeId]"); + expected.SelectAll().From($"[{Constants.DatabaseSchema.Tables.Content}]").GroupBy($"[{Constants.DatabaseSchema.Tables.Content}].[contentTypeId]"); var sql = Sql(); sql.SelectAll().From().GroupBy(x => x.ContentTypeId); @@ -263,7 +264,7 @@ namespace Umbraco.Tests.Persistence.NPocoTests public void Can_Use_Where_Predicate() { var expected = Sql(); - expected.SelectAll().From("[uContent]").Where("([uContent].[nodeId] = @0)", 1045); + expected.SelectAll().From($"[{Constants.DatabaseSchema.Tables.Content}]").Where($"([{Constants.DatabaseSchema.Tables.Content}].[nodeId] = @0)", 1045); var sql = Sql(); sql.SelectAll().From().Where(x => x.NodeId == 1045); @@ -278,9 +279,9 @@ namespace Umbraco.Tests.Persistence.NPocoTests { var expected = Sql(); expected.SelectAll() - .From("[uContent]") - .Where("([uContent].[nodeId] = @0)", 1045) - .Where("([uContent].[contentTypeId] = @0)", 1050); + .From($"[{Constants.DatabaseSchema.Tables.Content}]") + .Where($"([{Constants.DatabaseSchema.Tables.Content}].[nodeId] = @0)", 1045) + .Where($"([{Constants.DatabaseSchema.Tables.Content}].[contentTypeId] = @0)", 1050); var sql = Sql(); sql.SelectAll() diff --git a/src/Umbraco.Tests/Persistence/Querying/ContentTypeRepositorySqlClausesTest.cs b/src/Umbraco.Tests/Persistence/Querying/ContentTypeRepositorySqlClausesTest.cs index ba8155dc0a..4c10c4da41 100644 --- a/src/Umbraco.Tests/Persistence/Querying/ContentTypeRepositorySqlClausesTest.cs +++ b/src/Umbraco.Tests/Persistence/Querying/ContentTypeRepositorySqlClausesTest.cs @@ -94,7 +94,7 @@ namespace Umbraco.Tests.Persistence.Querying expected.SelectAll() .From("[cmsPropertyTypeGroup]") .RightJoin("[cmsPropertyType]").On("[cmsPropertyTypeGroup].[id] = [cmsPropertyType].[propertyTypeGroupId]") - .InnerJoin("[uDataType]").On("[cmsPropertyType].[dataTypeId] = [uDataType].[nodeId]"); + .InnerJoin($"[{Constants.DatabaseSchema.Tables.DataType}]").On($"[cmsPropertyType].[dataTypeId] = [{Constants.DatabaseSchema.Tables.DataType}].[nodeId]"); var sql = Sql(); sql.SelectAll() @@ -140,7 +140,7 @@ namespace Umbraco.Tests.Persistence.Querying expected.SelectAll() .From("[cmsPropertyTypeGroup]") .RightJoin("[cmsPropertyType]").On("[cmsPropertyTypeGroup].[id] = [cmsPropertyType].[propertyTypeGroupId]") - .InnerJoin("[uDataType]").On("[cmsPropertyType].[dataTypeId] = [uDataType].[nodeId]") + .InnerJoin($"[{Constants.DatabaseSchema.Tables.DataType}]").On($"[cmsPropertyType].[dataTypeId] = [{Constants.DatabaseSchema.Tables.DataType}].[nodeId]") .Where("([cmsPropertyType].[contentTypeId] = @0)", 1050); var sql = Sql(); diff --git a/src/Umbraco.Tests/Persistence/Querying/DataTypeDefinitionRepositorySqlClausesTest.cs b/src/Umbraco.Tests/Persistence/Querying/DataTypeDefinitionRepositorySqlClausesTest.cs index 2b3611cb02..e52da368c7 100644 --- a/src/Umbraco.Tests/Persistence/Querying/DataTypeDefinitionRepositorySqlClausesTest.cs +++ b/src/Umbraco.Tests/Persistence/Querying/DataTypeDefinitionRepositorySqlClausesTest.cs @@ -19,8 +19,8 @@ namespace Umbraco.Tests.Persistence.Querying var expected = new Sql(); expected.Select("*") - .From("[uDataType]") - .InnerJoin("[umbracoNode]").On("[uDataType].[nodeId] = [umbracoNode].[id]") + .From($"[{Constants.DatabaseSchema.Tables.DataType}]") + .InnerJoin("[umbracoNode]").On($"[{Constants.DatabaseSchema.Tables.DataType}].[nodeId] = [umbracoNode].[id]") .Where("([umbracoNode].[nodeObjectType] = @0)", new Guid("30a2a501-1978-4ddb-a57b-f7efed43ba3c")); var sql = Sql(); diff --git a/src/Umbraco.Tests/Persistence/Querying/MediaRepositorySqlClausesTest.cs b/src/Umbraco.Tests/Persistence/Querying/MediaRepositorySqlClausesTest.cs index 4def2621fd..246379bed3 100644 --- a/src/Umbraco.Tests/Persistence/Querying/MediaRepositorySqlClausesTest.cs +++ b/src/Umbraco.Tests/Persistence/Querying/MediaRepositorySqlClausesTest.cs @@ -19,9 +19,9 @@ namespace Umbraco.Tests.Persistence.Querying var expected = new Sql(); expected.Select("*") - .From("[uContentVersion]") - .InnerJoin("[uContent]").On("[uContentVersion].[nodeId] = [uContent].[nodeId]") - .InnerJoin("[umbracoNode]").On("[uContent].[nodeId] = [umbracoNode].[id]") + .From($"[{Constants.DatabaseSchema.Tables.ContentVersion}]") + .InnerJoin($"[{Constants.DatabaseSchema.Tables.Content}]").On($"[{Constants.DatabaseSchema.Tables.ContentVersion}].[nodeId] = [{Constants.DatabaseSchema.Tables.Content}].[nodeId]") + .InnerJoin("[umbracoNode]").On($"[{Constants.DatabaseSchema.Tables.Content}].[nodeId] = [umbracoNode].[id]") .Where("([umbracoNode].[nodeObjectType] = @0)", new Guid("b796f64c-1f99-4ffb-b886-4bf4bc011a9c")); var sql = Sql(); diff --git a/src/Umbraco.Tests/Persistence/Repositories/ContentRepositoryTest.cs b/src/Umbraco.Tests/Persistence/Repositories/ContentRepositoryTest.cs index 65a32942df..f6f7048315 100644 --- a/src/Umbraco.Tests/Persistence/Repositories/ContentRepositoryTest.cs +++ b/src/Umbraco.Tests/Persistence/Repositories/ContentRepositoryTest.cs @@ -152,7 +152,7 @@ namespace Umbraco.Tests.Persistence.Repositories Assert.AreEqual(versions[versions.Count - 1], repository.Get(content1.Id).VersionId); // misc checks - Assert.AreEqual(true, scope.Database.ExecuteScalar("SELECT published FROM uDocument WHERE nodeId=@id", new { id = content1.Id })); + Assert.AreEqual(true, scope.Database.ExecuteScalar($"SELECT published FROM {Constants.DatabaseSchema.Tables.Document} WHERE nodeId=@id", new { id = content1.Id })); // change something // save = update the current (draft) version @@ -168,7 +168,7 @@ namespace Umbraco.Tests.Persistence.Repositories Assert.AreEqual(versions[versions.Count - 1], repository.Get(content1.Id).VersionId); // misc checks - Assert.AreEqual(true, scope.Database.ExecuteScalar("SELECT published FROM uDocument WHERE nodeId=@id", new { id = content1.Id })); + Assert.AreEqual(true, scope.Database.ExecuteScalar($"SELECT published FROM {Constants.DatabaseSchema.Tables.Document} WHERE nodeId=@id", new { id = content1.Id })); // unpublish = no impact on versions ((Content) content1).PublishedState = PublishedState.Unpublishing; @@ -183,7 +183,7 @@ namespace Umbraco.Tests.Persistence.Repositories Assert.AreEqual(versions[versions.Count - 1], repository.Get(content1.Id).VersionId); // misc checks - Assert.AreEqual(false, scope.Database.ExecuteScalar("SELECT published FROM uDocument WHERE nodeId=@id", new { id = content1.Id })); + Assert.AreEqual(false, scope.Database.ExecuteScalar($"SELECT published FROM {Constants.DatabaseSchema.Tables.Document} WHERE nodeId=@id", new { id = content1.Id })); // change something // save = update the current (draft) version @@ -198,7 +198,7 @@ namespace Umbraco.Tests.Persistence.Repositories Assert.AreEqual(versions[versions.Count - 1], repository.Get(content1.Id).VersionId); // misc checks - Assert.AreEqual(false, scope.Database.ExecuteScalar("SELECT published FROM uDocument WHERE nodeId=@id", new { id = content1.Id })); + Assert.AreEqual(false, scope.Database.ExecuteScalar($"SELECT published FROM {Constants.DatabaseSchema.Tables.Document} WHERE nodeId=@id", new { id = content1.Id })); // publish = version ((Content) content1).PublishValues(); @@ -214,7 +214,7 @@ namespace Umbraco.Tests.Persistence.Repositories Assert.AreEqual(versions[versions.Count - 1], repository.Get(content1.Id).VersionId); // misc checks - Assert.AreEqual(true, scope.Database.ExecuteScalar("SELECT published FROM uDocument WHERE nodeId=@id", new { id = content1.Id })); + Assert.AreEqual(true, scope.Database.ExecuteScalar($"SELECT published FROM {Constants.DatabaseSchema.Tables.Document} WHERE nodeId=@id", new { id = content1.Id })); // change something // save = update the current (draft) version @@ -232,7 +232,7 @@ namespace Umbraco.Tests.Persistence.Repositories Assert.AreEqual(versions[versions.Count - 1], repository.Get(content1.Id).VersionId); // misc checks - Assert.AreEqual(true, scope.Database.ExecuteScalar("SELECT published FROM uDocument WHERE nodeId=@id", new { id = content1.Id })); + Assert.AreEqual(true, scope.Database.ExecuteScalar($"SELECT published FROM {Constants.DatabaseSchema.Tables.Document} WHERE nodeId=@id", new { id = content1.Id })); // publish = new version content1.Name = "name-4"; @@ -250,7 +250,7 @@ namespace Umbraco.Tests.Persistence.Repositories Assert.AreEqual(versions[versions.Count - 1], repository.Get(content1.Id).VersionId); // misc checks - Assert.AreEqual(true, scope.Database.ExecuteScalar("SELECT published FROM uDocument WHERE nodeId=@id", new { id = content1.Id })); + Assert.AreEqual(true, scope.Database.ExecuteScalar($"SELECT published FROM {Constants.DatabaseSchema.Tables.Document} WHERE nodeId=@id", new { id = content1.Id })); // all versions var allVersions = repository.GetAllVersions(content1.Id).ToArray(); diff --git a/src/Umbraco.Tests/Persistence/Repositories/LanguageRepositoryTest.cs b/src/Umbraco.Tests/Persistence/Repositories/LanguageRepositoryTest.cs index 3d0b484a50..fbf43a1889 100644 --- a/src/Umbraco.Tests/Persistence/Repositories/LanguageRepositoryTest.cs +++ b/src/Umbraco.Tests/Persistence/Repositories/LanguageRepositoryTest.cs @@ -2,14 +2,10 @@ using System.Linq; using Moq; using NUnit.Framework; -using Umbraco.Core; using Umbraco.Core.Cache; using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Persistence; - -using Umbraco.Core.Persistence.Querying; -using Umbraco.Core.Persistence.Repositories; using Umbraco.Core.Persistence.Repositories.Implement; using Umbraco.Core.Scoping; using Umbraco.Tests.TestHelpers; @@ -33,8 +29,6 @@ namespace Umbraco.Tests.Persistence.Repositories return new LanguageRepository((IScopeAccessor) provider, CacheHelper.CreateDisabledCacheHelper(), Mock.Of()); } - - [Test] public void Can_Perform_Get_On_LanguageRepository() { @@ -109,7 +103,7 @@ namespace Umbraco.Tests.Persistence.Repositories } [Test] - public void Get_WhenIdDoesntExist_ReturnsNull() + public void Get_When_Id_Doesnt_Exist_Returns_Null() { // Arrange var provider = TestObjects.GetScopeProvider(Logger); @@ -219,6 +213,59 @@ namespace Umbraco.Tests.Persistence.Repositories // Assert Assert.That(languageBR.HasIdentity, Is.True); Assert.That(languageBR.Id, Is.EqualTo(6)); //With 5 existing entries the Id should be 6 + Assert.IsFalse(languageBR.IsDefaultVariantLanguage); + Assert.IsFalse(languageBR.Mandatory); + } + } + + [Test] + public void Can_Perform_Add_On_LanguageRepository_With_Boolean_Properties() + { + // Arrange + var provider = TestObjects.GetScopeProvider(Logger); + using (var scope = provider.CreateScope()) + { + var repository = CreateRepository(provider); + + // Act + var languageBR = new Language("pt-BR") { CultureName = "pt-BR", IsDefaultVariantLanguage = true, Mandatory = true }; + repository.Save(languageBR); + + // Assert + Assert.That(languageBR.HasIdentity, Is.True); + Assert.That(languageBR.Id, Is.EqualTo(6)); //With 5 existing entries the Id should be 6 + Assert.IsTrue(languageBR.IsDefaultVariantLanguage); + Assert.IsTrue(languageBR.Mandatory); + } + } + + [Test] + public void Can_Perform_Add_On_LanguageRepository_With_New_Default() + { + // Arrange + var provider = TestObjects.GetScopeProvider(Logger); + using (var scope = provider.CreateScope()) + { + var repository = CreateRepository(provider); + + var languageBR = (ILanguage)new Language("pt-BR") { CultureName = "pt-BR", IsDefaultVariantLanguage = true, Mandatory = true }; + repository.Save(languageBR); + var languageEN = new Language("en-AU") { CultureName = "en-AU" }; + repository.Save(languageEN); + + Assert.IsTrue(languageBR.IsDefaultVariantLanguage); + Assert.IsTrue(languageBR.Mandatory); + + // Act + + var languageNZ = new Language("en-NZ") { CultureName = "en-NZ", IsDefaultVariantLanguage = true, Mandatory = true }; + repository.Save(languageNZ); + languageBR = repository.Get(languageBR.Id); + + // Assert + + Assert.IsFalse(languageBR.IsDefaultVariantLanguage); + Assert.IsTrue(languageNZ.IsDefaultVariantLanguage); } } diff --git a/src/Umbraco.Tests/Persistence/Repositories/MemberRepositoryTest.cs b/src/Umbraco.Tests/Persistence/Repositories/MemberRepositoryTest.cs index a625cc14d1..4f901935dc 100644 --- a/src/Umbraco.Tests/Persistence/Repositories/MemberRepositoryTest.cs +++ b/src/Umbraco.Tests/Persistence/Repositories/MemberRepositoryTest.cs @@ -323,8 +323,8 @@ namespace Umbraco.Tests.Persistence.Repositories } var sql = provider.SqlContext.Sql(); - sql.Select("umbracoNode.*", "uContent.contentTypeId", "cmsContentType.alias AS ContentTypeAlias", "uContentVersion.versionId", - "uContentVersion.versionDate", "cmsMember.Email", + sql.Select("umbracoNode.*", $"{Constants.DatabaseSchema.Tables.Content}.contentTypeId", "cmsContentType.alias AS ContentTypeAlias", $"{Constants.DatabaseSchema.Tables.ContentVersion}.versionId", + $"{Constants.DatabaseSchema.Tables.ContentVersion}.versionDate", "cmsMember.Email", "cmsMember.LoginName", "cmsMember.Password", Constants.DatabaseSchema.Tables.PropertyData + ".id AS PropertyDataId", Constants.DatabaseSchema.Tables.PropertyData + ".propertytypeid", Constants.DatabaseSchema.Tables.PropertyData + ".dateValue", Constants.DatabaseSchema.Tables.PropertyData + ".intValue", @@ -341,7 +341,7 @@ namespace Umbraco.Tests.Persistence.Repositories .LeftJoin().On(left => left.ContentTypeId, right => right.ContentTypeId) .LeftJoin().On(left => left.NodeId, right => right.DataTypeId) .LeftJoin().On(left => left.PropertyTypeId, right => right.Id) - .Append("AND " + Constants.DatabaseSchema.Tables.PropertyData + ".versionId = uContentVersion.id") + .Append("AND " + Constants.DatabaseSchema.Tables.PropertyData + $".versionId = {Constants.DatabaseSchema.Tables.ContentVersion}.id") .Where(x => x.NodeObjectType == NodeObjectTypeId); return sql; } @@ -359,7 +359,7 @@ namespace Umbraco.Tests.Persistence.Repositories .LeftJoin().On(left => left.ContentTypeId, right => right.ContentTypeId) .LeftJoin().On(left => left.NodeId, right => right.DataTypeId) .LeftJoin().On(left => left.PropertyTypeId, right => right.Id) - .Append("AND " + Constants.DatabaseSchema.Tables.PropertyData + ".versionId = uContentVersion.id") + .Append("AND " + Constants.DatabaseSchema.Tables.PropertyData + $".versionId = {Constants.DatabaseSchema.Tables.ContentVersion}.id") .Where(x => x.NodeObjectType == NodeObjectTypeId); return sql; } diff --git a/src/Umbraco.Tests/Persistence/Repositories/UserRepositoryTest.cs b/src/Umbraco.Tests/Persistence/Repositories/UserRepositoryTest.cs index 1166ce8743..03ea7391f9 100644 --- a/src/Umbraco.Tests/Persistence/Repositories/UserRepositoryTest.cs +++ b/src/Umbraco.Tests/Persistence/Repositories/UserRepositoryTest.cs @@ -217,7 +217,6 @@ namespace Umbraco.Tests.Persistence.Repositories } [Test] - [Ignore("has bugs")] public void Can_Perform_Get_On_UserRepository() { // Arrange diff --git a/src/Umbraco.Tests/Services/ContentServiceTests.cs b/src/Umbraco.Tests/Services/ContentServiceTests.cs index 5dd11b2812..a67d71d081 100644 --- a/src/Umbraco.Tests/Services/ContentServiceTests.cs +++ b/src/Umbraco.Tests/Services/ContentServiceTests.cs @@ -36,7 +36,7 @@ namespace Umbraco.Tests.Services [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest, PublishedRepositoryEvents = true, WithApplication = true)] public class ContentServiceTests : TestWithSomeContentBase { - //TODO Add test to verify there is only ONE newest document/content in uDocument table after updating. + //TODO Add test to verify there is only ONE newest document/content in {Constants.DatabaseSchema.Tables.Document} table after updating. //TODO Add test to delete specific version (with and without deleting prior versions) and versions by date. public override void SetUp() diff --git a/src/Umbraco.Tests/Services/LocalizationServiceTests.cs b/src/Umbraco.Tests/Services/LocalizationServiceTests.cs index b7f958cb8e..e39ebfee8e 100644 --- a/src/Umbraco.Tests/Services/LocalizationServiceTests.cs +++ b/src/Umbraco.Tests/Services/LocalizationServiceTests.cs @@ -364,6 +364,28 @@ namespace Umbraco.Tests.Services Assert.NotNull(result); } + [Test] + public void Set_Default_Language() + { + var localizationService = ServiceContext.LocalizationService; + var language = new Core.Models.Language("en-AU"); + language.IsDefaultVariantLanguage = true; + localizationService.Save(language); + var result = localizationService.GetLanguageById(language.Id); + + Assert.IsTrue(result.IsDefaultVariantLanguage); + + var language2 = new Core.Models.Language("en-NZ"); + language2.IsDefaultVariantLanguage = true; + localizationService.Save(language2); + var result2 = localizationService.GetLanguageById(language2.Id); + //re-get + result = localizationService.GetLanguageById(language.Id); + + Assert.IsTrue(result2.IsDefaultVariantLanguage); + Assert.IsFalse(result.IsDefaultVariantLanguage); + } + [Test] public void Deleted_Language_Should_Not_Exist() { diff --git a/src/Umbraco.Tests/UmbracoExamine/IndexInitializer.cs b/src/Umbraco.Tests/UmbracoExamine/IndexInitializer.cs index c5b161f44a..6e82f7d21e 100644 --- a/src/Umbraco.Tests/UmbracoExamine/IndexInitializer.cs +++ b/src/Umbraco.Tests/UmbracoExamine/IndexInitializer.cs @@ -168,7 +168,7 @@ namespace Umbraco.Tests.UmbracoExamine //var query = new Mock>(); //query // .Setup(x => x.GetWhereClauses()) - // .Returns(new List> { new Tuple("uDocument.published", new object[] { 1 }) }); + // .Returns(new List> { new Tuple($"{Constants.DatabaseSchema.Tables.Document}.published", new object[] { 1 }) }); var scopeProvider = new Mock(); //scopeProvider // .Setup(x => x.Query()) diff --git a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj index add06f81b6..2c09e6ff7b 100644 --- a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj +++ b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj @@ -673,7 +673,9 @@ SettingsSingleFileGenerator Settings.Designer.cs - + + Designer + UI.xml diff --git a/src/Umbraco.Web/Editors/LanguageController.cs b/src/Umbraco.Web/Editors/LanguageController.cs new file mode 100644 index 0000000000..20932f6bf9 --- /dev/null +++ b/src/Umbraco.Web/Editors/LanguageController.cs @@ -0,0 +1,83 @@ +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Web.Http; +using Umbraco.Core.Persistence; +using Umbraco.Web.Models; +using Umbraco.Web.Mvc; + +namespace Umbraco.Web.Editors +{ + /// + /// Backoffice controller supporting the dashboard for language administration. + /// + [PluginController("UmbracoApi")] + public class LanguageController : UmbracoAuthorizedJsonController + { + /// + /// Returns all cultures available for creating languages. + /// + /// + [HttpGet] + public IEnumerable GetAllCultures() + { + return CultureInfo.GetCultures(CultureTypes.AllCultures) + .Select(x => new Culture {IsoCode = x.Name, Name = x.DisplayName}); + } + + /// + /// Returns all currently configured languages. + /// + /// + [HttpGet] + public IEnumerable GetAllLanguages() + { + var allLanguages = Services.LocalizationService.GetAllLanguages(); + + return allLanguages.Select(x => new Language + { + Id = x.Id, + IsoCode = x.IsoCode, + Name = x.CultureInfo.DisplayName, + IsDefaultVariantLanguage = x.IsDefaultVariantLanguage, + Mandatory = x.Mandatory + }); + } + + /// + /// Deletes a language with a given ID + /// + [HttpDelete] + [HttpPost] + public void DeleteLanguage(int id) + { + var language = Services.LocalizationService.GetLanguageById(id); + if (language == null) + { + throw new EntityNotFoundException(id, $"Could not find language by id: '{id}'."); + } + Services.LocalizationService.Delete(language); + } + + /// + /// Saves a bulk set of languages with default/mandatory settings and returns the full set of languages configured. + /// + [HttpPost] + public IEnumerable SaveLanguages(IEnumerable languages) + { + foreach (var l in languages) + { + var language = Services.LocalizationService.GetLanguageByIsoCode(l.IsoCode); + if (language == null) + { + language = new Core.Models.Language(l.IsoCode); + } + language.Mandatory = l.Mandatory; + language.IsDefaultVariantLanguage = l.IsDefaultVariantLanguage; + Services.LocalizationService.Save(language); + } + + return GetAllLanguages(); + } + } +} \ No newline at end of file diff --git a/src/Umbraco.Web/Models/Culture.cs b/src/Umbraco.Web/Models/Culture.cs new file mode 100644 index 0000000000..16ebc6bc2a --- /dev/null +++ b/src/Umbraco.Web/Models/Culture.cs @@ -0,0 +1,8 @@ +namespace Umbraco.Web.Models +{ + public class Culture + { + public string IsoCode { get; set; } + public string Name { get; set; } + } +} \ No newline at end of file diff --git a/src/Umbraco.Web/Models/Language.cs b/src/Umbraco.Web/Models/Language.cs new file mode 100644 index 0000000000..4fdf418eef --- /dev/null +++ b/src/Umbraco.Web/Models/Language.cs @@ -0,0 +1,13 @@ +using System.Globalization; + +namespace Umbraco.Web.Models +{ + public class Language + { + public int Id { get; set; } + public string IsoCode { get; set; } + public string Name { get; set; } + public bool IsDefaultVariantLanguage { get; set; } + public bool Mandatory { get; set; } + } +} \ No newline at end of file diff --git a/src/Umbraco.Web/PublishedCache/NuCache/PublishedSnapshotService.cs b/src/Umbraco.Web/PublishedCache/NuCache/PublishedSnapshotService.cs index bf1fd2473b..df264ac51c 100644 --- a/src/Umbraco.Web/PublishedCache/NuCache/PublishedSnapshotService.cs +++ b/src/Umbraco.Web/PublishedCache/NuCache/PublishedSnapshotService.cs @@ -1251,12 +1251,12 @@ WHERE cmsContentNu.nodeId IN ( { // assume number of ctypes won't blow IN(...) // must support SQL-CE - db.Execute(@"DELETE FROM cmsContentNu + db.Execute($@"DELETE FROM cmsContentNu WHERE cmsContentNu.nodeId IN ( SELECT id FROM umbracoNode - JOIN uContent ON uContent.nodeId=umbracoNode.id + JOIN {Constants.DatabaseSchema.Tables.Content} ON {Constants.DatabaseSchema.Tables.Content}.nodeId=umbracoNode.id WHERE umbracoNode.nodeObjectType=@objType - AND uContent.contentTypeId IN (@ctypes) + AND {Constants.DatabaseSchema.Tables.Content}.contentTypeId IN (@ctypes) )", new { objType = contentObjectType, ctypes = contentTypeIdsA }); } @@ -1318,12 +1318,12 @@ WHERE cmsContentNu.nodeId IN ( { // assume number of ctypes won't blow IN(...) // must support SQL-CE - db.Execute(@"DELETE FROM cmsContentNu + db.Execute($@"DELETE FROM cmsContentNu WHERE cmsContentNu.nodeId IN ( SELECT id FROM umbracoNode - JOIN uContent ON uContent.nodeId=umbracoNode.id + JOIN {Constants.DatabaseSchema.Tables.Content} ON {Constants.DatabaseSchema.Tables.Content}.nodeId=umbracoNode.id WHERE umbracoNode.nodeObjectType=@objType - AND uContent.contentTypeId IN (@ctypes) + AND {Constants.DatabaseSchema.Tables.Content}.contentTypeId IN (@ctypes) )", new { objType = mediaObjectType, ctypes = contentTypeIdsA }); } @@ -1376,12 +1376,12 @@ WHERE cmsContentNu.nodeId IN ( { // assume number of ctypes won't blow IN(...) // must support SQL-CE - db.Execute(@"DELETE FROM cmsContentNu + db.Execute($@"DELETE FROM cmsContentNu WHERE cmsContentNu.nodeId IN ( SELECT id FROM umbracoNode - JOIN uContent ON uContent.nodeId=umbracoNode.id + JOIN {Constants.DatabaseSchema.Tables.Content} ON {Constants.DatabaseSchema.Tables.Content}.nodeId=umbracoNode.id WHERE umbracoNode.nodeObjectType=@objType - AND uContent.contentTypeId IN (@ctypes) + AND {Constants.DatabaseSchema.Tables.Content}.contentTypeId IN (@ctypes) )", new { objType = memberObjectType, ctypes = contentTypeIdsA }); } @@ -1423,13 +1423,13 @@ WHERE cmsContentNu.nodeId IN ( var contentObjectType = Constants.ObjectTypes.Document; var db = scope.Database; - var count = db.ExecuteScalar(@"SELECT COUNT(*) + var count = db.ExecuteScalar($@"SELECT COUNT(*) FROM umbracoNode -JOIN uDocument ON umbracoNode.id=uDocument.nodeId +JOIN {Constants.DatabaseSchema.Tables.Document} ON umbracoNode.id={Constants.DatabaseSchema.Tables.Document}.nodeId LEFT JOIN cmsContentNu nuEdited ON (umbracoNode.id=nuEdited.nodeId AND nuEdited.published=0) LEFT JOIN cmsContentNu nuPublished ON (umbracoNode.id=nuPublished.nodeId AND nuPublished.published=1) WHERE umbracoNode.nodeObjectType=@objType -AND nuEdited.nodeId IS NULL OR (uDocument.published=1 AND nuPublished.nodeId IS NULL);" +AND nuEdited.nodeId IS NULL OR ({Constants.DatabaseSchema.Tables.Document}.published=1 AND nuPublished.nodeId IS NULL);" , new { objType = contentObjectType }); return count == 0; diff --git a/src/Umbraco.Web/PublishedCache/XmlPublishedCache/XmlStore.cs b/src/Umbraco.Web/PublishedCache/XmlPublishedCache/XmlStore.cs index a0e7f6370d..cec34f0b3d 100644 --- a/src/Umbraco.Web/PublishedCache/XmlPublishedCache/XmlStore.cs +++ b/src/Umbraco.Web/PublishedCache/XmlPublishedCache/XmlStore.cs @@ -497,16 +497,18 @@ AND (umbracoNode.id=@id)"; return xml; } - public XmlNode GetPreviewXmlNode(int contentId) - { - const string sql = @"SELECT umbracoNode.id, umbracoNode.parentId, umbracoNode.sortOrder, umbracoNode.Level, -cmsPreviewXml.xml, uDocument.published + private static readonly string PreviewXmlNodeSql = $@"SELECT umbracoNode.id, umbracoNode.parentId, umbracoNode.sortOrder, umbracoNode.Level, +cmsPreviewXml.xml, {Constants.DatabaseSchema.Tables.Document}.published FROM umbracoNode JOIN cmsPreviewXml ON (cmsPreviewXml.nodeId=umbracoNode.id) -JOIN uDocument ON (uDocument.nodeId=umbracoNode.id) +JOIN {Constants.DatabaseSchema.Tables.Document} ON ({Constants.DatabaseSchema.Tables.Document}.nodeId=umbracoNode.id) WHERE umbracoNode.nodeObjectType = @nodeObjectType AND (umbracoNode.id=@id)"; + public XmlNode GetPreviewXmlNode(int contentId) + { + var sql = PreviewXmlNodeSql; + XmlDto xmlDto; using (var scope = _scopeProvider.CreateScope()) { @@ -840,32 +842,32 @@ AND (umbracoNode.id=@id)"; #region Database - private const string ReadTreeCmsContentXmlSql = @"SELECT + private static readonly string ReadTreeCmsContentXmlSql = $@"SELECT umbracoNode.id, umbracoNode.parentId, umbracoNode.sortOrder, umbracoNode.level, umbracoNode.path, - cmsContentXml.xml, cmsContentXml.rv, uDocument.published + cmsContentXml.xml, cmsContentXml.rv, {Constants.DatabaseSchema.Tables.Document}.published FROM umbracoNode JOIN cmsContentXml ON (cmsContentXml.nodeId=umbracoNode.id) -JOIN uDocument ON (uDocument.nodeId=umbracoNode.id) -WHERE umbracoNode.nodeObjectType = @nodeObjectType AND uDocument.published=1 +JOIN {Constants.DatabaseSchema.Tables.Document} ON ({Constants.DatabaseSchema.Tables.Document}.nodeId=umbracoNode.id) +WHERE umbracoNode.nodeObjectType = @nodeObjectType AND {Constants.DatabaseSchema.Tables.Document}.published=1 ORDER BY umbracoNode.level, umbracoNode.sortOrder"; - private const string ReadBranchCmsContentXmlSql = @"SELECT + private static readonly string ReadBranchCmsContentXmlSql = $@"SELECT umbracoNode.id, umbracoNode.parentId, umbracoNode.sortOrder, umbracoNode.level, umbracoNode.path, - cmsContentXml.xml, cmsContentXml.rv, uDocument.published + cmsContentXml.xml, cmsContentXml.rv, {Constants.DatabaseSchema.Tables.Document}.published FROM umbracoNode JOIN cmsContentXml ON (cmsContentXml.nodeId=umbracoNode.id) -JOIN uDocument ON (uDocument.nodeId=umbracoNode.id) -WHERE umbracoNode.nodeObjectType = @nodeObjectType AND uDocument.published=1 AND (umbracoNode.id = @id OR umbracoNode.path LIKE @path) +JOIN {Constants.DatabaseSchema.Tables.Document} ON ({Constants.DatabaseSchema.Tables.Document}.nodeId=umbracoNode.id) +WHERE umbracoNode.nodeObjectType = @nodeObjectType AND {Constants.DatabaseSchema.Tables.Document}.published=1 AND (umbracoNode.id = @id OR umbracoNode.path LIKE @path) ORDER BY umbracoNode.level, umbracoNode.sortOrder"; - private const string ReadCmsContentXmlForContentTypesSql = @"SELECT + private static readonly string ReadCmsContentXmlForContentTypesSql = $@"SELECT umbracoNode.id, umbracoNode.parentId, umbracoNode.sortOrder, umbracoNode.level, umbracoNode.path, - cmsContentXml.xml, cmsContentXml.rv, uDocument.published + cmsContentXml.xml, cmsContentXml.rv, {Constants.DatabaseSchema.Tables.Document}.published FROM umbracoNode JOIN cmsContentXml ON (cmsContentXml.nodeId=umbracoNode.id) -JOIN uDocument ON (uDocument.nodeId=umbracoNode.id) -JOIN uContent ON (uDocument.nodeId=uContent.nodeId) -WHERE umbracoNode.nodeObjectType = @nodeObjectType AND uDocument.published=1 AND uContent.contentTypeId IN (@ids) +JOIN {Constants.DatabaseSchema.Tables.Document} ON ({Constants.DatabaseSchema.Tables.Document}.nodeId=umbracoNode.id) +JOIN {Constants.DatabaseSchema.Tables.Content} ON ({Constants.DatabaseSchema.Tables.Document}.nodeId={Constants.DatabaseSchema.Tables.Content}.nodeId) +WHERE umbracoNode.nodeObjectType = @nodeObjectType AND {Constants.DatabaseSchema.Tables.Document}.published=1 AND {Constants.DatabaseSchema.Tables.Content}.contentTypeId IN (@ids) ORDER BY umbracoNode.level, umbracoNode.sortOrder"; private const string ReadMoreCmsContentXmlSql = @"SELECT @@ -876,13 +878,13 @@ JOIN cmsContentXml ON (cmsContentXml.nodeId=umbracoNode.id) WHERE umbracoNode.nodeObjectType = @nodeObjectType ORDER BY umbracoNode.level, umbracoNode.sortOrder"; - private const string ReadCmsPreviewXmlSql1 = @"SELECT + private static readonly string ReadCmsPreviewXmlSql1 = $@"SELECT umbracoNode.id, umbracoNode.parentId, umbracoNode.sortOrder, umbracoNode.level, umbracoNode.path, - cmsPreviewXml.xml, cmsPreviewXml.rv, uDocument.published + cmsPreviewXml.xml, cmsPreviewXml.rv, {Constants.DatabaseSchema.Tables.Document}.published FROM umbracoNode JOIN cmsPreviewXml ON (cmsPreviewXml.nodeId=umbracoNode.id) -JOIN uDocument ON (uDocument.nodeId=umbracoNode.id) -WHERE umbracoNode.nodeObjectType = @nodeObjectType AND uDocument.published=1 +JOIN {Constants.DatabaseSchema.Tables.Document} ON ({Constants.DatabaseSchema.Tables.Document}.nodeId=umbracoNode.id) +WHERE umbracoNode.nodeObjectType = @nodeObjectType AND {Constants.DatabaseSchema.Tables.Document}.published=1 AND (umbracoNode.path=@path OR"; // @path LIKE concat(umbracoNode.path, ',%')"; private const string ReadCmsPreviewXmlSql2 = @") @@ -1714,15 +1716,15 @@ WHERE cmsContentXml.nodeId IN ( // db.Execute(@"DELETE cmsContentXml //FROM cmsContentXml //JOIN umbracoNode ON (cmsContentXml.nodeId=umbracoNode.Id) - //JOIN uContent ON (cmsContentXml.nodeId=uContent.nodeId) + //JOIN {Constants.DatabaseSchema.Tables.Content} ON (cmsContentXml.nodeId={Constants.DatabaseSchema.Tables.Content}.nodeId) //WHERE umbracoNode.nodeObjectType=@objType - //AND uContent.contentTypeId IN (@ctypes)", - db.Execute(@"DELETE FROM cmsContentXml + //AND {Constants.DatabaseSchema.Tables.Content}.contentTypeId IN (@ctypes)", + db.Execute($@"DELETE FROM cmsContentXml WHERE cmsContentXml.nodeId IN ( SELECT id FROM umbracoNode - JOIN uContent ON uContent.nodeId=umbracoNode.id + JOIN {Constants.DatabaseSchema.Tables.Content} ON {Constants.DatabaseSchema.Tables.Content}.nodeId=umbracoNode.id WHERE umbracoNode.nodeObjectType=@objType - AND uContent.contentTypeId IN (@ctypes) + AND {Constants.DatabaseSchema.Tables.Content}.contentTypeId IN (@ctypes) )", new { objType = contentObjectType, ctypes = contentTypeIdsA }); } @@ -1785,15 +1787,15 @@ WHERE cmsPreviewXml.nodeId IN ( // db.Execute(@"DELETE cmsPreviewXml //FROM cmsPreviewXml //JOIN umbracoNode ON (cmsPreviewXml.nodeId=umbracoNode.Id) - //JOIN uContent ON (cmsPreviewXml.nodeId=uContent.nodeId) + //JOIN {Constants.DatabaseSchema.Tables.Content} ON (cmsPreviewXml.nodeId={Constants.DatabaseSchema.Tables.Content}.nodeId) //WHERE umbracoNode.nodeObjectType=@objType - //AND uContent.contentTypeId IN (@ctypes)", - db.Execute(@"DELETE FROM cmsPreviewXml + //AND {Constants.DatabaseSchema.Tables.Content}.contentTypeId IN (@ctypes)", + db.Execute($@"DELETE FROM cmsPreviewXml WHERE cmsPreviewXml.nodeId IN ( SELECT id FROM umbracoNode - JOIN uContent ON uContent.nodeId=umbracoNode.id + JOIN {Constants.DatabaseSchema.Tables.Content} ON {Constants.DatabaseSchema.Tables.Content}.nodeId=umbracoNode.id WHERE umbracoNode.nodeObjectType=@objType - AND uContent.contentTypeId IN (@ctypes) + AND {Constants.DatabaseSchema.Tables.Content}.contentTypeId IN (@ctypes) )", new { objType = contentObjectType, ctypes = contentTypeIdsA }); } @@ -1808,7 +1810,7 @@ WHERE cmsPreviewXml.nodeId IN ( long total; do { - // .GetPagedResultsByQuery implicitely adds (uDocument.newest = 1) which + // .GetPagedResultsByQuery implicitely adds ({Constants.DatabaseSchema.Tables.Document}.newest = 1) which // is what we want for preview (ie latest version of a content, published or not) var descendants = _documentRepository.GetPage(query, pageIndex++, groupSize, out total, "Path", Direction.Ascending, true); const bool published = true; // previewXml contains edit content! @@ -1860,15 +1862,15 @@ WHERE cmsContentXml.nodeId IN ( // db.Execute(@"DELETE cmsContentXml //FROM cmsContentXml //JOIN umbracoNode ON (cmsContentXml.nodeId=umbracoNode.Id) - //JOIN uContent ON (cmsContentXml.nodeId=uContent.nodeId) + //JOIN {Constants.DatabaseSchema.Tables.Content} ON (cmsContentXml.nodeId={Constants.DatabaseSchema.Tables.Content}.nodeId) //WHERE umbracoNode.nodeObjectType=@objType - //AND uContent.contentTypeId IN (@ctypes)", - db.Execute(@"DELETE FROM cmsContentXml + //AND {Constants.DatabaseSchema.Tables.Content}.contentTypeId IN (@ctypes)", + db.Execute($@"DELETE FROM cmsContentXml WHERE cmsContentXml.nodeId IN ( SELECT id FROM umbracoNode - JOIN uContent ON uContent.nodeId=umbracoNode.id + JOIN {Constants.DatabaseSchema.Tables.Content} ON {Constants.DatabaseSchema.Tables.Content}.nodeId=umbracoNode.id WHERE umbracoNode.nodeObjectType=@objType - AND uContent.contentTypeId IN (@ctypes) + AND {Constants.DatabaseSchema.Tables.Content}.contentTypeId IN (@ctypes) )", new { objType = mediaObjectType, ctypes = contentTypeIdsA }); } @@ -1929,15 +1931,15 @@ WHERE cmsContentXml.nodeId IN ( // db.Execute(@"DELETE cmsContentXml //FROM cmsContentXml //JOIN umbracoNode ON (cmsContentXml.nodeId=umbracoNode.Id) - //JOIN uContent ON (cmsContentXml.nodeId=uContent.nodeId) + //JOIN {Constants.DatabaseSchema.Tables.Content} ON (cmsContentXml.nodeId={Constants.DatabaseSchema.Tables.Content}.nodeId) //WHERE umbracoNode.nodeObjectType=@objType - //AND uContent.contentTypeId IN (@ctypes)", - db.Execute(@"DELETE FROM cmsContentXml + //AND {Constants.DatabaseSchema.Tables.Content}.contentTypeId IN (@ctypes)", + db.Execute($@"DELETE FROM cmsContentXml WHERE cmsContentXml.nodeId IN ( SELECT id FROM umbracoNode - JOIN uContent ON uContent.nodeId=umbracoNode.id + JOIN {Constants.DatabaseSchema.Tables.Content} ON {Constants.DatabaseSchema.Tables.Content}.nodeId=umbracoNode.id WHERE umbracoNode.nodeObjectType=@objType - AND uContent.contentTypeId IN (@ctypes) + AND {Constants.DatabaseSchema.Tables.Content}.contentTypeId IN (@ctypes) )", new { objType = memberObjectType, ctypes = contentTypeIdsA }); } @@ -1980,9 +1982,9 @@ WHERE cmsContentXml.nodeId IN ( var contentObjectType = Constants.ObjectTypes.Document; var db = scope.Database; - var count = db.ExecuteScalar(@"SELECT COUNT(*) + var count = db.ExecuteScalar($@"SELECT COUNT(*) FROM umbracoNode -JOIN uDocument ON (umbracoNode.id=uDocument.nodeId and uDocument.published=1) +JOIN {Constants.DatabaseSchema.Tables.Document} ON (umbracoNode.id={Constants.DatabaseSchema.Tables.Document}.nodeId and {Constants.DatabaseSchema.Tables.Document}.published=1) LEFT JOIN cmsContentXml ON (umbracoNode.id=cmsContentXml.nodeId) WHERE umbracoNode.nodeObjectType=@objType AND cmsContentXml.nodeId IS NULL OR cmsContentXml.xml NOT LIKE '% key=""' @@ -2021,9 +2023,9 @@ AND cmsPreviewXml.nodeId IS NULL OR cmsPreviewXml.xml NOT LIKE '% key=""' var mediaObjectType = Constants.ObjectTypes.Media; var db = scope.Database; - var count = db.ExecuteScalar(@"SELECT COUNT(*) + var count = db.ExecuteScalar($@"SELECT COUNT(*) FROM umbracoNode -JOIN uDocument ON (umbracoNode.id=uDocument.nodeId and uDocument.published=1) +JOIN {Constants.DatabaseSchema.Tables.Document} ON (umbracoNode.id={Constants.DatabaseSchema.Tables.Document}.nodeId and {Constants.DatabaseSchema.Tables.Document}.published=1) LEFT JOIN cmsContentXml ON (umbracoNode.id=cmsContentXml.nodeId) WHERE umbracoNode.nodeObjectType=@objType AND cmsContentXml.nodeId IS NULL OR cmsContentXml.xml NOT LIKE '% key=""' diff --git a/src/Umbraco.Web/Trees/LanguageTreeController.cs b/src/Umbraco.Web/Trees/LanguageTreeController.cs index 76a34385db..0e547fea6a 100644 --- a/src/Umbraco.Web/Trees/LanguageTreeController.cs +++ b/src/Umbraco.Web/Trees/LanguageTreeController.cs @@ -35,6 +35,8 @@ namespace Umbraco.Web.Trees //this will load in a custom UI instead of the dashboard for the root node root.RoutePath = string.Format("{0}/{1}/{2}", Constants.Applications.Settings, Constants.Trees.Languages, "overview"); root.Icon = "icon-flag-alt"; + root.HasChildren = false; + root.MenuUrl = null; return root; } diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index 3d662ce5d5..5ba647ddff 100644 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -138,6 +138,7 @@ + @@ -233,6 +234,8 @@ + +