diff --git a/.gitignore b/.gitignore index 51405dd753..b6839b4e04 100644 --- a/.gitignore +++ b/.gitignore @@ -84,3 +84,4 @@ src/*.psess NDependOut/* *.ndproj QueryResult.htm +*.ndproj diff --git a/src/Umbraco.Core/Persistence/Repositories/ContentRepository.cs b/src/Umbraco.Core/Persistence/Repositories/ContentRepository.cs index 870ed2cc00..f290b5b54a 100644 --- a/src/Umbraco.Core/Persistence/Repositories/ContentRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/ContentRepository.cs @@ -170,11 +170,31 @@ namespace Umbraco.Core.Persistence.Repositories return content; } + public override void DeleteVersion(Guid versionId) + { + var sql = new Sql() + .Select("*") + .From() + .InnerJoin().On(left => left.VersionId, right => right.VersionId) + .Where(x => x.VersionId == versionId) + .Where(x => x.Newest == true); + var dto = Database.Fetch(sql).FirstOrDefault(); + + if(dto == null) return; + + using (var transaction = Database.GetTransaction()) + { + PerformDeleteVersion(dto.NodeId, versionId); + + transaction.Complete(); + } + } + protected override void PerformDeleteVersion(int id, Guid versionId) { Database.Delete("WHERE nodeId = @Id AND versionId = @VersionId", new { Id = id, VersionId = versionId }); - Database.Delete("WHERE nodeId = @Id AND versionId = @VersionId", new { Id = id, VersionId = versionId }); - Database.Delete("WHERE nodeId = @Id AND VersionId = @VersionId", new { Id = id, VersionId = versionId }); + Database.Delete("WHERE contentNodeId = @Id AND versionId = @VersionId", new { Id = id, VersionId = versionId }); + Database.Delete("WHERE ContentId = @Id AND VersionId = @VersionId", new { Id = id, VersionId = versionId }); Database.Delete("WHERE nodeId = @Id AND versionId = @VersionId", new { Id = id, VersionId = versionId }); } @@ -340,19 +360,18 @@ namespace Umbraco.Core.Persistence.Repositories } } + //Look up (newest) entries by id in cmsDocument table to set newest = false + var documentDtos = Database.Fetch("WHERE nodeId = @Id AND newest = @IsNewest", new { Id = entity.Id, IsNewest = true }); + foreach (var documentDto in documentDtos) + { + var docDto = documentDto; + docDto.Newest = false; + Database.Update(docDto); + } + var contentVersionDto = dto.ContentVersionDto; if (shouldCreateNewVersion) { - //Look up (newest) entries by id in cmsDocument table to set newest = false - //NOTE: This is only relevant when a new version is created, which is why its done inside this if-statement. - var documentDtos = Database.Fetch("WHERE nodeId = @Id AND newest = @IsNewest", new { Id = entity.Id, IsNewest = true }); - foreach (var documentDto in documentDtos) - { - var docDto = documentDto; - docDto.Newest = false; - Database.Update(docDto); - } - //Create a new version - cmsContentVersion //Assumes a new Version guid and Version date (modified date) has been set Database.Insert(contentVersionDto); diff --git a/src/Umbraco.Core/Persistence/Repositories/MediaRepository.cs b/src/Umbraco.Core/Persistence/Repositories/MediaRepository.cs index e27fac1ba3..8292fc8977 100644 --- a/src/Umbraco.Core/Persistence/Repositories/MediaRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/MediaRepository.cs @@ -176,8 +176,8 @@ namespace Umbraco.Core.Persistence.Repositories protected override void PerformDeleteVersion(int id, Guid versionId) { Database.Delete("WHERE nodeId = @Id AND versionId = @VersionId", new { Id = id, VersionId = versionId }); - Database.Delete("WHERE nodeId = @Id AND versionId = @VersionId", new { Id = id, VersionId = versionId }); - Database.Delete("WHERE nodeId = @Id AND VersionId = @VersionId", new { Id = id, VersionId = versionId }); + Database.Delete("WHERE contentNodeId = @Id AND versionId = @VersionId", new { Id = id, VersionId = versionId }); + Database.Delete("WHERE ContentId = @Id AND VersionId = @VersionId", new { Id = id, VersionId = versionId }); } #endregion diff --git a/src/Umbraco.Core/Persistence/Repositories/VersionableRepositoryBase.cs b/src/Umbraco.Core/Persistence/Repositories/VersionableRepositoryBase.cs index 0ed84582fa..9b9160b66a 100644 --- a/src/Umbraco.Core/Persistence/Repositories/VersionableRepositoryBase.cs +++ b/src/Umbraco.Core/Persistence/Repositories/VersionableRepositoryBase.cs @@ -43,8 +43,8 @@ namespace Umbraco.Core.Persistence.Repositories public virtual void DeleteVersion(Guid versionId) { - var dto = Database.FirstOrDefault("WHERE versionId = @VersionId AND newest = @Newest", new { VersionId = versionId, Newest = false }); - Mandate.That(dto != null); + var dto = Database.FirstOrDefault("WHERE versionId = @VersionId", new { VersionId = versionId }); + if(dto == null) return; using (var transaction = Database.GetTransaction()) { @@ -56,8 +56,8 @@ namespace Umbraco.Core.Persistence.Repositories public virtual void DeleteVersions(int id, DateTime versionDate) { - var list = Database.Fetch("WHERE nodeId = @Id AND VersionDate < @VersionDate", new { Id = id, VersionDate = versionDate }); - Mandate.That(list.Any()); + var list = Database.Fetch("WHERE ContentId = @Id AND VersionDate < @VersionDate", new { Id = id, VersionDate = versionDate }); + if (list.Any() == false) return; using (var transaction = Database.GetTransaction()) { diff --git a/src/Umbraco.Tests/Models/DataValueSetterTests.cs b/src/Umbraco.Tests/Models/DataValueSetterTests.cs index db59217166..891c53dd0d 100644 --- a/src/Umbraco.Tests/Models/DataValueSetterTests.cs +++ b/src/Umbraco.Tests/Models/DataValueSetterTests.cs @@ -66,6 +66,7 @@ namespace Umbraco.Tests.Models var dataTypeId = Guid.NewGuid(); var dataTypeData = MockRepository.GenerateMock(); + dataTypeData .Stub(data => data.ToXMl(Arg.Is.Anything)) .Return(null) // you have to call Return() even though we're about to override it @@ -98,5 +99,18 @@ namespace Umbraco.Tests.Models ((IDataValueSetter)dataTypeData).AssertWasCalled(setter => setter.SetValue("Hello world", DataTypeDatabaseType.Nvarchar.ToString())); } + [TestCase(DataTypeDatabaseType.Nvarchar)] + [TestCase(DataTypeDatabaseType.Date)] + [TestCase(DataTypeDatabaseType.Integer)] + [TestCase(DataTypeDatabaseType.Ntext)] + public void DefaultData_SetValue_Ensures_Empty_String_When_Null_Value_Any_Data_Type(DataTypeDatabaseType type) + { + var defaultData = new DefaultData(MockRepository.GenerateMock()); + + ((IDataValueSetter)defaultData).SetValue(null, type.ToString()); + + Assert.AreEqual(string.Empty, defaultData.Value); + } + } } \ No newline at end of file diff --git a/src/Umbraco.Tests/Services/ContentServiceTests.cs b/src/Umbraco.Tests/Services/ContentServiceTests.cs index 522f608272..a8d3f6d30c 100644 --- a/src/Umbraco.Tests/Services/ContentServiceTests.cs +++ b/src/Umbraco.Tests/Services/ContentServiceTests.cs @@ -861,6 +861,22 @@ namespace Umbraco.Tests.Services Assert.That(sut.GetValue("imgCropper"), Is.Empty); } + [Test] + public void Can_Delete_Previous_Versions_Not_Latest() + { + // Arrange + var contentService = ServiceContext.ContentService; + var content = contentService.GetById(1049); + var version = content.Version; + + // Act + contentService.DeleteVersion(1049, version, true, 0); + var sut = contentService.GetById(1049); + + // Assert + Assert.That(sut.Version, Is.EqualTo(version)); + } + private IEnumerable CreateContentHierarchy() { var contentType = ServiceContext.ContentTypeService.GetContentType("umbTextpage"); diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/create/PartialViewTasks.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/create/PartialViewTasks.cs index c1c9f27a8a..9d9e65f151 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/create/PartialViewTasks.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/create/PartialViewTasks.cs @@ -101,8 +101,7 @@ namespace umbraco { //write out the template header sw.Write("@inherits "); - sw.Write(typeof(UmbracoViewPage<>).FullName.TrimEnd("`1")); - sw.Write(""); + sw.Write(typeof(UmbracoTemplatePage).FullName.TrimEnd("`1")); } public bool Delete() diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/dialogs/moveOrCopy.aspx.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/dialogs/moveOrCopy.aspx.cs index ccd6c6481d..86446782fe 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/dialogs/moveOrCopy.aspx.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/dialogs/moveOrCopy.aspx.cs @@ -272,11 +272,15 @@ namespace umbraco.dialogs { if (CurrentApp == Constants.Applications.Content) { - Services.ContentService.Move((IContent)currContent, Request.GetItemAs("copyTo"), getUser().Id); + //Backwards comp. change, so old events are fired #U4-2731 + var doc = new Document(currContent as IContent); + doc.Move(Request.GetItemAs("copyTo")); } else { - Services.MediaService.Move((IMedia)currContent, Request.GetItemAs("copyTo"), getUser().Id); + //Backwards comp. change, so old events are fired #U4-2731 + var media = new umbraco.cms.businesslogic.media.Media(currContent as IMedia); + media.Move(Request.GetItemAs("copyTo")); library.ClearLibraryCacheForMedia(currContent.Id); } @@ -290,7 +294,9 @@ namespace umbraco.dialogs { //NOTE: We ONLY support Copy on content not media for some reason. - var newContent = Services.ContentService.Copy((IContent)currContent, Request.GetItemAs("copyTo"), RelateDocuments.Checked, getUser().Id); + //Backwards comp. change, so old events are fired #U4-2731 + var newContent = new Document(currContent as IContent); + newContent.Copy(Request.GetItemAs("copyTo"), getUser(), RelateDocuments.Checked); feedback.Text = ui.Text("moveOrCopy", "copyDone", nodes, getUser()) + "

" + ui.Text("closeThisWindow") + ""; feedback.type = uicontrols.Feedback.feedbacktype.success; diff --git a/src/umbraco.cms/businesslogic/datatype/DefaultData.cs b/src/umbraco.cms/businesslogic/datatype/DefaultData.cs index a974fda7c2..471fcc9479 100644 --- a/src/umbraco.cms/businesslogic/datatype/DefaultData.cs +++ b/src/umbraco.cms/businesslogic/datatype/DefaultData.cs @@ -65,6 +65,17 @@ namespace umbraco.cms.businesslogic.datatype /// void IDataValueSetter.SetValue(object val, string strDbType) { + //We need to ensure that val is not a null value, if it is then we'll convert this to an empty string. + //The reason for this is because by default the DefaultData.Value property returns an empty string when + // there is no value, this is based on the PropertyDataDto.GetValue return value which defaults to an + // empty string (which is called from this class's method LoadValueFromDatabase). + //Some legacy implementations of DefaultData are expecting an empty string when there is + // no value so we need to keep this consistent. + if (val == null) + { + val = string.Empty; + } + _value = val; //now that we've set our value, we can update our BaseDataType object with the correct values from the db //instead of making it query for itself. This is a peformance optimization enhancement.