From c5047148b3668b253dbb43f54297a66bb83b1e7e Mon Sep 17 00:00:00 2001 From: Shannon Date: Tue, 10 Dec 2013 12:56:31 +1100 Subject: [PATCH] Fixes legacy media business logic to return null when calling ToXml if the media item is trashed - this makes it consistent with how content works and also prevents being able to show the media on the front-end when it is trashed. Fixes up how the MediaService rebuilds the XML to make sure it's transactional based. Fixes: U4-3820 cached media xml is not cleared from the cmsContentXml table when recycled Conflicts: src/Umbraco.Web/umbraco.presentation/library.cs --- src/Umbraco.Core/Services/ContentService.cs | 61 +++++++++---------- src/Umbraco.Core/Services/MediaService.cs | 56 +++++++++-------- .../umbraco.presentation/library.cs | 20 +++--- src/umbraco.cms/businesslogic/media/Media.cs | 9 +++ 4 files changed, 83 insertions(+), 63 deletions(-) diff --git a/src/Umbraco.Core/Services/ContentService.cs b/src/Umbraco.Core/Services/ContentService.cs index 543bbcc483..9d80369e93 100644 --- a/src/Umbraco.Core/Services/ContentService.cs +++ b/src/Umbraco.Core/Services/ContentService.cs @@ -1374,49 +1374,48 @@ namespace Umbraco.Core.Services var list = new List(); var uow = _uowProvider.GetUnitOfWork(); - using (var repository = _repositoryFactory.CreateContentRepository(uow)) + + //First we're going to get the data that needs to be inserted before clearing anything, this + //ensures that we don't accidentally leave the content xml table empty if something happens + //during the lookup process. + + list.AddRange(contentTypeIds.Any() == false + ? GetAllPublished() + : contentTypeIds.SelectMany(GetPublishedContentOfContentType)); + + var xmlItems = new List(); + foreach (var c in list) { - //First we're going to get the data that needs to be inserted before clearing anything, this - //ensures that we don't accidentally leave the content xml table empty if something happens - //during the lookup process. + var xml = c.ToXml(); + xmlItems.Add(new ContentXmlDto { NodeId = c.Id, Xml = xml.ToString(SaveOptions.None) }); + } - list.AddRange(contentTypeIds.Any() == false - ? GetAllPublished() - : contentTypeIds.SelectMany(GetPublishedContentOfContentType)); - - var xmlItems = new List(); - foreach (var c in list) + //Ok, now we need to remove the data and re-insert it, we'll do this all in one transaction too. + using (var tr = uow.Database.GetTransaction()) + { + if (contentTypeIds.Any() == false) { - var xml = c.ToXml(); - xmlItems.Add(new ContentXmlDto {NodeId = c.Id, Xml = xml.ToString(SaveOptions.None)}); - } - - //Ok, now we need to remove the data and re-insert it, we'll do this all in one transaction too. - using (var tr = uow.Database.GetTransaction()) - { - if (contentTypeIds.Any() == false) - { - //Remove all Document records from the cmsContentXml table (DO NOT REMOVE Media/Members!) - uow.Database.Execute(@"DELETE FROM cmsContentXml WHERE nodeId IN + //Remove all Document records from the cmsContentXml table (DO NOT REMOVE Media/Members!) + uow.Database.Execute(@"DELETE FROM cmsContentXml WHERE nodeId IN (SELECT DISTINCT cmsContentXml.nodeId FROM cmsContentXml INNER JOIN cmsDocument ON cmsContentXml.nodeId = cmsDocument.nodeId)"); - } - else + } + else + { + foreach (var id in contentTypeIds) { - foreach (var id in contentTypeIds) - { - //first we'll clear out the data from the cmsContentXml table for this type - uow.Database.Execute(@"delete from cmsContentXml where nodeId in + //first we'll clear out the data from the cmsContentXml table for this type + uow.Database.Execute(@"delete from cmsContentXml where nodeId in (select cmsDocument.nodeId from cmsDocument inner join cmsContent on cmsDocument.nodeId = cmsContent.nodeId where published = 1 and contentType = @contentTypeId)", new { contentTypeId = id }); - } } - - //bulk insert it into the database - uow.Database.BulkInsertRecords(xmlItems, tr); } + + //bulk insert it into the database + uow.Database.BulkInsertRecords(xmlItems, tr); } + Audit.Add(AuditTypes.Publish, "RebuildXmlStructures completed, the xml has been regenerated in the database", 0, -1); } } diff --git a/src/Umbraco.Core/Services/MediaService.cs b/src/Umbraco.Core/Services/MediaService.cs index 71231b1d77..8d85007a16 100644 --- a/src/Umbraco.Core/Services/MediaService.cs +++ b/src/Umbraco.Core/Services/MediaService.cs @@ -849,7 +849,34 @@ namespace Umbraco.Core.Services var list = new List(); var uow = _uowProvider.GetUnitOfWork(); - using (var repository = _repositoryFactory.CreateContentRepository(uow)) + + //First we're going to get the data that needs to be inserted before clearing anything, this + //ensures that we don't accidentally leave the content xml table empty if something happens + //during the lookup process. + + if (contentTypeIds.Any() == false) + { + var rootMedia = GetRootMedia(); + foreach (var media in rootMedia) + { + list.Add(media); + list.AddRange(GetDescendants(media)); + } + } + else + { + list.AddRange(contentTypeIds.SelectMany(i => GetMediaOfMediaType(i).Where(media => media.Trashed == false))); + } + + var xmlItems = new List(); + foreach (var c in list) + { + var xml = c.ToXml(); + xmlItems.Add(new ContentXmlDto { NodeId = c.Id, Xml = xml.ToString(SaveOptions.None) }); + } + + //Ok, now we need to remove the data and re-insert it, we'll do this all in one transaction too. + using (var tr = uow.Database.GetTransaction()) { if (contentTypeIds.Any() == false) { @@ -858,16 +885,7 @@ namespace Umbraco.Core.Services (SELECT DISTINCT cmsContentXml.nodeId FROM cmsContentXml INNER JOIN umbracoNode ON cmsContentXml.nodeId = umbracoNode.id WHERE nodeObjectType = @nodeObjectType)", - new {nodeObjectType = Constants.ObjectTypes.Media}); - - // Consider creating a Path query instead of recursive method: - // var query = Query.Builder.Where(x => x.Path.StartsWith("-1")); - var rootMedia = GetRootMedia(); - foreach (var media in rootMedia) - { - list.Add(media); - list.AddRange(GetDescendants(media)); - } + new { nodeObjectType = Constants.ObjectTypes.Media }); } else { @@ -879,24 +897,14 @@ namespace Umbraco.Core.Services INNER JOIN umbracoNode ON cmsContentXml.nodeId = umbracoNode.id INNER JOIN cmsContent ON cmsContent.nodeId = umbracoNode.id WHERE nodeObjectType = @nodeObjectType AND cmsContent.contentType = @contentTypeId)", - new {contentTypeId = id, nodeObjectType = Constants.ObjectTypes.Media}); - - //now get all media objects of this type and add to the list - list.AddRange(GetMediaOfMediaType(id)); + new { contentTypeId = id, nodeObjectType = Constants.ObjectTypes.Media }); } } - var xmlItems = new List(); - foreach (var c in list) - { - //generate the xml - var xml = c.ToXml(); - //create the dto to insert - xmlItems.Add(new ContentXmlDto { NodeId = c.Id, Xml = xml.ToString(SaveOptions.None) }); - } //bulk insert it into the database - uow.Database.BulkInsertRecords(xmlItems); + uow.Database.BulkInsertRecords(xmlItems, tr); } + Audit.Add(AuditTypes.Publish, "RebuildXmlStructures completed, the xml has been regenerated in the database", 0, -1); } } diff --git a/src/Umbraco.Web/umbraco.presentation/library.cs b/src/Umbraco.Web/umbraco.presentation/library.cs index 7e870c3e72..5cc1b85e8e 100644 --- a/src/Umbraco.Web/umbraco.presentation/library.cs +++ b/src/Umbraco.Web/umbraco.presentation/library.cs @@ -474,14 +474,14 @@ namespace umbraco string.Format( "{0}_{1}_{2}", CacheKeys.MediaCacheKey, MediaId, Deep), TimeSpan.FromSeconds(UmbracoSettings.UmbracoLibraryCacheDuration), - () => getMediaDo(MediaId, Deep)); + () => GetMediaDo(MediaId, Deep)); if (retVal != null) return retVal; } else { - return getMediaDo(MediaId, Deep); + return GetMediaDo(MediaId, Deep); } } @@ -494,15 +494,19 @@ namespace umbraco return xd.CreateNavigator().Select("/"); } - private static XPathNodeIterator getMediaDo(int MediaId, bool Deep) + private static XPathNodeIterator GetMediaDo(int mediaId, bool deep) { - Media m = new Media(MediaId); + var m = new Media(mediaId); if (m.nodeObjectType == Media._objectType) { - XmlDocument mXml = new XmlDocument(); - mXml.LoadXml(m.ToXml(mXml, Deep).OuterXml); - XPathNavigator xp = mXml.CreateNavigator(); - string xpath = UmbracoSettings.UseLegacyXmlSchema ? "/node" : String.Format("/{0}", Casing.SafeAliasWithForcingCheck(m.ContentType.Alias)); + var mXml = new XmlDocument(); + var xml = m.ToXml(mXml, deep); + //This will be null if the media isn't public (meaning it is in the trash) + if (xml == null) return null; + //TODO: This is an aweful way of loading in XML - it is very slow. + mXml.LoadXml(xml.OuterXml); + var xp = mXml.CreateNavigator(); + var xpath = UmbracoSettings.UseLegacyXmlSchema ? "/node" : String.Format("/{0}", Casing.SafeAliasWithForcingCheck(m.ContentType.Alias)); return xp.Select(xpath); } return null; diff --git a/src/umbraco.cms/businesslogic/media/Media.cs b/src/umbraco.cms/businesslogic/media/Media.cs index 805ed1a567..4b425f0981 100644 --- a/src/umbraco.cms/businesslogic/media/Media.cs +++ b/src/umbraco.cms/businesslogic/media/Media.cs @@ -243,6 +243,15 @@ namespace umbraco.cms.businesslogic.media #region Public methods + public override XmlNode ToXml(XmlDocument xd, bool Deep) + { + if (IsTrashed == false) + { + return base.ToXml(xd, Deep); + } + return null; + } + /// /// Overrides the moving of a object to a new location by changing its parent id. ///