From 78d6cac14a2abfe555fb90524ba6d156be86ad46 Mon Sep 17 00:00:00 2001 From: Morten Christensen Date: Thu, 3 Jan 2013 13:19:41 -0100 Subject: [PATCH 1/3] Cleaning up how MasterContentTypes are used to load inherited propertytypes in the backoffice. Fixing the loading of tabs on DocumentTypes in backoffice. Adding check for saving boolean property values in the Integer db column. --- .../Persistence/Factories/PropertyFactory.cs | 14 +++++++++++++- .../controls/ContentTypeControlNew.ascx.cs | 18 +++++++++--------- src/umbraco.cms/businesslogic/ContentType.cs | 15 ++++++++++----- src/umbraco.cms/businesslogic/media/Media.cs | 3 +++ src/umbraco.cms/businesslogic/web/Document.cs | 6 ++++++ 5 files changed, 41 insertions(+), 15 deletions(-) diff --git a/src/Umbraco.Core/Persistence/Factories/PropertyFactory.cs b/src/Umbraco.Core/Persistence/Factories/PropertyFactory.cs index 789646df2d..2dd018ac55 100644 --- a/src/Umbraco.Core/Persistence/Factories/PropertyFactory.cs +++ b/src/Umbraco.Core/Persistence/Factories/PropertyFactory.cs @@ -56,7 +56,19 @@ namespace Umbraco.Core.Persistence.Factories if (property.DataTypeDatabaseType == DataTypeDatabaseType.Integer && property.Value != null && string.IsNullOrWhiteSpace(property.Value.ToString()) == false) { - dto.Integer = int.Parse(property.Value.ToString()); + if (property.Value is bool) + { + int val = Convert.ToInt32(property.Value); + dto.Integer = val; + } + else + { + int val; + if (int.TryParse(property.Value.ToString(), out val)) + { + dto.Integer = val; + } + } } else if (property.DataTypeDatabaseType == DataTypeDatabaseType.Date && property.Value != null && string.IsNullOrWhiteSpace(property.Value.ToString()) == false) { 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 2c06cb849f..252beffbc2 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/controls/ContentTypeControlNew.ascx.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/controls/ContentTypeControlNew.ascx.cs @@ -8,14 +8,13 @@ using System.Web.UI; using System.Web.UI.HtmlControls; using System.Web.UI.WebControls; using ClientDependency.Core; +using Umbraco.Core; using umbraco.cms.helpers; -using umbraco.cms.presentation.Trees; using umbraco.controls.GenericProperties; using umbraco.IO; using umbraco.presentation; using umbraco.cms.businesslogic; using umbraco.BasePages; -using Tuple = System.Tuple; namespace umbraco.controls { @@ -319,8 +318,8 @@ jQuery(document).ready(function() {{ refreshDropDowns(); }}); } private void bindDataGenericProperties(bool Refresh) { - cms.businesslogic.ContentType.TabI[] tabs = cType.getVirtualTabs; - cms.businesslogic.datatype.DataTypeDefinition[] dtds = cms.businesslogic.datatype.DataTypeDefinition.GetAll(); + var tabs = cType.getVirtualTabs.DistinctBy(x => x.ContentType).ToArray(); + var dtds = cms.businesslogic.datatype.DataTypeDefinition.GetAll(); PropertyTypes.Controls.Clear(); @@ -765,14 +764,15 @@ jQuery(document).ready(function() {{ refreshDropDowns(); }}); dt.Columns.Add("name"); dt.Columns.Add("id"); dt.Columns.Add("order"); - foreach (cms.businesslogic.ContentType.TabI tb in cType.getVirtualTabs.ToList()) + + foreach (var grp in cType.PropertyTypeGroups) { - if (tb.ContentType == cType.Id) + if (grp.ContentTypeId == cType.Id) { DataRow dr = dt.NewRow(); - dr["name"] = tb.GetRawCaption(); - dr["id"] = tb.Id; - dr["order"] = tb.SortOrder; + dr["name"] = grp.Name; + dr["id"] = grp.Id; + dr["order"] = grp.SortOrder; dt.Rows.Add(dr); } } diff --git a/src/umbraco.cms/businesslogic/ContentType.cs b/src/umbraco.cms/businesslogic/ContentType.cs index 3db18b7762..96d760c48a 100644 --- a/src/umbraco.cms/businesslogic/ContentType.cs +++ b/src/umbraco.cms/businesslogic/ContentType.cs @@ -543,7 +543,11 @@ namespace umbraco.cms.businesslogic TimeSpan.FromMinutes(15), delegate { - List result = new List(); + //MCH NOTE: For the timing being I have changed this to a dictionary to ensure that property types + //aren't added multiple times through the MasterContentType structure, because each level loads + //its own + inherited property types, which is wrong. Once we are able to fully switch to the new api + //this should no longer be a problem as the composition always contains a correct list of property types. + var result = new Dictionary(); using (IRecordsReader dr = SqlHelper.ExecuteReader( "select id from cmsPropertyType where contentTypeId = @ctId order by sortOrder", @@ -554,7 +558,7 @@ namespace umbraco.cms.businesslogic int id = dr.GetInt("id"); PropertyType pt = PropertyType.GetPropertyType(id); if (pt != null) - result.Add(pt); + result.Add(pt.Id, pt); } } @@ -563,14 +567,15 @@ namespace umbraco.cms.businesslogic { foreach (var mct in MasterContentTypes) { - List pts = ContentType.GetContentType(mct).PropertyTypes; + var pts = ContentType.GetContentType(mct).PropertyTypes; foreach (PropertyType pt in pts) { - result.Add(pt); + if(result.ContainsKey(pt.Id) == false) + result.Add(pt.Id, pt); } } } - return result; + return result.Select(x => x.Value).ToList(); }); } } diff --git a/src/umbraco.cms/businesslogic/media/Media.cs b/src/umbraco.cms/businesslogic/media/Media.cs index 4695fab3cc..9328bbf4fb 100644 --- a/src/umbraco.cms/businesslogic/media/Media.cs +++ b/src/umbraco.cms/businesslogic/media/Media.cs @@ -296,6 +296,9 @@ namespace umbraco.cms.businesslogic.media foreach (var property in GenericProperties) { + if (property.Value == null) + continue; + MediaItem.SetValue(property.PropertyType.Alias, property.Value); } diff --git a/src/umbraco.cms/businesslogic/web/Document.cs b/src/umbraco.cms/businesslogic/web/Document.cs index 31c730dd45..b4840249ef 100644 --- a/src/umbraco.cms/businesslogic/web/Document.cs +++ b/src/umbraco.cms/businesslogic/web/Document.cs @@ -934,6 +934,9 @@ namespace umbraco.cms.businesslogic.web foreach (var property in GenericProperties) { + if (property.Value == null) + continue; + Content.SetValue(property.PropertyType.Alias, property.Value); } @@ -962,6 +965,9 @@ namespace umbraco.cms.businesslogic.web foreach (var property in GenericProperties) { + if(property.Value == null) + continue; + Content.SetValue(property.PropertyType.Alias, property.Value); } From a421999ef8a7ca95ed03c46ac5823b8ab5175185 Mon Sep 17 00:00:00 2001 From: Sebastiaan Janssen Date: Thu, 3 Jan 2013 13:56:53 -0100 Subject: [PATCH 2/3] Fix missing connection string during upgrades --- src/umbraco.businesslogic/Application.cs | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/umbraco.businesslogic/Application.cs b/src/umbraco.businesslogic/Application.cs index e776569fc6..9b1a6b5bab 100644 --- a/src/umbraco.businesslogic/Application.cs +++ b/src/umbraco.businesslogic/Application.cs @@ -5,6 +5,7 @@ using System.IO; using System.Linq; using System.Web; using System.Xml.Linq; +using Umbraco.Core; using umbraco.DataLayer; using umbraco.IO; using System.Runtime.CompilerServices; @@ -79,8 +80,19 @@ namespace umbraco.BusinessLogic { try { - var databaseSettings = ConfigurationManager.ConnectionStrings[Umbraco.Core.Configuration.GlobalSettings.UmbracoConnectionName]; - _sqlHelper = DataLayerHelper.CreateSqlHelper(databaseSettings.ConnectionString); + const string umbracoDsn = Umbraco.Core.Configuration.GlobalSettings.UmbracoConnectionName; + + var connectionString = string.Empty; + + var databaseSettings = ConfigurationManager.ConnectionStrings[umbracoDsn]; + if(databaseSettings != null) + connectionString = databaseSettings.ConnectionString; + + // During upgrades we might still have the old appSettings connectionstring, and not the new one, so get that one instead + if (string.IsNullOrWhiteSpace(connectionString) && ConfigurationManager.AppSettings.ContainsKey(umbracoDsn)) + connectionString = ConfigurationManager.AppSettings[umbracoDsn]; + + _sqlHelper = DataLayerHelper.CreateSqlHelper(connectionString); } catch { } } From 9520f2d57053e9a47d0df3cf2a38e7b102bae919 Mon Sep 17 00:00:00 2001 From: Morten Christensen Date: Thu, 3 Jan 2013 15:16:17 -0100 Subject: [PATCH 3/3] Fixes how PropertyTypes are removed from a DocumentType or MediaType when using the backoffice. --- src/Umbraco.Core/Models/ContentTypeBase.cs | 26 ++++++++-- src/Umbraco.Core/Models/IContentTypeBase.cs | 10 ++++ .../Models/PropertyTypeCollection.cs | 8 +++ .../controls/ContentTypeControlNew.ascx.cs | 35 +++++++++++-- src/umbraco.cms/businesslogic/ContentType.cs | 50 +++++++++++-------- 5 files changed, 99 insertions(+), 30 deletions(-) diff --git a/src/Umbraco.Core/Models/ContentTypeBase.cs b/src/Umbraco.Core/Models/ContentTypeBase.cs index d44b132832..5d86e4cc2c 100644 --- a/src/Umbraco.Core/Models/ContentTypeBase.cs +++ b/src/Umbraco.Core/Models/ContentTypeBase.cs @@ -93,11 +93,6 @@ namespace Umbraco.Core.Models } } - public void SetLazyParentId(Lazy id) - { - _parentId = id; - } - /// /// Gets or sets the name of the current entity /// @@ -309,6 +304,27 @@ namespace Umbraco.Core.Models get { return PropertyGroups.SelectMany(x => x.PropertyTypes); } } + /// + /// Removes a PropertyType from the current ContentType + /// + /// Alias of the to remove + public void RemovePropertyType(string propertyTypeAlias) + { + foreach (var propertyGroup in PropertyGroups) + { + propertyGroup.PropertyTypes.RemoveItem(propertyTypeAlias); + } + } + + /// + /// Sets the ParentId from the lazy integer id + /// + /// Id of the Parent + public void SetLazyParentId(Lazy id) + { + _parentId = id; + } + //TODO Implement moving PropertyType between groups. /*public bool MovePropertyTypeToGroup(string propertyTypeAlias, string groupName) {}*/ diff --git a/src/Umbraco.Core/Models/IContentTypeBase.cs b/src/Umbraco.Core/Models/IContentTypeBase.cs index db1a86f4e9..2b19dd216c 100644 --- a/src/Umbraco.Core/Models/IContentTypeBase.cs +++ b/src/Umbraco.Core/Models/IContentTypeBase.cs @@ -63,6 +63,16 @@ namespace Umbraco.Core.Models /// IEnumerable PropertyTypes { get; } + /// + /// Removes a PropertyType from the current ContentType + /// + /// Alias of the to remove + void RemovePropertyType(string propertyTypeAlias); + + /// + /// Sets the ParentId from the lazy integer id + /// + /// Id of the Parent void SetLazyParentId(Lazy id); } } \ No newline at end of file diff --git a/src/Umbraco.Core/Models/PropertyTypeCollection.cs b/src/Umbraco.Core/Models/PropertyTypeCollection.cs index bba80a5ee0..27e3926f09 100644 --- a/src/Umbraco.Core/Models/PropertyTypeCollection.cs +++ b/src/Umbraco.Core/Models/PropertyTypeCollection.cs @@ -97,6 +97,14 @@ namespace Umbraco.Core.Models return this.Any(x => x.Alias == propertyAlias); } + public void RemoveItem(string propertyTypeAlias) + { + var key = IndexOfKey(propertyTypeAlias); + //Only removes an item if the key was found + if(key != -1) + RemoveItem(key); + } + public int IndexOfKey(string key) { for (var i = 0; i < this.Count; i++) 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 252beffbc2..e7f6bed492 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/controls/ContentTypeControlNew.ascx.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/controls/ContentTypeControlNew.ascx.cs @@ -9,12 +9,14 @@ using System.Web.UI.HtmlControls; using System.Web.UI.WebControls; using ClientDependency.Core; using Umbraco.Core; +using Umbraco.Core.Models; +using umbraco.cms.businesslogic.web; using umbraco.cms.helpers; using umbraco.controls.GenericProperties; using umbraco.IO; using umbraco.presentation; -using umbraco.cms.businesslogic; using umbraco.BasePages; +using ContentType = umbraco.cms.businesslogic.ContentType; namespace umbraco.controls { @@ -59,7 +61,19 @@ namespace umbraco.controls base.OnInit(e); int docTypeId = getDocTypeId(); - cType = new cms.businesslogic.ContentType(docTypeId); + //Fairly hacky code to load the ContentType as the real type instead of its base type, so it can be properly saved. + if (Request.Path.ToLowerInvariant().Contains("editnodetypenew.aspx")) + { + cType = new cms.businesslogic.web.DocumentType(docTypeId); + } + else if (Request.Path.ToLowerInvariant().Contains("editmediatype.aspx")) + { + cType = new cms.businesslogic.media.MediaType(docTypeId); + } + else + { + cType = new cms.businesslogic.ContentType(docTypeId); + } setupInfoPane(); if (!HideStructure) @@ -126,6 +140,15 @@ namespace umbraco.controls SaveAllowedChildTypes(); + if (cType.ContentTypeItem is IContentType) + { + ((DocumentType)cType).Save(); + } + else if (cType.ContentTypeItem is IMediaType) + { + ((umbraco.cms.businesslogic.media.MediaType)cType).Save(); + } + // reload content type (due to caching) cType = new ContentType(cType.Id); @@ -516,8 +539,14 @@ jQuery(document).ready(function() {{ refreshDropDowns(); }}); protected void gpw_Delete(object sender, System.EventArgs e) { - GenericProperties.GenericPropertyWrapper gpw = (GenericProperties.GenericPropertyWrapper)sender; + var gpw = (GenericProperties.GenericPropertyWrapper)sender; + var alias = gpw.PropertyType.Alias; + gpw.GenricPropertyControl.PropertyType.delete(); + //We have to ensure that the property type is removed from the underlying IContentType object + cType.ContentTypeItem.RemovePropertyType(alias); + cType.Save(); + cType = ContentType.GetContentType(cType.Id); this.bindDataGenericProperties(true); } diff --git a/src/umbraco.cms/businesslogic/ContentType.cs b/src/umbraco.cms/businesslogic/ContentType.cs index 96d760c48a..529fefb11a 100644 --- a/src/umbraco.cms/businesslogic/ContentType.cs +++ b/src/umbraco.cms/businesslogic/ContentType.cs @@ -75,7 +75,7 @@ namespace umbraco.cms.businesslogic internal ContentType(IContentTypeComposition contentType) : base(contentType) { - _contentType = contentType; + ContentTypeItem = contentType; } #endregion @@ -279,7 +279,7 @@ namespace umbraco.cms.businesslogic private static readonly object propertyTypesCacheSyncLock = new object(); - private IContentTypeComposition _contentType; + protected internal IContentTypeComposition ContentTypeItem; #endregion @@ -304,7 +304,7 @@ namespace umbraco.cms.businesslogic //This switches between using new vs. legacy api. //Note that this is currently only done to support both DocumentType and MediaType, which use the new api and MemberType that doesn't. - if (_contentType == null) + if (ContentTypeItem == null) { SqlHelper.ExecuteNonQuery("update cmsContentType set alias = @alias where nodeId = @id", SqlHelper.CreateParameter("@alias", _alias), @@ -312,7 +312,7 @@ namespace umbraco.cms.businesslogic } else { - _contentType.Alias = _alias; + ContentTypeItem.Alias = _alias; } // Remove from cache @@ -333,13 +333,13 @@ namespace umbraco.cms.businesslogic //This switches between using new vs. legacy api. //Note that this is currently only done to support both DocumentType and MediaType, which use the new api and MemberType that doesn't. - if (_contentType == null) + if (ContentTypeItem == null) { SqlHelper.ExecuteNonQuery("update cmsContentType set icon='" + value + "' where nodeid = " + Id); } else { - _contentType.Icon = _iconurl; + ContentTypeItem.Icon = _iconurl; } // Remove from cache @@ -360,7 +360,7 @@ namespace umbraco.cms.businesslogic //This switches between using new vs. legacy api. //Note that this is currently only done to support both DocumentType and MediaType, which use the new api and MemberType that doesn't. - if (_contentType == null) + if (ContentTypeItem == null) { SqlHelper.ExecuteNonQuery( "update cmsContentType set isContainer = @isContainer where nodeId = @id", @@ -369,7 +369,7 @@ namespace umbraco.cms.businesslogic } else { - _contentType.IsContainer = _isContainerContentType; + ContentTypeItem.IsContainer = _isContainerContentType; } } } @@ -386,7 +386,7 @@ namespace umbraco.cms.businesslogic //This switches between using new vs. legacy api. //Note that this is currently only done to support both DocumentType and MediaType, which use the new api and MemberType that doesn't. - if (_contentType == null) + if (ContentTypeItem == null) { SqlHelper.ExecuteNonQuery( "update cmsContentType set allowAtRoot = @allowAtRoot where nodeId = @id", @@ -395,7 +395,7 @@ namespace umbraco.cms.businesslogic } else { - _contentType.AllowedAsRoot = _allowAtRoot; + ContentTypeItem.AllowedAsRoot = _allowAtRoot; } } } @@ -437,7 +437,7 @@ namespace umbraco.cms.businesslogic //This switches between using new vs. legacy api. //Note that this is currently only done to support both DocumentType and MediaType, which use the new api and MemberType that doesn't. - if (_contentType == null) + if (ContentTypeItem == null) { SqlHelper.ExecuteNonQuery( "update cmsContentType set description = @description where nodeId = @id", @@ -446,7 +446,7 @@ namespace umbraco.cms.businesslogic } else { - _contentType.Description = _description; + ContentTypeItem.Description = _description; } FlushFromCache(Id); @@ -466,7 +466,7 @@ namespace umbraco.cms.businesslogic //This switches between using new vs. legacy api. //Note that this is currently only done to support both DocumentType and MediaType, which use the new api and MemberType that doesn't. - if (_contentType == null) + if (ContentTypeItem == null) { SqlHelper.ExecuteNonQuery( "update cmsContentType set thumbnail = @thumbnail where nodeId = @id", @@ -475,7 +475,7 @@ namespace umbraco.cms.businesslogic } else { - _contentType.Thumbnail = _thumbnail; + ContentTypeItem.Thumbnail = _thumbnail; } FlushFromCache(Id); @@ -514,9 +514,9 @@ namespace umbraco.cms.businesslogic { base.Text = value; - if (_contentType != null) + if (ContentTypeItem != null) { - _contentType.Name = value; + ContentTypeItem.Name = value; } // Remove from cache @@ -587,7 +587,7 @@ namespace umbraco.cms.businesslogic if (m_masterContentTypes == null) { m_masterContentTypes = new List(); - if (_contentType == null) + if (ContentTypeItem == null) { //TODO Make this recursive, so it looks up Masters of the Master ContentType using ( @@ -604,7 +604,7 @@ namespace umbraco.cms.businesslogic } else { - m_masterContentTypes = _contentType.CompositionIds().ToList(); + m_masterContentTypes = ContentTypeItem.CompositionIds().ToList(); } } @@ -788,7 +788,7 @@ namespace umbraco.cms.businesslogic //This switches between using new vs. legacy api. //Note that this is currently only done to support both DocumentType and MediaType, which use the new api and MemberType that doesn't. - if (_contentType == null) + if (ContentTypeItem == null) { SqlHelper.ExecuteNonQuery( "delete from cmsContentTypeAllowedContentType where id=" + Id); @@ -810,7 +810,7 @@ namespace umbraco.cms.businesslogic sort++; } - _contentType.AllowedContentTypes = list; + ContentTypeItem.AllowedContentTypes = list; } } } @@ -917,6 +917,12 @@ namespace umbraco.cms.businesslogic public void removePropertyTypeFromTab(PropertyType pt) { pt.TabId = 0; //this will set to null in the database. + + if (ContentTypeItem != null) + { + ContentTypeItem.RemovePropertyType(pt.Alias); + } + // Remove from cache FlushFromCache(Id); } @@ -1056,8 +1062,8 @@ namespace umbraco.cms.businesslogic _thumbnail = contentType.Thumbnail; _description = contentType.Description; - if (_contentType == null) - _contentType = contentType; + if (ContentTypeItem == null) + ContentTypeItem = contentType; } protected void PopulateContentTypeNodeFromReader(IRecordsReader dr)