diff --git a/.hgtags b/.hgtags index 63565343a8..ce40c67fcc 100644 --- a/.hgtags +++ b/.hgtags @@ -27,6 +27,7 @@ ff3bb24ea0c915878396a6ae27f1ff164e8ac150 Release-6.0.0-beta 1719fbd857f28b376639ac2aa0abada0ef2e7560 Release-6.0.0 e02f5aebb87e3f07d27376647756caa9762931d8 Release-4.11.4 14338b0ab1738fbd8987677ecdb9a73d79fc229d release-4.11.6 +ce47176bc6b9298741783e20f1fe2672c811f744 release-4.11.7 b247b35d821144849f551e02da8ba719f91d5fb0 Release-6.0.2 aed55cba29009ad3db48880a7cfb66407ce9805f release-6.0.3 0dee9964687ea51ea797984cf7cce3655d6a6558 release-6.0.4 diff --git a/src/Umbraco.Web.UI/umbraco/login.aspx b/src/Umbraco.Web.UI/umbraco/login.aspx index 47f65fb716..93ca7a7034 100644 --- a/src/Umbraco.Web.UI/umbraco/login.aspx +++ b/src/Umbraco.Web.UI/umbraco/login.aspx @@ -21,7 +21,7 @@ } body { - font-size: 11px; + font-size: 11px; width: 100%; font-family: Trebuchet MS, verdana, arial, Lucida Grande; text-align: center; @@ -70,7 +70,7 @@ - @@ -85,7 +85,7 @@ - diff --git a/src/Umbraco.Web.UI/web.Template.config b/src/Umbraco.Web.UI/web.Template.config index 4702427a8f..dd8264c3fe 100644 --- a/src/Umbraco.Web.UI/web.Template.config +++ b/src/Umbraco.Web.UI/web.Template.config @@ -93,7 +93,7 @@ - + @@ -232,6 +232,14 @@ + + + + + + + + diff --git a/src/Umbraco.Web/UmbracoApplication.cs b/src/Umbraco.Web/UmbracoApplication.cs index 7a47847b5e..b32cbc1f0f 100644 --- a/src/Umbraco.Web/UmbracoApplication.cs +++ b/src/Umbraco.Web/UmbracoApplication.cs @@ -5,6 +5,7 @@ using System.Linq; using System.Text; using System.Web; using System.Web.Hosting; +using System.Web.Mvc; using Umbraco.Core; using Umbraco.Core.Logging; using Umbraco.Web.Routing; @@ -17,6 +18,9 @@ namespace Umbraco.Web /// public class UmbracoApplication : UmbracoApplicationBase { + //don't output the MVC version header (security) + MvcHandler.DisableMvcResponseHeader = true; + protected override IBootManager GetBootManager() { diff --git a/src/Umbraco.Web/UmbracoModule.cs b/src/Umbraco.Web/UmbracoModule.cs index abe135a865..da3ed2f1da 100644 --- a/src/Umbraco.Web/UmbracoModule.cs +++ b/src/Umbraco.Web/UmbracoModule.cs @@ -426,6 +426,15 @@ namespace Umbraco.Web DisposeHttpContextItems(httpContext); }; + + //disable asp.net headers (security) + app.PreSendRequestHeaders += (sender, args) => + { + var httpContext = ((HttpApplication)sender).Context; + httpContext.Response.Headers.Remove("Server"); + //this doesn't normally work since IIS sets it but we'll keep it here anyways. + httpContext.Response.Headers.Remove("X-Powered-By"); + }; } public void Dispose() diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/controls/ContentTypeControlNew.ascx.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/controls/ContentTypeControlNew.ascx.cs index 25285355c1..e1c23b4ad6 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/controls/ContentTypeControlNew.ascx.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/controls/ContentTypeControlNew.ascx.cs @@ -63,11 +63,13 @@ namespace umbraco.controls //the async saving task private Action _asyncSaveTask; + //the async delete property task + private Action _asyncDeleteTask; override protected void OnInit(EventArgs e) { base.OnInit(e); - + LoadContentType(); SetupInfoPane(); @@ -78,17 +80,17 @@ namespace umbraco.controls SetupGenericPropertiesPane(); SetupTabPane(); - } + } protected void Page_Load(object sender, EventArgs e) { - pp_newTab.Text = ui.Text("newtab", UmbracoEnsuredPage.CurrentUser); - pp_alias.Text = ui.Text("alias", UmbracoEnsuredPage.CurrentUser); - pp_name.Text = ui.Text("name", UmbracoEnsuredPage.CurrentUser); - pp_allowedChildren.Text = ui.Text("allowedchildnodetypes", UmbracoEnsuredPage.CurrentUser); - pp_description.Text = ui.Text("editcontenttype", "description"); - pp_icon.Text = ui.Text("icon", UmbracoEnsuredPage.CurrentUser); - pp_thumbnail.Text = ui.Text("editcontenttype", "thumbnail"); + pp_newTab.Text = ui.Text("newtab", CurrentUser); + pp_alias.Text = ui.Text("alias", CurrentUser); + pp_name.Text = ui.Text("name", CurrentUser); + pp_allowedChildren.Text = ui.Text("allowedchildnodetypes", CurrentUser); + pp_description.Text = ui.Text("editcontenttype", "description", CurrentUser); + pp_icon.Text = ui.Text("icon", CurrentUser); + pp_thumbnail.Text = ui.Text("editcontenttype", "thumbnail", CurrentUser); // we'll disable this... @@ -130,20 +132,24 @@ namespace umbraco.controls string originalAlias, string originalName, string newAlias, - string newName) + string newName + string[] originalPropertyAliases) { SaveArgs = saveArgs; - OriginalAlias = originalAlias; - OriginalName = originalName; + _originalAlias = originalAlias; + _originalName = originalName; NewAlias = newAlias; + _originalPropertyAliases = originalPropertyAliases; NewName = newName; } public SaveClickEventArgs SaveArgs { get; private set; } - public string OriginalAlias { get; private set; } - public string OriginalName { get; private set; } + private readonly string _originalAlias; + private readonly string _originalName; public string NewAlias { get; private set; } public string NewName { get; private set; } + private readonly string[] _originalPropertyAliases; + public bool HasAliasChanged() { @@ -153,6 +159,23 @@ namespace umbraco.controls { return (string.Compare(OriginalName, NewName, StringComparison.OrdinalIgnoreCase) != 0); } + + /// + /// Returns true if any property has been removed or if any alias has changed + /// + /// + /// + public bool HasAnyPropertyAliasChanged(ContentType contentType) + { + var newAliases = contentType.PropertyTypes.Select(x => x.Alias).ToArray(); + //if any have been removed, return true + if (newAliases.Length < _originalPropertyAliases.Count()) + { + return true; + } + //otherwise ensure that all of the original aliases are still existing + return newAliases.ContainsAll(_originalPropertyAliases) == false; + } } /// @@ -233,7 +256,7 @@ namespace umbraco.controls var state = new SaveAsyncState(new SaveClickEventArgs("Saved") { IconType = BasePage.speechBubbleIcon.success - }, _contentType.Alias, _contentType.Text, txtAlias.Text, txtName.Text); + }, _contentType.Alias, _contentType.Text, txtAlias.Text, txtName.Text, _contentType.PropertyTypes.Select(x => x.Alias).ToArray()); //Add the async operation to the page Page.RegisterAsyncTask(new PageAsyncTask(BeginAsyncSaveOperation, EndAsyncSaveOperation, HandleAsyncSaveTimeout, state)); @@ -310,13 +333,13 @@ namespace umbraco.controls _contentType.AllowedChildContentTypeIDs = SaveAllowedChildTypes(); _contentType.AllowAtRoot = allowAtRoot.Checked; - + _contentType.Save(); } // Only if the doctype alias changed, cause a regeneration of the xml cache file since // the xml element names will need to be updated to reflect the new alias - if (asyncState.HasAliasChanged()) + if (asyncState.HasAliasChanged(_contentType) || asyncState.HasAnyPropertyAliasChanged(_contentType)) RegenerateXmlCaches(); Trace.Write("ContentTypeControlNew", "task completing"); @@ -347,6 +370,10 @@ namespace umbraco.controls { _contentType = new cms.businesslogic.media.MediaType(docTypeId); } + else if (Request.Path.ToLowerInvariant().Contains("editmembertype.aspx")) + { + _contentType = new cms.businesslogic.member.MemberType(docTypeId); + } else { _contentType = new ContentType(docTypeId); @@ -356,10 +383,19 @@ namespace umbraco.controls /// /// Regenerates the XML caches. Used after a document type alias has been changed. /// + /// + /// We only regenerate any XML cache based on if this is a Document type, not a media type or + /// a member type. + /// private void RegenerateXmlCaches() { - Document.RePublishAll(); - library.RefreshContent(); + _contentType.RebuildXmlStructuresForContent(); + + //special case for DocumentType's + if (_contentType is DocumentType) + { + library.RefreshContent(); + } } /// diff --git a/src/umbraco.businesslogic/BasePages/BasePage.cs b/src/umbraco.businesslogic/BasePages/BasePage.cs index 71dd03b8d4..25c0d5e0ec 100644 --- a/src/umbraco.businesslogic/BasePages/BasePage.cs +++ b/src/umbraco.businesslogic/BasePages/BasePage.cs @@ -251,29 +251,21 @@ namespace umbraco.BasePages { get { - // zb-00004 #29956 : refactor cookies names & handling if (StateHelper.Cookies.HasCookies && StateHelper.Cookies.UserContext.HasValue) - return StateHelper.Cookies.UserContext.GetValue(); - else { try { - string encTicket = StateHelper.Cookies.UserContext.GetValue(); - if (!String.IsNullOrEmpty(encTicket)) - return FormsAuthentication.Decrypt(encTicket).UserData; + var encTicket = StateHelper.Cookies.UserContext.GetValue(); + if (string.IsNullOrEmpty(encTicket) == false) + { + return encTicket.DecryptWithMachineKey(); + } } catch (HttpException ex) { // we swallow this type of exception as it happens if a legacy (pre 4.8.1) cookie is set } - catch (ArgumentException ex) - { - // we swallow this one because it's 99.99% certaincy is legacy based. We'll still log it, though - LogHelper.Error("An error occurred reading auth cookie value", ex); - - } } - return ""; } set @@ -285,25 +277,15 @@ namespace umbraco.BasePages if (StateHelper.Cookies.UserContext.HasValue) StateHelper.Cookies.ClearAll(); - if (!String.IsNullOrEmpty(value)) - { - FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(1, - value, - DateTime.Now, - DateTime.Now.AddDays(1), - false, - value, - FormsAuthentication.FormsCookiePath); - - // Encrypt the ticket. - string encTicket = FormsAuthentication.Encrypt(ticket); - + if (string.IsNullOrEmpty(value) == false) + { + // Encrypt the value + var encTicket = value.EncryptWithMachineKey(); // Create new cookie. - StateHelper.Cookies.UserContext.SetValue(value, 1); - - - } else + StateHelper.Cookies.UserContext.SetValue(encTicket, 1); + } + else { StateHelper.Cookies.UserContext.Clear(); } diff --git a/src/umbraco.businesslogic/StateHelper.cs b/src/umbraco.businesslogic/StateHelper.cs index da79724f2b..387efd2ca3 100644 --- a/src/umbraco.businesslogic/StateHelper.cs +++ b/src/umbraco.businesslogic/StateHelper.cs @@ -454,6 +454,9 @@ namespace umbraco.BusinessLogic if (GlobalSettings.UseSSL) cookie.Secure = true; + //ensure http only, this should only be able to be accessed via the server + cookie.HttpOnly = true; + cookie.Expires = expires; ResponseCookie = cookie; diff --git a/src/umbraco.cms/businesslogic/Content.cs b/src/umbraco.cms/businesslogic/Content.cs index 4c7181892a..2dcde49f8b 100644 --- a/src/umbraco.cms/businesslogic/Content.cs +++ b/src/umbraco.cms/businesslogic/Content.cs @@ -4,6 +4,7 @@ using System.Linq; using System.Xml; using Umbraco.Core; using Umbraco.Core.IO; +using Umbraco.Core.Logging; using Umbraco.Core.Models; using umbraco.cms.businesslogic.property; using umbraco.DataLayer; @@ -386,8 +387,7 @@ namespace umbraco.cms.businesslogic /// public virtual void XmlGenerate(XmlDocument xd) { - XmlNode node = generateXmlWithoutSaving(xd); - SaveXmlDocument(node); + SaveXmlDocument(generateXmlWithoutSaving(xd)); } public virtual void XmlPopulate(XmlDocument xd, ref XmlNode x, bool Deep) @@ -398,27 +398,27 @@ namespace umbraco.cms.businesslogic x.AppendChild(p.ToXml(xd)); // attributes - x.Attributes.Append(xmlHelper.addAttribute(xd, "id", this.Id.ToString())); - x.Attributes.Append(xmlHelper.addAttribute(xd, "version", this.Version.ToString())); + x.Attributes.Append(XmlHelper.AddAttribute(xd, "id", this.Id.ToString())); + x.Attributes.Append(XmlHelper.AddAttribute(xd, "version", this.Version.ToString())); if (this.Level > 1) - x.Attributes.Append(xmlHelper.addAttribute(xd, "parentID", this.Parent.Id.ToString())); + x.Attributes.Append(XmlHelper.AddAttribute(xd, "parentID", this.Parent.Id.ToString())); else - x.Attributes.Append(xmlHelper.addAttribute(xd, "parentID", "-1")); - x.Attributes.Append(xmlHelper.addAttribute(xd, "level", this.Level.ToString())); - x.Attributes.Append(xmlHelper.addAttribute(xd, "writerID", this.User.Id.ToString())); + x.Attributes.Append(XmlHelper.AddAttribute(xd, "parentID", "-1")); + x.Attributes.Append(XmlHelper.AddAttribute(xd, "level", this.Level.ToString())); + x.Attributes.Append(XmlHelper.AddAttribute(xd, "writerID", this.User.Id.ToString())); if (this.ContentType != null) - x.Attributes.Append(xmlHelper.addAttribute(xd, "nodeType", this.ContentType.Id.ToString())); - x.Attributes.Append(xmlHelper.addAttribute(xd, "template", "0")); - x.Attributes.Append(xmlHelper.addAttribute(xd, "sortOrder", this.sortOrder.ToString())); - x.Attributes.Append(xmlHelper.addAttribute(xd, "createDate", this.CreateDateTime.ToString("s"))); - x.Attributes.Append(xmlHelper.addAttribute(xd, "updateDate", this.VersionDate.ToString("s"))); - x.Attributes.Append(xmlHelper.addAttribute(xd, "nodeName", this.Text)); + x.Attributes.Append(XmlHelper.AddAttribute(xd, "nodeType", this.ContentType.Id.ToString())); + x.Attributes.Append(XmlHelper.AddAttribute(xd, "template", "0")); + x.Attributes.Append(XmlHelper.AddAttribute(xd, "sortOrder", this.sortOrder.ToString())); + x.Attributes.Append(XmlHelper.AddAttribute(xd, "createDate", this.CreateDateTime.ToString("s"))); + x.Attributes.Append(XmlHelper.AddAttribute(xd, "updateDate", this.VersionDate.ToString("s"))); + x.Attributes.Append(XmlHelper.AddAttribute(xd, "nodeName", this.Text)); if (this.Text != null) - x.Attributes.Append(xmlHelper.addAttribute(xd, "urlName", this.Text.Replace(" ", "").ToLower())); - x.Attributes.Append(xmlHelper.addAttribute(xd, "writerName", this.User.Name)); + x.Attributes.Append(XmlHelper.AddAttribute(xd, "urlName", this.Text.Replace(" ", "").ToLower())); + x.Attributes.Append(XmlHelper.AddAttribute(xd, "writerName", this.User.Name)); if (this.ContentType != null) - x.Attributes.Append(xmlHelper.addAttribute(xd, "nodeTypeAlias", this.ContentType.Alias)); - x.Attributes.Append(xmlHelper.addAttribute(xd, "path", this.Path)); + x.Attributes.Append(XmlHelper.AddAttribute(xd, "nodeTypeAlias", this.ContentType.Alias)); + x.Attributes.Append(XmlHelper.AddAttribute(xd, "path", this.Path)); if (Deep) { diff --git a/src/umbraco.cms/businesslogic/ContentType.cs b/src/umbraco.cms/businesslogic/ContentType.cs index 6e2f972d43..c11c26f0ee 100644 --- a/src/umbraco.cms/businesslogic/ContentType.cs +++ b/src/umbraco.cms/businesslogic/ContentType.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.Threading; using System.Runtime.CompilerServices; using System.Linq; +using System.Xml; using Umbraco.Core; using Umbraco.Core.Models; using Umbraco.Core.Models.Rdbms; @@ -246,6 +247,84 @@ namespace umbraco.cms.businesslogic #region Public Properties + #region Regenerate Xml Structures + + /// + /// Used to rebuild all of the xml structures for content of the current content type in the cmsContentXml table + /// + [MethodImpl(MethodImplOptions.Synchronized)] + internal void RebuildXmlStructuresForContent() + { + //Clears all xml structures in the cmsContentXml table for the current content type + ClearXmlStructuresForContent(); + foreach (var i in GetContentIdsForContentType()) + { + RebuildXmlStructureForContentItem(i); + } + } + + /// + /// Returns all content ids associated with this content type + /// + /// + /// + /// This will generally just return the content ids associated with this content type but in the case + /// of a DocumentType where we can have inherited types, this will return all content Ids that are of + /// this content type or any descendant types as well. + /// + internal virtual IEnumerable GetContentIdsForContentType() + { + var ids = new List(); + //get all the content item ids of the current content type + using (var dr = SqlHelper.ExecuteReader(@"SELECT DISTINCT cmsContent.nodeId FROM cmsContent + INNER JOIN cmsContentType ON cmsContent.contentType = cmsContentType.nodeId + WHERE cmsContentType.nodeId = @nodeId", + SqlHelper.CreateParameter("@nodeId", this.Id))) + { + while (dr.Read()) + { + ids.Add(dr.GetInt("nodeId")); + } + dr.Close(); + } + return ids; + } + + /// + /// Rebuilds the xml structure for the content item by id + /// + /// + /// + /// This is not thread safe + /// + internal virtual void RebuildXmlStructureForContentItem(int contentId) + { + var xd = new XmlDocument(); + try + { + new Content(contentId).XmlGenerate(xd); + } + catch (Exception ee) + { + LogHelper.Error("Error generating xml", ee); + } + } + + /// + /// Clears all xml structures in the cmsContentXml table for the current content type + /// + internal virtual void ClearXmlStructuresForContent() + { + //Remove all items from the cmsContentXml table that are of this current content type + SqlHelper.ExecuteNonQuery(@"DELETE FROM cmsContentXml WHERE nodeId IN + (SELECT DISTINCT cmsContent.nodeId FROM cmsContent + INNER JOIN cmsContentType ON cmsContent.contentType = cmsContentType.nodeId + WHERE cmsContentType.nodeId = @nodeId)", + SqlHelper.CreateParameter("@nodeId", this.Id)); + } + + #endregion + /// /// The Alias of the ContentType, is used for import/export and more human readable initialization see: GetByAlias /// method. diff --git a/src/umbraco.cms/businesslogic/member/Member.cs b/src/umbraco.cms/businesslogic/member/Member.cs index 3738890789..918327564d 100644 --- a/src/umbraco.cms/businesslogic/member/Member.cs +++ b/src/umbraco.cms/businesslogic/member/Member.cs @@ -647,16 +647,7 @@ namespace umbraco.cms.businesslogic.member FireAfterSave(e); } } - - /// - /// Generates the xmlrepresentation of a member - /// - /// - public override void XmlGenerate(XmlDocument xd) - { - SaveXmlDocument(generateXmlWithoutSaving(xd)); - } - + /// /// Xmlrepresentation of a member /// diff --git a/src/umbraco.cms/businesslogic/member/MemberType.cs b/src/umbraco.cms/businesslogic/member/MemberType.cs index c6ba370986..e480d6fd34 100644 --- a/src/umbraco.cms/businesslogic/member/MemberType.cs +++ b/src/umbraco.cms/businesslogic/member/MemberType.cs @@ -1,5 +1,6 @@ using System; using System.Xml; +using Umbraco.Core.Logging; using umbraco.cms.businesslogic.propertytype; using System.Linq; using umbraco.BusinessLogic; @@ -32,6 +33,30 @@ namespace umbraco.cms.businesslogic.member /// MemberType id public MemberType(Guid id) : base(id) { } + #region Regenerate Xml Structures + + /// + /// Rebuilds the xml structure for the member item by id + /// + /// + /// + /// This is not thread safe + /// + internal override void RebuildXmlStructureForContentItem(int contentId) + { + var xd = new XmlDocument(); + try + { + new Member(contentId).XmlGenerate(xd); + } + catch (Exception ee) + { + LogHelper.Error("Error generating xml", ee); + } + } + + #endregion + #endregion #region Public Methods diff --git a/src/umbraco.cms/businesslogic/web/Document.cs b/src/umbraco.cms/businesslogic/web/Document.cs index 49835a2a68..29e5b4a82e 100644 --- a/src/umbraco.cms/businesslogic/web/Document.cs +++ b/src/umbraco.cms/businesslogic/web/Document.cs @@ -402,22 +402,26 @@ namespace umbraco.cms.businesslogic.web var children = ApplicationContext.Current.Services.ContentService.GetChildrenByName(NodeId, searchString); return children.Select(x => new Document(x)).ToList(); } - - [Obsolete("Obsolete, Use Umbraco.Core.Services.ContentService.RePublishAll()", false)] + + /// + /// This will clear out the cmsContentXml table for all Documents (not media or members) and then + /// rebuild the xml for each Docuemtn item and store it in this table. + /// + /// + /// This method is thread safe + /// [MethodImpl(MethodImplOptions.Synchronized)] + [Obsolete("Obsolete, Use Umbraco.Core.Services.ContentService.RePublishAll()", false)] public static void RePublishAll() { - XmlDocument xd = new XmlDocument(); + var xd = new XmlDocument(); - if (!DataLayerHelper.IsEmbeddedDatabase(SqlHelper.ConnectionString)) - { - SqlHelper.ExecuteNonQuery("truncate table cmsContentXml"); - } - else - { - SqlHelper.ExecuteNonQuery("delete from cmsContentXml"); - } - IRecordsReader dr = SqlHelper.ExecuteReader("select nodeId from cmsDocument where published = 1"); + //Remove all Documents (not media or members), only Documents are stored in the cmsDocument table + SqlHelper.ExecuteNonQuery(@"DELETE FROM cmsContentXml WHERE nodeId IN + (SELECT DISTINCT cmsContentXml.nodeId FROM cmsContentXml + INNER JOIN cmsDocument ON cmsContentXml.nodeId = cmsDocument.nodeId)"); + + var dr = SqlHelper.ExecuteReader("select nodeId from cmsDocument where published = 1"); while (dr.Read()) { @@ -427,7 +431,7 @@ namespace umbraco.cms.businesslogic.web } catch (Exception ee) { - LogHelper.Error("Error generating xml", ee); + LogHelper.Error("Error generating xml", ee); } } dr.Close(); diff --git a/src/umbraco.cms/businesslogic/web/DocumentType.cs b/src/umbraco.cms/businesslogic/web/DocumentType.cs index 0c07a3266c..a552176fd4 100644 --- a/src/umbraco.cms/businesslogic/web/DocumentType.cs +++ b/src/umbraco.cms/businesslogic/web/DocumentType.cs @@ -280,6 +280,86 @@ namespace umbraco.cms.businesslogic.web #region Public Methods + #region Regenerate Xml Structures + + /// + /// This will return all PUBLISHED content Ids that are of this content type or any descendant types as well. + /// + /// + internal override IEnumerable GetContentIdsForContentType() + { + var ids = new List(); + int? currentContentTypeId = this.Id; + while (currentContentTypeId != null) + { + //get all the content item ids of the current content type + using (var dr = SqlHelper.ExecuteReader(@"SELECT DISTINCT cmsDocument.nodeId FROM cmsDocument + INNER JOIN cmsContent ON cmsContent.nodeId = cmsDocument.nodeId + INNER JOIN cmsContentType ON cmsContent.contentType = cmsContentType.nodeId + WHERE cmsContentType.nodeId = @contentTypeId AND cmsDocument.published = 1", + SqlHelper.CreateParameter("@contentTypeId", currentContentTypeId))) + { + while (dr.Read()) + { + ids.Add(dr.GetInt("nodeId")); + } + dr.Close(); + } + + //lookup the child content type if there is one + currentContentTypeId = SqlHelper.ExecuteScalar("SELECT nodeId FROM cmsContentType WHERE masterContentType=@contentTypeId", + SqlHelper.CreateParameter("@contentTypeId", currentContentTypeId)); + } + return ids; + } + + /// + /// Rebuilds the xml structure for the content item by id + /// + /// + /// + /// This is not thread safe + /// + internal override void RebuildXmlStructureForContentItem(int contentId) + { + var xd = new XmlDocument(); + try + { + new Document(contentId).XmlGenerate(xd); + } + catch (Exception ee) + { + LogHelper.Error("Error generating xml", ee); + } + } + + /// + /// Clears all xml structures in the cmsContentXml table for the current content type and any of it's descendant types + /// + /// + /// This is not thread safe + /// + internal override void ClearXmlStructuresForContent() + { + int? currentContentTypeId = this.Id; + while (currentContentTypeId != null) + { + //Remove all items from the cmsContentXml table that are of this current content type + SqlHelper.ExecuteNonQuery(@"DELETE FROM cmsContentXml WHERE nodeId IN + (SELECT DISTINCT cmsContent.nodeId FROM cmsContent + INNER JOIN cmsContentType ON cmsContent.contentType = cmsContentType.nodeId + WHERE cmsContentType.nodeId = @contentTypeId)", + SqlHelper.CreateParameter("@contentTypeId", currentContentTypeId)); + + //lookup the child content type if there is one + currentContentTypeId = SqlHelper.ExecuteScalar("SELECT nodeId FROM cmsContentType WHERE masterContentType=@contentTypeId", + SqlHelper.CreateParameter("@contentTypeId", currentContentTypeId)); + } + + } + + #endregion + [Obsolete("Obsolete, Use RemoveTemplate() on Umbraco.Core.Models.ContentType", false)] public void RemoveTemplate(int templateId) {