From 0632ffb93dc4a45adbe284042c1484b1bc338a5a Mon Sep 17 00:00:00 2001 From: Morten Christensen Date: Sat, 20 Apr 2013 11:03:57 -0200 Subject: [PATCH 01/19] Fixes #U4-2069 --- src/Umbraco.Core/Services/ContentService.cs | 2 +- src/Umbraco.Core/Services/MediaService.cs | 11 +++++++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/Umbraco.Core/Services/ContentService.cs b/src/Umbraco.Core/Services/ContentService.cs index 036a40f240..0813cbd694 100644 --- a/src/Umbraco.Core/Services/ContentService.cs +++ b/src/Umbraco.Core/Services/ContentService.cs @@ -560,7 +560,7 @@ namespace Umbraco.Core.Services } /// - /// Permanently deletes an object. + /// Permanently deletes an object as well as all of its Children. /// /// /// This method will also delete associated media files, child content and possibly associated domains. diff --git a/src/Umbraco.Core/Services/MediaService.cs b/src/Umbraco.Core/Services/MediaService.cs index ced8372720..07a7c11fdd 100644 --- a/src/Umbraco.Core/Services/MediaService.cs +++ b/src/Umbraco.Core/Services/MediaService.cs @@ -489,11 +489,11 @@ namespace Umbraco.Core.Services } /// - /// Permanently deletes an object + /// Permanently deletes an object as well as all of its Children. /// /// /// Please note that this method will completely remove the Media from the database, - /// but current not from the file system. + /// as well as associated media files from the file system. /// /// The to delete /// Id of the User deleting the Media @@ -502,6 +502,13 @@ namespace Umbraco.Core.Services if (Deleting.IsRaisedEventCancelled(new DeleteEventArgs(media), this)) return; + //Delete children before deleting the 'possible parent' + var children = GetChildren(media.Id); + foreach (var child in children) + { + Delete(child, userId); + } + var uow = _uowProvider.GetUnitOfWork(); using (var repository = _repositoryFactory.CreateMediaRepository(uow)) { From 59184981cb8a551f0a7061efa0b66a2138e46713 Mon Sep 17 00:00:00 2001 From: Morten Christensen Date: Sat, 20 Apr 2013 11:05:48 -0200 Subject: [PATCH 02/19] Fixes #U4-2009 Delete of media doesnt delete relations --- src/Umbraco.Core/Persistence/Repositories/MediaRepository.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Umbraco.Core/Persistence/Repositories/MediaRepository.cs b/src/Umbraco.Core/Persistence/Repositories/MediaRepository.cs index 34d67e5db8..24e6f409ca 100644 --- a/src/Umbraco.Core/Persistence/Repositories/MediaRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/MediaRepository.cs @@ -118,6 +118,8 @@ namespace Umbraco.Core.Persistence.Repositories { "DELETE FROM umbracoUser2NodeNotify WHERE nodeId = @Id", "DELETE FROM umbracoUser2NodePermission WHERE nodeId = @Id", + "DELETE FROM umbracoRelation WHERE parentId = @Id", + "DELETE FROM umbracoRelation WHERE childId = @Id", "DELETE FROM cmsTagRelationship WHERE nodeId = @Id", "DELETE FROM cmsDocument WHERE NodeId = @Id", "DELETE FROM cmsPropertyData WHERE contentNodeId = @Id", From 1e21671b620e2d98d7051ecd329e3adad5680a15 Mon Sep 17 00:00:00 2001 From: Morten Christensen Date: Sat, 20 Apr 2013 11:10:28 -0200 Subject: [PATCH 03/19] Fixes #U4-2008 Umbraco.Core.Models.PropertyType -> change ValidationRegExp from internal to public --- src/Umbraco.Core/Models/PropertyType.cs | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/src/Umbraco.Core/Models/PropertyType.cs b/src/Umbraco.Core/Models/PropertyType.cs index 55bec87bf3..026b6ffc27 100644 --- a/src/Umbraco.Core/Models/PropertyType.cs +++ b/src/Umbraco.Core/Models/PropertyType.cs @@ -13,7 +13,6 @@ namespace Umbraco.Core.Models [DataContract(IsReference = true)] public class PropertyType : Entity, IEquatable { - //private SerializationService _service; private string _name; private string _alias; private string _description; @@ -33,22 +32,12 @@ namespace Umbraco.Core.Models DataTypeId = dataTypeDefinition.ControlId; DataTypeDatabaseType = dataTypeDefinition.DatabaseType; - - EnsureSerializationService(); } internal PropertyType(Guid dataTypeControlId, DataTypeDatabaseType dataTypeDatabaseType) { DataTypeId = dataTypeControlId; DataTypeDatabaseType = dataTypeDatabaseType; - - EnsureSerializationService(); - } - - private void EnsureSerializationService() - { - /*var serviceStackSerializer = new ServiceStackXmlSerializer(); - _service = new SerializationService(serviceStackSerializer);*/ } private static readonly PropertyInfo NameSelector = ExpressionHelper.GetPropertyInfo(x => x.Name); @@ -181,6 +170,7 @@ namespace Umbraco.Core.Models /// Gets of Sets the Help text for the current PropertyType /// [DataMember] + [Obsolete("Not used anywhere in the UI")] public string HelpText { get { return _helpText; } @@ -209,7 +199,7 @@ namespace Umbraco.Core.Models /// Gets or Sets the RegEx for validation of legacy DataTypes /// [DataMember] - internal string ValidationRegExp + public string ValidationRegExp { get { return _validationRegExp; } set @@ -218,7 +208,6 @@ namespace Umbraco.Core.Models OnPropertyChanged(ValidationRegExpSelector); } } - //Note that Validation should eventually come from PropertyEditors like in v5 /// /// Create a new Property object from a "raw" database value. From b776675ac8c62ce769f9ac0eb37294600ec2b56c Mon Sep 17 00:00:00 2001 From: Morten Christensen Date: Sat, 20 Apr 2013 11:19:27 -0200 Subject: [PATCH 04/19] Fixes #U4-2065 Document.AfterMove legacy event handler returns wrong parent. --- src/umbraco.cms/businesslogic/CMSNode.cs | 1 + src/umbraco.cms/businesslogic/web/Document.cs | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/src/umbraco.cms/businesslogic/CMSNode.cs b/src/umbraco.cms/businesslogic/CMSNode.cs index 64858dce8a..1087a5b5ae 100644 --- a/src/umbraco.cms/businesslogic/CMSNode.cs +++ b/src/umbraco.cms/businesslogic/CMSNode.cs @@ -759,6 +759,7 @@ order by level,sortOrder"; public virtual int ParentId { get { return _parentid; } + internal set { _parentid = value; } } /// diff --git a/src/umbraco.cms/businesslogic/web/Document.cs b/src/umbraco.cms/businesslogic/web/Document.cs index 6b8a65ca55..c9317e81f0 100644 --- a/src/umbraco.cms/businesslogic/web/Document.cs +++ b/src/umbraco.cms/businesslogic/web/Document.cs @@ -1033,6 +1033,10 @@ namespace umbraco.cms.businesslogic.web var current = User.GetCurrent(); int userId = current == null ? 0 : current.Id; ApplicationContext.Current.Services.ContentService.Move(Content, newParentId, userId); + + //We need to manually update this property as the above change is not directly reflected in + //the current object unless its reloaded. + base.ParentId = newParentId; } base.FireAfterMove(e); From ff6715d42af753bb1eaa48217209ad57ca1ef568 Mon Sep 17 00:00:00 2001 From: Morten Christensen Date: Sat, 20 Apr 2013 11:23:04 -0200 Subject: [PATCH 05/19] Fixes #U4-2013 Localization lost in packaging for DocumentTypes --- src/umbraco.cms/businesslogic/web/DocumentType.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/umbraco.cms/businesslogic/web/DocumentType.cs b/src/umbraco.cms/businesslogic/web/DocumentType.cs index 2a5523ae21..0c07a3266c 100644 --- a/src/umbraco.cms/businesslogic/web/DocumentType.cs +++ b/src/umbraco.cms/businesslogic/web/DocumentType.cs @@ -342,11 +342,11 @@ namespace umbraco.cms.businesslogic.web // info section XmlElement info = xd.CreateElement("Info"); doc.AppendChild(info); - info.AppendChild(XmlHelper.AddTextNode(xd, "Name", Text)); + info.AppendChild(XmlHelper.AddTextNode(xd, "Name", GetRawText())); info.AppendChild(XmlHelper.AddTextNode(xd, "Alias", Alias)); info.AppendChild(XmlHelper.AddTextNode(xd, "Icon", IconUrl)); info.AppendChild(XmlHelper.AddTextNode(xd, "Thumbnail", Thumbnail)); - info.AppendChild(XmlHelper.AddTextNode(xd, "Description", Description)); + info.AppendChild(XmlHelper.AddTextNode(xd, "Description", GetRawDescription())); info.AppendChild(XmlHelper.AddTextNode(xd, "AllowAtRoot", AllowAtRoot.ToString())); //TODO: Add support for mixins! @@ -385,7 +385,7 @@ namespace umbraco.cms.businesslogic.web if (pt.ContentTypeId == this.Id) { XmlElement ptx = xd.CreateElement("GenericProperty"); - ptx.AppendChild(XmlHelper.AddTextNode(xd, "Name", pt.Name)); + ptx.AppendChild(XmlHelper.AddTextNode(xd, "Name", pt.GetRawName())); ptx.AppendChild(XmlHelper.AddTextNode(xd, "Alias", pt.Alias)); ptx.AppendChild(XmlHelper.AddTextNode(xd, "Type", pt.DataTypeDefinition.DataType.Id.ToString())); @@ -395,7 +395,7 @@ namespace umbraco.cms.businesslogic.web ptx.AppendChild(XmlHelper.AddTextNode(xd, "Tab", Tab.GetCaptionById(pt.TabId))); ptx.AppendChild(XmlHelper.AddTextNode(xd, "Mandatory", pt.Mandatory.ToString())); ptx.AppendChild(XmlHelper.AddTextNode(xd, "Validation", pt.ValidationRegExp)); - ptx.AppendChild(XmlHelper.AddCDataNode(xd, "Description", pt.Description)); + ptx.AppendChild(XmlHelper.AddCDataNode(xd, "Description", pt.GetRawDescription())); pts.AppendChild(ptx); } } From afc2fd94202b4ea4748d323be8a45e607f0ca58d Mon Sep 17 00:00:00 2001 From: Morten Christensen Date: Sat, 20 Apr 2013 12:23:14 -0200 Subject: [PATCH 06/19] Ensures that CreateDate and UpdateDate is set on both PropertyTypes and Properties for Content and Media. Fixes #U4-2028 --- .../Persistence/Factories/PropertyFactory.cs | 13 +++++++++++++ .../Persistence/Factories/PropertyGroupFactory.cs | 13 ++++++++++++- .../Persistence/Repositories/ContentRepository.cs | 6 +++--- .../Repositories/ContentTypeBaseRepository.cs | 10 ++++++---- .../Repositories/ContentTypeRepository.cs | 4 ++-- .../Persistence/Repositories/MediaRepository.cs | 8 ++++---- .../Persistence/Repositories/MediaTypeRepository.cs | 4 ++-- .../Services/Importing/PackageImportTests.cs | 5 ++--- .../umbraco/dialogs/importDocumenttype.aspx.cs | 4 +++- 9 files changed, 47 insertions(+), 20 deletions(-) diff --git a/src/Umbraco.Core/Persistence/Factories/PropertyFactory.cs b/src/Umbraco.Core/Persistence/Factories/PropertyFactory.cs index 623e770525..8b1a88126a 100644 --- a/src/Umbraco.Core/Persistence/Factories/PropertyFactory.cs +++ b/src/Umbraco.Core/Persistence/Factories/PropertyFactory.cs @@ -11,6 +11,8 @@ namespace Umbraco.Core.Persistence.Factories private readonly IContentTypeComposition _contentType; private readonly Guid _version; private readonly int _id; + private readonly DateTime _createDate; + private readonly DateTime _updateDate; public PropertyFactory(IContentTypeComposition contentType, Guid version, int id) { @@ -19,6 +21,15 @@ namespace Umbraco.Core.Persistence.Factories _id = id; } + public PropertyFactory(IContentTypeComposition contentType, Guid version, int id, DateTime createDate, DateTime updateDate) + { + _contentType = contentType; + _version = version; + _id = id; + _createDate = createDate; + _updateDate = updateDate; + } + #region Implementation of IEntityFactory public IEnumerable BuildEntity(IEnumerable dtos) @@ -34,6 +45,8 @@ namespace Umbraco.Core.Persistence.Factories propertyDataDto.VersionId.Value, propertyDataDto.Id); + property.CreateDate = _createDate; + property.UpdateDate = _updateDate; property.ResetDirtyProperties(); properties.Add(property); } diff --git a/src/Umbraco.Core/Persistence/Factories/PropertyGroupFactory.cs b/src/Umbraco.Core/Persistence/Factories/PropertyGroupFactory.cs index 3139fe5fa4..17dc7a69d9 100644 --- a/src/Umbraco.Core/Persistence/Factories/PropertyGroupFactory.cs +++ b/src/Umbraco.Core/Persistence/Factories/PropertyGroupFactory.cs @@ -9,12 +9,21 @@ namespace Umbraco.Core.Persistence.Factories internal class PropertyGroupFactory : IEntityFactory, IEnumerable> { private readonly int _id; + private readonly DateTime _createDate; + private readonly DateTime _updateDate; public PropertyGroupFactory(int id) { _id = id; } + public PropertyGroupFactory(int id, DateTime createDate, DateTime updateDate) + { + _id = id; + _createDate = createDate; + _updateDate = updateDate; + } + #region Implementation of IEntityFactory,IEnumerable> public IEnumerable BuildEntity(IEnumerable dto) @@ -58,7 +67,9 @@ namespace Umbraco.Core.Persistence.Factories Mandatory = typeDto.Mandatory, SortOrder = typeDto.SortOrder, ValidationRegExp = typeDto.ValidationRegExp, - PropertyGroupId = new Lazy(() => tempGroupDto.Id) + PropertyGroupId = new Lazy(() => tempGroupDto.Id), + CreateDate = _createDate, + UpdateDate = _updateDate }; propertyType.ResetDirtyProperties(); diff --git a/src/Umbraco.Core/Persistence/Repositories/ContentRepository.cs b/src/Umbraco.Core/Persistence/Repositories/ContentRepository.cs index 3eb7d0d3a3..8f2f7d6656 100644 --- a/src/Umbraco.Core/Persistence/Repositories/ContentRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/ContentRepository.cs @@ -437,13 +437,13 @@ namespace Umbraco.Core.Persistence.Repositories content.Template = _templateRepository.Get(dto.TemplateId.Value); } - content.Properties = GetPropertyCollection(dto.NodeId, versionId, contentType); + content.Properties = GetPropertyCollection(dto.NodeId, versionId, contentType, content.CreateDate, content.UpdateDate); ((ICanBeDirty)content).ResetDirtyProperties(); return content; } - private PropertyCollection GetPropertyCollection(int id, Guid versionId, IContentType contentType) + private PropertyCollection GetPropertyCollection(int id, Guid versionId, IContentType contentType, DateTime createDate, DateTime updateDate) { var sql = new Sql(); sql.Select("*") @@ -454,7 +454,7 @@ namespace Umbraco.Core.Persistence.Repositories .Where(x => x.VersionId == versionId); var propertyDataDtos = Database.Fetch(sql); - var propertyFactory = new PropertyFactory(contentType, versionId, id); + var propertyFactory = new PropertyFactory(contentType, versionId, id, createDate, updateDate); var properties = propertyFactory.BuildEntity(propertyDataDtos); var newProperties = properties.Where(x => x.HasIdentity == false); diff --git a/src/Umbraco.Core/Persistence/Repositories/ContentTypeBaseRepository.cs b/src/Umbraco.Core/Persistence/Repositories/ContentTypeBaseRepository.cs index 7aad681549..44254e803b 100644 --- a/src/Umbraco.Core/Persistence/Repositories/ContentTypeBaseRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/ContentTypeBaseRepository.cs @@ -312,7 +312,7 @@ namespace Umbraco.Core.Persistence.Repositories return allowedContentTypeDtos.Select(x => new ContentTypeSort { Id = new Lazy(() => x.AllowedId), SortOrder = x.SortOrder }).ToList(); } - protected PropertyGroupCollection GetPropertyGroupCollection(int id) + protected PropertyGroupCollection GetPropertyGroupCollection(int id, DateTime createDate, DateTime updateDate) { var sql = new Sql(); sql.Select("*") @@ -326,12 +326,12 @@ namespace Umbraco.Core.Persistence.Repositories var dtos = Database.Fetch(new GroupPropertyTypeRelator().Map, sql); - var propertyGroupFactory = new PropertyGroupFactory(id); + var propertyGroupFactory = new PropertyGroupFactory(id, createDate, updateDate); var propertyGroups = propertyGroupFactory.BuildEntity(dtos); return new PropertyGroupCollection(propertyGroups); } - protected PropertyTypeCollection GetPropertyTypeCollection(int id) + protected PropertyTypeCollection GetPropertyTypeCollection(int id, DateTime createDate, DateTime updateDate) { var sql = new Sql(); sql.Select("*") @@ -357,7 +357,9 @@ namespace Umbraco.Core.Persistence.Repositories HelpText = dto.HelpText, Mandatory = dto.Mandatory, SortOrder = dto.SortOrder, - ValidationRegExp = dto.ValidationRegExp + ValidationRegExp = dto.ValidationRegExp, + CreateDate = createDate, + UpdateDate = updateDate }).ToList(); //Reset dirty properties diff --git a/src/Umbraco.Core/Persistence/Repositories/ContentTypeRepository.cs b/src/Umbraco.Core/Persistence/Repositories/ContentTypeRepository.cs index c35105d13f..340d89bb38 100644 --- a/src/Umbraco.Core/Persistence/Repositories/ContentTypeRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/ContentTypeRepository.cs @@ -51,8 +51,8 @@ namespace Umbraco.Core.Persistence.Repositories var contentType = factory.BuildEntity(dto); contentType.AllowedContentTypes = GetAllowedContentTypeIds(id); - contentType.PropertyGroups = GetPropertyGroupCollection(id); - ((ContentType)contentType).PropertyTypes = GetPropertyTypeCollection(id); + contentType.PropertyGroups = GetPropertyGroupCollection(id, contentType.CreateDate, contentType.UpdateDate); + ((ContentType)contentType).PropertyTypes = GetPropertyTypeCollection(id, contentType.CreateDate, contentType.UpdateDate); var templates = Database.Fetch("WHERE contentTypeNodeId = @Id", new { Id = id }); if(templates.Any()) diff --git a/src/Umbraco.Core/Persistence/Repositories/MediaRepository.cs b/src/Umbraco.Core/Persistence/Repositories/MediaRepository.cs index 24e6f409ca..ae689325cf 100644 --- a/src/Umbraco.Core/Persistence/Repositories/MediaRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/MediaRepository.cs @@ -51,7 +51,7 @@ namespace Umbraco.Core.Persistence.Repositories var factory = new MediaFactory(mediaType, NodeObjectTypeId, id); var media = factory.BuildEntity(dto); - media.Properties = GetPropertyCollection(id, dto.VersionId, mediaType); + media.Properties = GetPropertyCollection(id, dto.VersionId, mediaType, media.CreateDate, media.UpdateDate); ((ICanBeDirty)media).ResetDirtyProperties(); return media; @@ -157,7 +157,7 @@ namespace Umbraco.Core.Persistence.Repositories var factory = new MediaFactory(mediaType, NodeObjectTypeId, dto.NodeId); var media = factory.BuildEntity(dto); - media.Properties = GetPropertyCollection(dto.NodeId, dto.VersionId, mediaType); + media.Properties = GetPropertyCollection(dto.NodeId, dto.VersionId, mediaType, media.CreateDate, media.UpdateDate); ((ICanBeDirty)media).ResetDirtyProperties(); return media; @@ -340,7 +340,7 @@ namespace Umbraco.Core.Persistence.Repositories #endregion - private PropertyCollection GetPropertyCollection(int id, Guid versionId, IMediaType contentType) + private PropertyCollection GetPropertyCollection(int id, Guid versionId, IMediaType contentType, DateTime createDate, DateTime updateDate) { var sql = new Sql(); sql.Select("*") @@ -351,7 +351,7 @@ namespace Umbraco.Core.Persistence.Repositories .Where(x => x.VersionId == versionId); var propertyDataDtos = Database.Fetch(sql); - var propertyFactory = new PropertyFactory(contentType, versionId, id); + var propertyFactory = new PropertyFactory(contentType, versionId, id, createDate, updateDate); var properties = propertyFactory.BuildEntity(propertyDataDtos); var newProperties = properties.Where(x => x.HasIdentity == false); diff --git a/src/Umbraco.Core/Persistence/Repositories/MediaTypeRepository.cs b/src/Umbraco.Core/Persistence/Repositories/MediaTypeRepository.cs index 7ea930a90e..bfb9fe09f7 100644 --- a/src/Umbraco.Core/Persistence/Repositories/MediaTypeRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/MediaTypeRepository.cs @@ -42,8 +42,8 @@ namespace Umbraco.Core.Persistence.Repositories var contentType = factory.BuildEntity(dto); contentType.AllowedContentTypes = GetAllowedContentTypeIds(id); - contentType.PropertyGroups = GetPropertyGroupCollection(id); - ((MediaType)contentType).PropertyTypes = GetPropertyTypeCollection(id); + contentType.PropertyGroups = GetPropertyGroupCollection(id, contentType.CreateDate, contentType.UpdateDate); + ((MediaType)contentType).PropertyTypes = GetPropertyTypeCollection(id, contentType.CreateDate, contentType.UpdateDate); var list = Database.Fetch("WHERE childContentTypeId = @Id", new{ Id = id}); foreach (var contentTypeDto in list) diff --git a/src/Umbraco.Tests/Services/Importing/PackageImportTests.cs b/src/Umbraco.Tests/Services/Importing/PackageImportTests.cs index f791894f92..69f6811846 100644 --- a/src/Umbraco.Tests/Services/Importing/PackageImportTests.cs +++ b/src/Umbraco.Tests/Services/Importing/PackageImportTests.cs @@ -230,11 +230,10 @@ namespace Umbraco.Tests.Services.Importing // Arrange string strXml = ImportResources.SingleDocType; var docTypeElement = XElement.Parse(strXml); - var packagingService = ServiceContext.PackagingService; // Act - var contentTypes = packagingService.ImportContentTypes(docTypeElement); - var contentTypesUpdated = packagingService.ImportContentTypes(docTypeElement); + var contentTypes = ServiceContext.PackagingService.ImportContentTypes(docTypeElement); + var contentTypesUpdated = ServiceContext.PackagingService.ImportContentTypes(docTypeElement); // Assert Assert.That(contentTypes.Any(), Is.True); diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/dialogs/importDocumenttype.aspx.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/dialogs/importDocumenttype.aspx.cs index aec5421174..23005d62d2 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/dialogs/importDocumenttype.aspx.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/dialogs/importDocumenttype.aspx.cs @@ -72,8 +72,10 @@ namespace umbraco.presentation.umbraco.dialogs var xd = new XmlDocument(); xd.Load(tempFile.Value); + var userId = base.getUser().Id; + var element = XElement.Parse(xd.InnerXml); - var importContentTypes = ApplicationContext.Current.Services.PackagingService.ImportContentTypes(element); + var importContentTypes = ApplicationContext.Current.Services.PackagingService.ImportContentTypes(element, userId); var contentType = importContentTypes.FirstOrDefault(); if (contentType != null) dtNameConfirm.Text = contentType.Name; From 082dacf7376a0be10935d77393193bb1f821ec32 Mon Sep 17 00:00:00 2001 From: Morten Christensen Date: Sat, 20 Apr 2013 12:56:43 -0200 Subject: [PATCH 07/19] Fixes #U4-2029 Finding scripts and stylesheets recursively. --- .../Persistence/Repositories/FileRepository.cs | 14 ++++++++++++++ .../Persistence/Repositories/ScriptRepository.cs | 5 ++--- .../Repositories/StylesheetRepository.cs | 5 ++--- .../umbraco/Trees/loadScripts.cs | 7 ++++++- 4 files changed, 24 insertions(+), 7 deletions(-) diff --git a/src/Umbraco.Core/Persistence/Repositories/FileRepository.cs b/src/Umbraco.Core/Persistence/Repositories/FileRepository.cs index 7cf63b33ba..d70aa9510c 100644 --- a/src/Umbraco.Core/Persistence/Repositories/FileRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/FileRepository.cs @@ -111,6 +111,20 @@ namespace Umbraco.Core.Persistence.Repositories #endregion + protected IEnumerable FindAllFiles(string path) + { + var list = new List(); + list.AddRange(FileSystem.GetFiles(path, "*")); + + var directories = FileSystem.GetDirectories(path); + foreach (var directory in directories) + { + list.AddRange(FindAllFiles(directory)); + } + + return list; + } + /// /// Dispose any disposable properties /// diff --git a/src/Umbraco.Core/Persistence/Repositories/ScriptRepository.cs b/src/Umbraco.Core/Persistence/Repositories/ScriptRepository.cs index 9c3fa7898a..0ce031cff0 100644 --- a/src/Umbraco.Core/Persistence/Repositories/ScriptRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/ScriptRepository.cs @@ -45,12 +45,11 @@ namespace Umbraco.Core.Persistence.Repositories var path = FileSystem.GetRelativePath(id); var created = FileSystem.GetCreated(path).UtcDateTime; var updated = FileSystem.GetLastModified(path).UtcDateTime; - var name = new FileInfo(path).Name; var script = new Script(path) { Content = content, - Key = name.EncodeAsGuid(), + Key = path.EncodeAsGuid(), CreateDate = created, UpdateDate = updated }; @@ -71,7 +70,7 @@ namespace Umbraco.Core.Persistence.Repositories } else { - var files = FileSystem.GetFiles("", "*"); + var files = FindAllFiles(""); foreach (var file in files) { yield return Get(file); diff --git a/src/Umbraco.Core/Persistence/Repositories/StylesheetRepository.cs b/src/Umbraco.Core/Persistence/Repositories/StylesheetRepository.cs index 4e1ca44fb8..e67524f675 100644 --- a/src/Umbraco.Core/Persistence/Repositories/StylesheetRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/StylesheetRepository.cs @@ -47,12 +47,11 @@ namespace Umbraco.Core.Persistence.Repositories var path = FileSystem.GetRelativePath(id); var created = FileSystem.GetCreated(path).UtcDateTime; var updated = FileSystem.GetLastModified(path).UtcDateTime; - var name = new FileInfo(path).Name; var stylesheet = new Stylesheet(path) { Content = content, - Key = name.EncodeAsGuid(), + Key = path.EncodeAsGuid(), CreateDate = created, UpdateDate = updated }; @@ -73,7 +72,7 @@ namespace Umbraco.Core.Persistence.Repositories } else { - var files = FileSystem.GetFiles("", "*"); + var files = FindAllFiles(""); foreach (var file in files) { yield return Get(file); diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/Trees/loadScripts.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/Trees/loadScripts.cs index 7d368bc634..6aa12bce7d 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/Trees/loadScripts.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/Trees/loadScripts.cs @@ -3,10 +3,12 @@ using System.Collections; using System.Collections.Generic; using System.Data; using System.IO; +using System.Linq; using System.Text; using System.Web; using System.Xml; using System.Configuration; +using Umbraco.Core; using umbraco.BasePages; using umbraco.BusinessLogic; using umbraco.businesslogic; @@ -52,7 +54,10 @@ namespace umbraco protected override string FilePath { - get { return SystemDirectories.Scripts + "/"; } + get + { + return SystemDirectories.Scripts + "/"; + } } protected override string FileSearchPattern From eeb0e0026a1832fee7d7bbfb2cc670bc9c7a802e Mon Sep 17 00:00:00 2001 From: Morten Christensen Date: Sat, 20 Apr 2013 19:47:30 -0200 Subject: [PATCH 08/19] Making PropertyCollection, PropertyGroupCollection and PropertyTypeCollection return a proper null when FirstOrDefault should return null. --- src/Umbraco.Core/Models/EntityBase/Entity.cs | 13 - .../Collections/PropertyCollectionTests.cs | 423 ++++++++++++++++++ src/Umbraco.Tests/Umbraco.Tests.csproj | 1 + 3 files changed, 424 insertions(+), 13 deletions(-) create mode 100644 src/Umbraco.Tests/Models/Collections/PropertyCollectionTests.cs diff --git a/src/Umbraco.Core/Models/EntityBase/Entity.cs b/src/Umbraco.Core/Models/EntityBase/Entity.cs index 8df5be5809..50d7fec194 100644 --- a/src/Umbraco.Core/Models/EntityBase/Entity.cs +++ b/src/Umbraco.Core/Models/EntityBase/Entity.cs @@ -168,19 +168,6 @@ namespace Umbraco.Core.Models.EntityBase } } - public static bool operator ==(Entity left, Entity right) - { - if (ReferenceEquals(null, left)) - return false; - - return left.Equals(right); - } - - public static bool operator !=(Entity left, Entity right) - { - return !(left == right); - } - public virtual bool SameIdentityAs(IEntity other) { if (ReferenceEquals(null, other)) diff --git a/src/Umbraco.Tests/Models/Collections/PropertyCollectionTests.cs b/src/Umbraco.Tests/Models/Collections/PropertyCollectionTests.cs new file mode 100644 index 0000000000..0699370259 --- /dev/null +++ b/src/Umbraco.Tests/Models/Collections/PropertyCollectionTests.cs @@ -0,0 +1,423 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Collections.Specialized; +using System.ComponentModel; +using System.Linq; +using System.Reflection; +using System.Runtime.Serialization; +using NUnit.Framework; +using Umbraco.Core; +using Umbraco.Core.Models; +using Umbraco.Core.Models.EntityBase; +using Umbraco.Tests.TestHelpers.Entities; + +namespace Umbraco.Tests.Models.Collections +{ + [TestFixture] + public class PropertyCollectionTests + { + [Test] + public void SimpleOrder_Returns_Null_On_FirstOrDefault_When_Empty() + { + var orders = new SimpleOrder(); + var item = orders.FirstOrDefault(); + + Assert.That(item == null, Is.True); + } + + [Test] + public void PropertyCollection_Returns_Null_On_FirstOrDefault_When_Empty() + { + var list = new List(); + var collection = new PropertyCollection(list); + + var first = collection.FirstOrDefault(); + var second = collection.FirstOrDefault(x => x.Alias.InvariantEquals("Test")); + + Assert.That(first, Is.Null); + Assert.That(first == null, Is.True); + Assert.That(second == null, Is.True); + } + + [Test] + public void PropertyTypeCollection_Returns_Null_On_FirstOrDefault_When_Empty() + { + var list = new List(); + var collection = new PropertyTypeCollection(list); + + Assert.That(collection.FirstOrDefault(), Is.Null); + Assert.That(collection.FirstOrDefault(x => x.Alias.InvariantEquals("Test")) == null, Is.True); + } + + [Test] + public void PropertyGroupCollection_Returns_Null_On_FirstOrDefault_When_Empty() + { + var list = new List(); + var collection = new PropertyGroupCollection(list); + + Assert.That(collection.FirstOrDefault(), Is.Null); + Assert.That(collection.FirstOrDefault(x => x.Name.InvariantEquals("Test")) == null, Is.True); + } + + [Test] + public void PropertyGroups_Collection_FirstOrDefault_Returns_Null() + { + var contentType = MockedContentTypes.CreateTextpageContentType(); + + Assert.That(contentType.PropertyGroups, Is.Not.Null); + Assert.That(contentType.PropertyGroups.FirstOrDefault(x => x.Name.InvariantEquals("Content")) == null, Is.False); + Assert.That(contentType.PropertyGroups.FirstOrDefault(x => x.Name.InvariantEquals("Test")) == null, Is.True); + Assert.That(contentType.PropertyGroups.Any(x => x.Name.InvariantEquals("Test")), Is.False); + } + } + + public class SimpleOrder : KeyedCollection, INotifyCollectionChanged + { + // The parameterless constructor of the base class creates a + // KeyedCollection with an internal dictionary. For this code + // example, no other constructors are exposed. + // + public SimpleOrder() : base() { } + + public SimpleOrder(IEnumerable properties) + { + Reset(properties); + } + + // This is the only method that absolutely must be overridden, + // because without it the KeyedCollection cannot extract the + // keys from the items. The input parameter type is the + // second generic type argument, in this case OrderItem, and + // the return value type is the first generic type argument, + // in this case int. + // + protected override int GetKeyForItem(OrderItem item) + { + // In this example, the key is the part number. + return item.PartNumber; + } + + internal void Reset(IEnumerable properties) + { + Clear(); + properties.ForEach(Add); + OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); + } + + protected override void SetItem(int index, OrderItem item) + { + base.SetItem(index, item); + OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item, index)); + } + + protected override void RemoveItem(int index) + { + var removed = this[index]; + base.RemoveItem(index); + OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, removed)); + } + + protected override void InsertItem(int index, OrderItem item) + { + base.InsertItem(index, item); + OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item)); + } + + protected override void ClearItems() + { + base.ClearItems(); + OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); + } + + public new bool Contains(int partNumber) + { + return this.Any(x => x.PartNumber == partNumber); + } + + public event NotifyCollectionChangedEventHandler CollectionChanged; + + protected virtual void OnCollectionChanged(NotifyCollectionChangedEventArgs args) + { + if (CollectionChanged != null) + { + CollectionChanged(this, args); + } + } + } + + public class OrderItem : Item + { + public readonly int PartNumber; + public readonly string Description; + public readonly double UnitPrice; + + private int _quantity = 0; + + public OrderItem(int partNumber, string description, + int quantity, double unitPrice) + { + this.PartNumber = partNumber; + this.Description = description; + this.Quantity = quantity; + this.UnitPrice = unitPrice; + } + + public int Quantity + { + get { return _quantity; } + set + { + if (value < 0) + throw new ArgumentException("Quantity cannot be negative."); + + _quantity = value; + } + } + + public override string ToString() + { + return String.Format( + "{0,9} {1,6} {2,-12} at {3,8:#,###.00} = {4,10:###,###.00}", + PartNumber, _quantity, Description, UnitPrice, + UnitPrice * _quantity); + } + } + + public abstract class Item : IEntity, ICanBeDirty + { + private bool _hasIdentity; + private int? _hash; + private int _id; + private Guid _key; + + protected Item() + { + _propertyChangedInfo = new Dictionary(); + } + + /// + /// Integer Id + /// + [DataMember] + public int Id + { + get + { + return _id; + } + set + { + _id = value; + HasIdentity = true; + } + } + + /// + /// Guid based Id + /// + /// The key is currectly used to store the Unique Id from the + /// umbracoNode table, which many of the entities are based on. + [DataMember] + public Guid Key + { + get + { + if (_key == Guid.Empty) + return _id.ToGuid(); + + return _key; + } + set { _key = value; } + } + + /// + /// Gets or sets the Created Date + /// + [DataMember] + public DateTime CreateDate { get; set; } + + /// + /// Gets or sets the Modified Date + /// + [DataMember] + public DateTime UpdateDate { get; set; } + + /// + /// Gets or sets the WasCancelled flag, which is used to track + /// whether some action against an entity was cancelled through some event. + /// This only exists so we have a way to check if an event was cancelled through + /// the new api, which also needs to take effect in the legacy api. + /// + [IgnoreDataMember] + internal bool WasCancelled { get; set; } + + /// + /// Property changed event + /// + public event PropertyChangedEventHandler PropertyChanged; + + /// + /// Method to call on a property setter. + /// + /// The property info. + protected virtual void OnPropertyChanged(PropertyInfo propertyInfo) + { + _propertyChangedInfo[propertyInfo.Name] = true; + + if (PropertyChanged != null) + { + PropertyChanged(this, new PropertyChangedEventArgs(propertyInfo.Name)); + } + } + + internal virtual void ResetIdentity() + { + _hasIdentity = false; + _id = default(int); + } + + /// + /// Method to call on entity saved when first added + /// + internal virtual void AddingEntity() + { + CreateDate = DateTime.Now; + UpdateDate = DateTime.Now; + } + + /// + /// Method to call on entity saved/updated + /// + internal virtual void UpdatingEntity() + { + UpdateDate = DateTime.Now; + } + + /// + /// Tracks the properties that have changed + /// + //private readonly IDictionary _propertyChangedInfo = new Dictionary(); + private IDictionary _propertyChangedInfo; + + /// + /// Indicates whether a specific property on the current entity is dirty. + /// + /// Name of the property to check + /// True if Property is dirty, otherwise False + public virtual bool IsPropertyDirty(string propertyName) + { + return _propertyChangedInfo.Any(x => x.Key == propertyName); + } + + /// + /// Indicates whether the current entity is dirty. + /// + /// True if entity is dirty, otherwise False + public virtual bool IsDirty() + { + return _propertyChangedInfo.Any(); + } + + /// + /// Resets dirty properties by clearing the dictionary used to track changes. + /// + /// + /// Please note that resetting the dirty properties could potentially + /// obstruct the saving of a new or updated entity. + /// + public virtual void ResetDirtyProperties() + { + _propertyChangedInfo.Clear(); + } + + /// + /// Indicates whether the current entity has an identity, eg. Id. + /// + public virtual bool HasIdentity + { + get + { + return _hasIdentity; + } + protected set + { + _hasIdentity = value; + } + } + + public static bool operator ==(Item left, Item right) + { + /*if (ReferenceEquals(null, left)) + return false; + + if(ReferenceEquals(null, right)) + return false;*/ + + return ReferenceEquals(left, right); + + return left.Equals(right); + } + + public static bool operator !=(Item left, Item right) + { + return !(left == right); + } + + /*public virtual bool SameIdentityAs(IEntity other) + { + if (ReferenceEquals(null, other)) + return false; + if (ReferenceEquals(this, other)) + return true; + + return SameIdentityAs(other as Entity); + } + + public virtual bool Equals(Entity other) + { + if (ReferenceEquals(null, other)) + return false; + if (ReferenceEquals(this, other)) + return true; + + return SameIdentityAs(other); + } + + public virtual Type GetRealType() + { + return GetType(); + } + + public virtual bool SameIdentityAs(Entity other) + { + if (ReferenceEquals(null, other)) + return false; + + if (ReferenceEquals(this, other)) + return true; + + if (GetType() == other.GetRealType() && HasIdentity && other.HasIdentity) + return other.Id.Equals(Id); + + return false; + } + + public override bool Equals(object obj) + { + if (ReferenceEquals(null, obj)) + return false; + if (ReferenceEquals(this, obj)) + return true; + + return SameIdentityAs(obj as IEntity); + } + + public override int GetHashCode() + { + if (!_hash.HasValue) + _hash = !HasIdentity ? new int?(base.GetHashCode()) : new int?(Id.GetHashCode() * 397 ^ GetType().GetHashCode()); + return _hash.Value; + }*/ + } +} \ No newline at end of file diff --git a/src/Umbraco.Tests/Umbraco.Tests.csproj b/src/Umbraco.Tests/Umbraco.Tests.csproj index 27a18bd83a..150f3f78f2 100644 --- a/src/Umbraco.Tests/Umbraco.Tests.csproj +++ b/src/Umbraco.Tests/Umbraco.Tests.csproj @@ -178,6 +178,7 @@ + From f758b33da5ee0e8d980c4c44150de6dc2b276ba2 Mon Sep 17 00:00:00 2001 From: Morten Christensen Date: Sun, 21 Apr 2013 07:25:38 -0200 Subject: [PATCH 09/19] Properly fixes #U4-2112 and adds option to determine whether or not to import doc type structues. --- src/Umbraco.Core/Services/PackagingService.cs | 45 ++++++++++++------- .../businesslogic/Packager/Installer.cs | 2 +- 2 files changed, 31 insertions(+), 16 deletions(-) diff --git a/src/Umbraco.Core/Services/PackagingService.cs b/src/Umbraco.Core/Services/PackagingService.cs index ccfe885adf..36766382dc 100644 --- a/src/Umbraco.Core/Services/PackagingService.cs +++ b/src/Umbraco.Core/Services/PackagingService.cs @@ -196,9 +196,21 @@ namespace Umbraco.Core.Services /// Imports and saves package xml as /// /// Xml to import - /// + /// Optional id of the User performing the operation. Default is zero (admin). /// An enumrable list of generated ContentTypes public IEnumerable ImportContentTypes(XElement element, int userId = 0) + { + return ImportContentTypes(element, true, userId); + } + + /// + /// Imports and saves package xml as + /// + /// Xml to import + /// Boolean indicating whether or not to import the + /// Optional id of the User performing the operation. Default is zero (admin). + /// An enumrable list of generated ContentTypes + public IEnumerable ImportContentTypes(XElement element, bool importStructure, int userId = 0) { var name = element.Name.LocalName; if (name.Equals("DocumentTypes") == false && name.Equals("DocumentType") == false) @@ -227,22 +239,25 @@ namespace Umbraco.Core.Services var list = _importedContentTypes.Select(x => x.Value).ToList(); _contentTypeService.Save(list, userId); - var updatedContentTypes = new List(); - //Update the structure here - we can't do it untill all DocTypes have been created - foreach (var documentType in documentTypes) + if (importStructure) { - var alias = documentType.Element("Info").Element("Alias").Value; - var structureElement = documentType.Element("Structure"); - //Ensure that we only update ContentTypes which has actual structure-elements - if (structureElement == null || structureElement.Elements("DocumentType").Any() == false) continue; + var updatedContentTypes = new List(); + //Update the structure here - we can't do it untill all DocTypes have been created + foreach (var documentType in documentTypes) + { + var alias = documentType.Element("Info").Element("Alias").Value; + var structureElement = documentType.Element("Structure"); + //Ensure that we only update ContentTypes which has actual structure-elements + if (structureElement == null || structureElement.Elements("DocumentType").Any() == false) continue; - var updated = UpdateContentTypesStructure(_importedContentTypes[alias], structureElement); - updatedContentTypes.Add(updated); + var updated = UpdateContentTypesStructure(_importedContentTypes[alias], structureElement); + updatedContentTypes.Add(updated); + } + //Update ContentTypes with a newly added structure/list of allowed children + if (updatedContentTypes.Any()) + _contentTypeService.Save(updatedContentTypes, userId); } - //Update ContentTypes with a newly added structure/list of allowed children - if(updatedContentTypes.Any()) - _contentTypeService.Save(updatedContentTypes, userId); - + return list; } @@ -423,7 +438,7 @@ namespace Umbraco.Core.Services if (_importedContentTypes.ContainsKey(alias)) { var allowedChild = _importedContentTypes[alias]; - if(allowedChild == null || allowedChildren.Any(x => x.Alias == alias)) continue; + if (allowedChild == null || allowedChildren.Any(x => x.Id.IsValueCreated && x.Id.Value == allowedChild.Id)) continue; allowedChildren.Add(new ContentTypeSort(new Lazy(() => allowedChild.Id), sortOrder, allowedChild.Alias)); sortOrder++; diff --git a/src/umbraco.cms/businesslogic/Packager/Installer.cs b/src/umbraco.cms/businesslogic/Packager/Installer.cs index a3d8618a57..c890dbe6d7 100644 --- a/src/umbraco.cms/businesslogic/Packager/Installer.cs +++ b/src/umbraco.cms/businesslogic/Packager/Installer.cs @@ -936,7 +936,7 @@ namespace umbraco.cms.businesslogic.packager public static void ImportDocumentType(XmlNode n, User u, bool ImportStructure) { var element = n.GetXElement(); - var contentTypes = ApplicationContext.Current.Services.PackagingService.ImportContentTypes(element, u.Id); + var contentTypes = ApplicationContext.Current.Services.PackagingService.ImportContentTypes(element, ImportStructure, u.Id); } #endregion From 222723b8fe88c45891bc2c7c84ad90f0e04a27d4 Mon Sep 17 00:00:00 2001 From: Morten Christensen Date: Sun, 21 Apr 2013 09:06:22 -0200 Subject: [PATCH 10/19] Fixes #U4-2004 so GetPublishedDescendants retrieves the published version and not the latest version. --- .../Repositories/ContentRepository.cs | 18 ++++++++ .../Interfaces/IContentRepository.cs | 11 ++++- src/Umbraco.Core/Services/ContentService.cs | 4 +- .../Services/ContentServiceTests.cs | 44 +++++++++++++++++++ 4 files changed, 74 insertions(+), 3 deletions(-) diff --git a/src/Umbraco.Core/Persistence/Repositories/ContentRepository.cs b/src/Umbraco.Core/Persistence/Repositories/ContentRepository.cs index 8f2f7d6656..5d25ed2504 100644 --- a/src/Umbraco.Core/Persistence/Repositories/ContentRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/ContentRepository.cs @@ -401,6 +401,24 @@ namespace Umbraco.Core.Persistence.Repositories #region Implementation of IContentRepository + public IEnumerable GetByPublishedVersion(IQuery query) + { + var sqlClause = GetBaseQuery(false); + var translator = new SqlTranslator(sqlClause, query); + var sql = translator.Translate() + .Where(x => x.Published) + .OrderByDescending(x => x.VersionDate) + .OrderBy(x => x.SortOrder); + + //NOTE: This doesn't allow properties to be part of the query + var dtos = Database.Fetch(sql); + + foreach (var dto in dtos) + { + yield return CreateContentFromDto(dto, dto.VersionId); + } + } + public IContent GetByLanguage(int id, string language) { var sql = GetBaseQuery(false); diff --git a/src/Umbraco.Core/Persistence/Repositories/Interfaces/IContentRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Interfaces/IContentRepository.cs index 55c2c7b682..8453bcd6da 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Interfaces/IContentRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Interfaces/IContentRepository.cs @@ -1,4 +1,6 @@ -using Umbraco.Core.Models; +using System.Collections.Generic; +using Umbraco.Core.Models; +using Umbraco.Core.Persistence.Querying; namespace Umbraco.Core.Persistence.Repositories { @@ -11,5 +13,12 @@ namespace Umbraco.Core.Persistence.Repositories /// Culture code for the language to retrieve /// An item IContent GetByLanguage(int id, string language); + + /// + /// Gets all published Content byh the specified query + /// + /// Query to execute against published versions + /// An enumerable list of + IEnumerable GetByPublishedVersion(IQuery query); } } \ No newline at end of file diff --git a/src/Umbraco.Core/Services/ContentService.cs b/src/Umbraco.Core/Services/ContentService.cs index 0813cbd694..3fd486b477 100644 --- a/src/Umbraco.Core/Services/ContentService.cs +++ b/src/Umbraco.Core/Services/ContentService.cs @@ -1070,8 +1070,8 @@ namespace Umbraco.Core.Services { using (var repository = _repositoryFactory.CreateContentRepository(_uowProvider.GetUnitOfWork())) { - var query = Query.Builder.Where(x => x.Id != content.Id && x.Path.StartsWith(content.Path) && x.Published == true && x.Trashed == false); - var contents = repository.GetByQuery(query); + var query = Query.Builder.Where(x => x.Id != content.Id && x.Path.StartsWith(content.Path) && x.Trashed == false); + var contents = repository.GetByPublishedVersion(query); return contents; } diff --git a/src/Umbraco.Tests/Services/ContentServiceTests.cs b/src/Umbraco.Tests/Services/ContentServiceTests.cs index ba94145af2..ed7d22dd31 100644 --- a/src/Umbraco.Tests/Services/ContentServiceTests.cs +++ b/src/Umbraco.Tests/Services/ContentServiceTests.cs @@ -468,6 +468,50 @@ namespace Umbraco.Tests.Services Assert.That(published, Is.True); } + [Test] + public void Can_Get_Published_Descendant_Versions() + { + // Arrange + var contentService = ServiceContext.ContentService; + var root = contentService.GetById(1046); + var rootPublished = contentService.Publish(root); + var content = contentService.GetById(1048); + content.Properties["title"].Value = content.Properties["title"].Value + " Published"; + bool published = contentService.SaveAndPublish(content); + + var publishedVersion = content.Version; + + content.Properties["title"].Value = content.Properties["title"].Value + " Saved"; + contentService.Save(content); + + var savedVersion = content.Version; + + // Act + var publishedDescendants = ((ContentService) contentService).GetPublishedDescendants(root); + + // Assert + Assert.That(rootPublished, Is.True); + Assert.That(published, Is.True); + Assert.That(publishedDescendants.Any(x => x.Version == publishedVersion), Is.True); + Assert.That(publishedDescendants.Any(x => x.Version == savedVersion), Is.False); + + //Ensure that the published content version has the correct property value and is marked as published + var publishedContentVersion = publishedDescendants.First(x => x.Version == publishedVersion); + Assert.That(publishedContentVersion.Published, Is.True); + Assert.That(publishedContentVersion.Properties["title"].Value, Contains.Substring("Published")); + + //Ensure that the saved content version has the correct property value and is not marked as published + var savedContentVersion = contentService.GetByVersion(savedVersion); + Assert.That(savedContentVersion.Published, Is.False); + Assert.That(savedContentVersion.Properties["title"].Value, Contains.Substring("Saved")); + + //Ensure that the latest version of the content is the saved and not-yet-published one + var currentContent = contentService.GetById(1048); + Assert.That(currentContent.Published, Is.False); + Assert.That(currentContent.Properties["title"].Value, Contains.Substring("Saved")); + Assert.That(currentContent.Version, Is.EqualTo(savedVersion)); + } + [Test] public void Can_Save_Content() { From b99de245bf8937b5132bc87f402ea72208118536 Mon Sep 17 00:00:00 2001 From: Sebastiaan Janssen Date: Sun, 21 Apr 2013 09:44:08 -0200 Subject: [PATCH 11/19] Fixes U4-2052 for new mediatypes as well --- .../umbraco/create/MediaTypeTasks.cs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/create/MediaTypeTasks.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/create/MediaTypeTasks.cs index 269215d8fc..08b35b4c26 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/create/MediaTypeTasks.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/create/MediaTypeTasks.cs @@ -1,6 +1,7 @@ using System; using System.Data; using System.Web.Security; +using Umbraco.Core; using umbraco.BusinessLogic; using umbraco.DataLayer; using umbraco.BasePages; @@ -41,9 +42,11 @@ namespace umbraco } public bool Save() - { - int id = cms.businesslogic.media.MediaType.MakeNew(BusinessLogic.User.GetUser(_userID), Alias.Replace("'", "''")).Id; - m_returnUrl = string.Format("settings/editMediaType.aspx?id={0}", id); + { + var mediaType = cms.businesslogic.media.MediaType.MakeNew(User.GetUser(_userID), Alias.Replace("'", "''")); + mediaType.IconUrl = UmbracoSettings.IconPickerBehaviour == IconPickerBehaviour.HideFileDuplicates ? ".sprTreeFolder" : "folder.gif"; + + m_returnUrl = string.Format("settings/editMediaType.aspx?id={0}", mediaType.Id); return true; } From c5734596261e68e0e695d6895de6848e22e8b552 Mon Sep 17 00:00:00 2001 From: Morten Christensen Date: Mon, 22 Apr 2013 06:01:31 -0200 Subject: [PATCH 12/19] Fixing nuget related issue #U4-2067 and updating version --- build/Build.bat | 2 +- .../Configuration/UmbracoVersion.cs | 2 +- src/Umbraco.Web.UI/Umbraco.Web.UI.csproj | 1 + src/Umbraco.Web.UI/Views/Web.config.transform | 55 +++++++++++++++++++ 4 files changed, 58 insertions(+), 2 deletions(-) create mode 100644 src/Umbraco.Web.UI/Views/Web.config.transform diff --git a/build/Build.bat b/build/Build.bat index 66f0c7e3b9..28b98d9e59 100644 --- a/build/Build.bat +++ b/build/Build.bat @@ -1,5 +1,5 @@ @ECHO OFF -SET release=6.0.3 +SET release=6.0.4 SET comment= SET version=%release% diff --git a/src/Umbraco.Core/Configuration/UmbracoVersion.cs b/src/Umbraco.Core/Configuration/UmbracoVersion.cs index 583e1097bf..dcd3bb8444 100644 --- a/src/Umbraco.Core/Configuration/UmbracoVersion.cs +++ b/src/Umbraco.Core/Configuration/UmbracoVersion.cs @@ -5,7 +5,7 @@ namespace Umbraco.Core.Configuration { public class UmbracoVersion { - private static readonly Version Version = new Version("6.0.3"); + private static readonly Version Version = new Version("6.0.4"); /// /// Gets the current version of Umbraco. diff --git a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj index 8f7ffa2ed5..7d65212987 100644 --- a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj +++ b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj @@ -1902,6 +1902,7 @@ Designer + Web.Template.config Designer diff --git a/src/Umbraco.Web.UI/Views/Web.config.transform b/src/Umbraco.Web.UI/Views/Web.config.transform new file mode 100644 index 0000000000..f8333ed8ea --- /dev/null +++ b/src/Umbraco.Web.UI/Views/Web.config.transform @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 3594693f4b6ee3ae0e61961128ece57c981129ae Mon Sep 17 00:00:00 2001 From: agrath Date: Mon, 22 Apr 2013 11:12:03 -1200 Subject: [PATCH 13/19] Backported fix for u4-335 from Commit b15d0ab0b879 into 4.11.7 --- .../imagecropper/ImageManipulation.cs | 138 +++--------------- 1 file changed, 20 insertions(+), 118 deletions(-) diff --git a/src/umbraco.editorControls/imagecropper/ImageManipulation.cs b/src/umbraco.editorControls/imagecropper/ImageManipulation.cs index 3536b3a037..e9d67645b8 100644 --- a/src/umbraco.editorControls/imagecropper/ImageManipulation.cs +++ b/src/umbraco.editorControls/imagecropper/ImageManipulation.cs @@ -19,7 +19,7 @@ namespace umbraco.editorControls.imagecropper byte[] buffer = null; - using(FileStream fs = new FileStream(sourceFile, FileMode.Open, FileAccess.Read)) + using (FileStream fs = new FileStream(sourceFile, FileMode.Open, FileAccess.Read)) { buffer = new byte[fs.Length]; fs.Read(buffer, 0, (int)fs.Length); @@ -31,62 +31,25 @@ namespace umbraco.editorControls.imagecropper DirectoryInfo di = new DirectoryInfo(path); if (!di.Exists) di.Create(); - using(Image croppedImage = cropImage(image, new Rectangle(cropX, cropY, cropWidth, cropHeight))) + using (Image croppedImage = CropImage(image, new Rectangle(cropX, cropY, cropWidth, cropHeight))) { - using(Image resizedImage = resizeImage(croppedImage, new Size(sizeWidth, sizeHeight))) + using (Image resizedImage = ResizeImage(croppedImage, new Size(sizeWidth, sizeHeight))) { using (Bitmap b = new Bitmap(resizedImage)) { - saveJpeg(String.Format("{0}/{1}.jpg", path, name), b, quality); + SaveJpeg(String.Format("{0}/{1}.jpg", path, name), b, quality); } } } - - - //saveJpeg( - // String.Format("{0}/{1}.jpg", path, name), - // new Bitmap( - // resizeImage(cropImage(image, new Rectangle(cropX, cropY, cropWidth, cropHeight)), new Size(sizeWidth, sizeHeight))), - // quality - // ); - - //using (FileStream stm = new FileStream(sourceFile, FileMode.Open, FileAccess.Read)) - //{ - //using (Image image = Image.FromStream(stm)) - //{ - - //} - //stm.Close(); - //} - - - //using (Image image = Image.FromFile(sourceFile)) - //{ - // //image = cropImage(image, new Rectangle(cropX, cropY, cropWidth, cropHeight)); - // //cropImage(image, new Rectangle(cropX, cropY, cropWidth, cropHeight)); - // //image = resizeImage(image, new Size(sizeWidth, sizeHeight)); - // //resizeImage(image, new Size(sizeWidth, sizeHeight)); - // string path = sourceFile.Substring(0, sourceFile.LastIndexOf('\\') + 1) + "Crops"; - // DirectoryInfo di = new DirectoryInfo(path); - // if (!di.Exists) di.Create(); - // saveJpeg( - // String.Format("{0}/{1}.jpg", path, name), - // new Bitmap( - // resizeImage(cropImage(image, new Rectangle(cropX, cropY, cropWidth, cropHeight)), new Size(sizeWidth, sizeHeight))), - // quality - // ); - - // image.Dispose(); - //} } - private static void saveJpeg(string path, Bitmap img, long quality) + private static void SaveJpeg(string path, Bitmap img, long quality) { // Encoder parameter for image quality EncoderParameter qualityParam = new EncoderParameter(Encoder.Quality, quality); // Jpeg image codec - ImageCodecInfo jpegCodec = getEncoderInfo("image/jpeg"); + ImageCodecInfo jpegCodec = GetEncoderInfo("image/jpeg"); if (jpegCodec == null) return; @@ -97,7 +60,7 @@ namespace umbraco.editorControls.imagecropper img.Save(path, jpegCodec, encoderParams); } - private static ImageCodecInfo getEncoderInfo(string mimeType) + private static ImageCodecInfo GetEncoderInfo(string mimeType) { // Get image codecs for all image formats ImageCodecInfo[] codecs = ImageCodecInfo.GetImageEncoders(); @@ -109,39 +72,22 @@ namespace umbraco.editorControls.imagecropper return null; } - private static Image cropImage(Image img, Rectangle cropArea) + private static Image CropImage(Image img, Rectangle cropArea) { - Bitmap bmpImage = new Bitmap(img); - Bitmap bmpCrop = bmpImage.Clone(cropArea, bmpImage.PixelFormat); - return (Image)(bmpCrop); + var bmpImage = new Bitmap(img); + + if (cropArea.Right > img.Width) + cropArea.Width -= (cropArea.Right - img.Width); + + if (cropArea.Bottom > img.Height) + cropArea.Height -= (cropArea.Bottom - img.Height); + + var bmpCrop = bmpImage.Clone(cropArea, bmpImage.PixelFormat); + return bmpCrop; } - private static Image resizeImage(Image imgToResize, Size size) + private static Image ResizeImage(Image imgToResize, Size size) { - //int sourceWidth = imgToResize.Width; - //int sourceHeight = imgToResize.Height; - - //float nPercent = 0; - //float nPercentW = 0; - //float nPercentH = 0; - - //nPercentW = ((float)size.Width / (float)sourceWidth); - //nPercentH = ((float)size.Height / (float)sourceHeight); - - //if (nPercentH < nPercentW) - // nPercent = nPercentH; - //else - // nPercent = nPercentW; - - //int destWidth = (int)(sourceWidth * nPercent); - //int destHeight = (int)(sourceHeight * nPercent); - - - - - - - int destWidth = size.Width; int destHeight = size.Height; @@ -158,55 +104,11 @@ namespace umbraco.editorControls.imagecropper g.SmoothingMode = SmoothingMode.HighQuality; g.DrawImage(imgToResize, new Rectangle(0, 0, destWidth, destHeight), 0, 0, imgToResize.Width, imgToResize.Height, GraphicsUnit.Pixel, ia); - + ia.Dispose(); g.Dispose(); return b; - - - - - -#if false - - int destWidth = size.Width; - int destHeight = size.Height; - - using (Bitmap b = new Bitmap(destWidth, destHeight)) - { - using (Graphics g = Graphics.FromImage(b)) - { - g.PixelOffsetMode = PixelOffsetMode.HighQuality; - using (ImageAttributes ia = new ImageAttributes()) - { - ia.SetWrapMode(WrapMode.TileFlipXY); - g.Clear(Color.White); - g.InterpolationMode = InterpolationMode.HighQualityBicubic; - g.CompositingQuality = CompositingQuality.HighQuality; - g.SmoothingMode = SmoothingMode.HighQuality; - g.DrawImage(imgToResize, new Rectangle(0, 0, destWidth, destHeight), 0, 0, imgToResize.Width, - imgToResize.Height, GraphicsUnit.Pixel, ia); - } - } - return b; - } - -#endif - -#if false - int destWidth = size.Width; - int destHeight = size.Height; - - Bitmap b = new Bitmap(destWidth, destHeight); - Graphics g = Graphics.FromImage((Image)b); - g.InterpolationMode = InterpolationMode.HighQualityBicubic; - - g.DrawImage(imgToResize, 0, 0, destWidth, destHeight); - g.Dispose(); - - return (Image)b; -#endif } } } \ No newline at end of file From aa84a3f7f276cbf6f6049efe5f7567e418fdcefe Mon Sep 17 00:00:00 2001 From: Sebastiaan Janssen Date: Tue, 23 Apr 2013 12:49:33 -0200 Subject: [PATCH 14/19] Fixes U4-2138 Copying a node reverses sort order in target --- src/Umbraco.Core/Services/ContentService.cs | 1204 +++++++++---------- 1 file changed, 602 insertions(+), 602 deletions(-) diff --git a/src/Umbraco.Core/Services/ContentService.cs b/src/Umbraco.Core/Services/ContentService.cs index 3fd486b477..1254bb295c 100644 --- a/src/Umbraco.Core/Services/ContentService.cs +++ b/src/Umbraco.Core/Services/ContentService.cs @@ -19,25 +19,25 @@ using Umbraco.Core.Publishing; namespace Umbraco.Core.Services { - /// - /// Represents the Content Service, which is an easy access to operations involving - /// - public class ContentService : IContentService - { - private readonly IDatabaseUnitOfWorkProvider _uowProvider; - private readonly IPublishingStrategy _publishingStrategy; + /// + /// Represents the Content Service, which is an easy access to operations involving + /// + public class ContentService : IContentService + { + private readonly IDatabaseUnitOfWorkProvider _uowProvider; + private readonly IPublishingStrategy _publishingStrategy; private readonly RepositoryFactory _repositoryFactory; //Support recursive locks because some of the methods that require locking call other methods that require locking. //for example, the Move method needs to be locked but this calls the Save method which also needs to be locked. - private static readonly ReaderWriterLockSlim Locker = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion); + private static readonly ReaderWriterLockSlim Locker = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion); public ContentService() : this(new RepositoryFactory()) - {} + { } public ContentService(RepositoryFactory repositoryFactory) : this(new PetaPocoUnitOfWorkProvider(), repositoryFactory, new PublishingStrategy()) - {} + { } public ContentService(IDatabaseUnitOfWorkProvider provider) : this(provider, new RepositoryFactory(), new PublishingStrategy()) @@ -47,42 +47,42 @@ namespace Umbraco.Core.Services : this(provider, repositoryFactory, new PublishingStrategy()) { } - public ContentService(IDatabaseUnitOfWorkProvider provider, RepositoryFactory repositoryFactory, IPublishingStrategy publishingStrategy) - { - _uowProvider = provider; - _publishingStrategy = publishingStrategy; + public ContentService(IDatabaseUnitOfWorkProvider provider, RepositoryFactory repositoryFactory, IPublishingStrategy publishingStrategy) + { + _uowProvider = provider; + _publishingStrategy = publishingStrategy; _repositoryFactory = repositoryFactory; - } + } - /// - /// Creates an object using the alias of the - /// that this Content is based on. - /// + /// + /// Creates an object using the alias of the + /// that this Content is based on. + /// /// Name of the Content object - /// Id of Parent for the new Content - /// Alias of the - /// Optional id of the user creating the content - /// - public IContent CreateContent(string name, int parentId, string contentTypeAlias, int userId = 0) - { - var contentType = FindContentTypeByAlias(contentTypeAlias); + /// Id of Parent for the new Content + /// Alias of the + /// Optional id of the user creating the content + /// + public IContent CreateContent(string name, int parentId, string contentTypeAlias, int userId = 0) + { + var contentType = FindContentTypeByAlias(contentTypeAlias); var content = new Content(name, parentId, contentType); ; - if (Creating.IsRaisedEventCancelled(new NewEventArgs(content, contentTypeAlias, parentId), this)) - { - content.WasCancelled = true; - return content; - } + if (Creating.IsRaisedEventCancelled(new NewEventArgs(content, contentTypeAlias, parentId), this)) + { + content.WasCancelled = true; + return content; + } - content.CreatorId = userId; - content.WriterId = userId; + content.CreatorId = userId; + content.WriterId = userId; - Created.RaiseEvent(new NewEventArgs(content, false, contentTypeAlias, parentId), this); + Created.RaiseEvent(new NewEventArgs(content, false, contentTypeAlias, parentId), this); - Audit.Add(AuditTypes.New, "", content.CreatorId, content.Id); + Audit.Add(AuditTypes.New, "", content.CreatorId, content.Id); - return content; - } + return content; + } /// /// Creates an object using the alias of the @@ -114,65 +114,65 @@ namespace Umbraco.Core.Services return content; } - /// - /// Gets an object by Id - /// - /// Id of the Content to retrieve - /// - public IContent GetById(int id) - { - using (var repository = _repositoryFactory.CreateContentRepository(_uowProvider.GetUnitOfWork())) - { - return repository.Get(id); - } - } + /// + /// Gets an object by Id + /// + /// Id of the Content to retrieve + /// + public IContent GetById(int id) + { + using (var repository = _repositoryFactory.CreateContentRepository(_uowProvider.GetUnitOfWork())) + { + return repository.Get(id); + } + } - /// - /// Gets an object by its 'UniqueId' - /// - /// Guid key of the Content to retrieve - /// - public IContent GetById(Guid key) - { - using (var repository = _repositoryFactory.CreateContentRepository(_uowProvider.GetUnitOfWork())) - { - var query = Query.Builder.Where(x => x.Key == key); - var contents = repository.GetByQuery(query); - return contents.SingleOrDefault(); - } - } + /// + /// Gets an object by its 'UniqueId' + /// + /// Guid key of the Content to retrieve + /// + public IContent GetById(Guid key) + { + using (var repository = _repositoryFactory.CreateContentRepository(_uowProvider.GetUnitOfWork())) + { + var query = Query.Builder.Where(x => x.Key == key); + var contents = repository.GetByQuery(query); + return contents.SingleOrDefault(); + } + } - /// - /// Gets a collection of objects by the Id of the - /// - /// Id of the - /// An Enumerable list of objects - public IEnumerable GetContentOfContentType(int id) - { - using (var repository = _repositoryFactory.CreateContentRepository(_uowProvider.GetUnitOfWork())) - { - var query = Query.Builder.Where(x => x.ContentTypeId == id); - var contents = repository.GetByQuery(query); + /// + /// Gets a collection of objects by the Id of the + /// + /// Id of the + /// An Enumerable list of objects + public IEnumerable GetContentOfContentType(int id) + { + using (var repository = _repositoryFactory.CreateContentRepository(_uowProvider.GetUnitOfWork())) + { + var query = Query.Builder.Where(x => x.ContentTypeId == id); + var contents = repository.GetByQuery(query); - return contents; - } - } + return contents; + } + } - /// - /// Gets a collection of objects by Level - /// - /// The level to retrieve Content from - /// An Enumerable list of objects - public IEnumerable GetByLevel(int level) - { - using (var repository = _repositoryFactory.CreateContentRepository(_uowProvider.GetUnitOfWork())) - { + /// + /// Gets a collection of objects by Level + /// + /// The level to retrieve Content from + /// An Enumerable list of objects + public IEnumerable GetByLevel(int level) + { + using (var repository = _repositoryFactory.CreateContentRepository(_uowProvider.GetUnitOfWork())) + { var query = Query.Builder.Where(x => x.Level == level && !x.Path.StartsWith("-20")); - var contents = repository.GetByQuery(query); + var contents = repository.GetByQuery(query); - return contents; - } - } + return contents; + } + } /// /// Gets a specific version of an item. @@ -201,21 +201,21 @@ namespace Umbraco.Core.Services } } - /// - /// Gets a collection of objects by Parent Id - /// - /// Id of the Parent to retrieve Children from - /// An Enumerable list of objects - public IEnumerable GetChildren(int id) - { - using (var repository = _repositoryFactory.CreateContentRepository(_uowProvider.GetUnitOfWork())) - { - var query = Query.Builder.Where(x => x.ParentId == id); - var contents = repository.GetByQuery(query); + /// + /// Gets a collection of objects by Parent Id + /// + /// Id of the Parent to retrieve Children from + /// An Enumerable list of objects + public IEnumerable GetChildren(int id) + { + using (var repository = _repositoryFactory.CreateContentRepository(_uowProvider.GetUnitOfWork())) + { + var query = Query.Builder.Where(x => x.ParentId == id); + var contents = repository.GetByQuery(query); - return contents; - } - } + return contents; + } + } /// /// Gets a collection of objects by its name or partial name @@ -272,65 +272,65 @@ namespace Umbraco.Core.Services return version.FirstOrDefault(x => x.Published == true); } - /// - /// Gets a collection of objects, which reside at the first level / root - /// - /// An Enumerable list of objects - public IEnumerable GetRootContent() - { - using (var repository = _repositoryFactory.CreateContentRepository(_uowProvider.GetUnitOfWork())) - { - var query = Query.Builder.Where(x => x.ParentId == -1); - var contents = repository.GetByQuery(query); + /// + /// Gets a collection of objects, which reside at the first level / root + /// + /// An Enumerable list of objects + public IEnumerable GetRootContent() + { + using (var repository = _repositoryFactory.CreateContentRepository(_uowProvider.GetUnitOfWork())) + { + var query = Query.Builder.Where(x => x.ParentId == -1); + var contents = repository.GetByQuery(query); - return contents; - } - } + return contents; + } + } - /// - /// Gets a collection of objects, which has an expiration date less than or equal to today. - /// - /// An Enumerable list of objects - public IEnumerable GetContentForExpiration() - { - using (var repository = _repositoryFactory.CreateContentRepository(_uowProvider.GetUnitOfWork())) - { - var query = Query.Builder.Where(x => x.Published == true && x.ExpireDate <= DateTime.Now); - var contents = repository.GetByQuery(query); + /// + /// Gets a collection of objects, which has an expiration date less than or equal to today. + /// + /// An Enumerable list of objects + public IEnumerable GetContentForExpiration() + { + using (var repository = _repositoryFactory.CreateContentRepository(_uowProvider.GetUnitOfWork())) + { + var query = Query.Builder.Where(x => x.Published == true && x.ExpireDate <= DateTime.Now); + var contents = repository.GetByQuery(query); - return contents; - } - } + return contents; + } + } - /// - /// Gets a collection of objects, which has a release date less than or equal to today. - /// - /// An Enumerable list of objects - public IEnumerable GetContentForRelease() - { - using (var repository = _repositoryFactory.CreateContentRepository(_uowProvider.GetUnitOfWork())) - { - var query = Query.Builder.Where(x => x.Published == false && x.ReleaseDate <= DateTime.Now); - var contents = repository.GetByQuery(query); + /// + /// Gets a collection of objects, which has a release date less than or equal to today. + /// + /// An Enumerable list of objects + public IEnumerable GetContentForRelease() + { + using (var repository = _repositoryFactory.CreateContentRepository(_uowProvider.GetUnitOfWork())) + { + var query = Query.Builder.Where(x => x.Published == false && x.ReleaseDate <= DateTime.Now); + var contents = repository.GetByQuery(query); - return contents; - } - } + return contents; + } + } - /// - /// Gets a collection of an objects, which resides in the Recycle Bin - /// - /// An Enumerable list of objects - public IEnumerable GetContentInRecycleBin() - { - using (var repository = _repositoryFactory.CreateContentRepository(_uowProvider.GetUnitOfWork())) - { - var query = Query.Builder.Where(x => x.Path.Contains("-20")); - var contents = repository.GetByQuery(query); + /// + /// Gets a collection of an objects, which resides in the Recycle Bin + /// + /// An Enumerable list of objects + public IEnumerable GetContentInRecycleBin() + { + using (var repository = _repositoryFactory.CreateContentRepository(_uowProvider.GetUnitOfWork())) + { + var query = Query.Builder.Where(x => x.Path.Contains("-20")); + var contents = repository.GetByQuery(query); - return contents; - } - } + return contents; + } + } /// /// Checks whether an item has any children @@ -403,7 +403,7 @@ namespace Umbraco.Core.Services } } - /// + /// /// Publishes a single object /// /// The to publish @@ -414,152 +414,152 @@ namespace Umbraco.Core.Services return SaveAndPublishDo(content, false, userId); } - /// - /// Publishes a object and all its children - /// - /// The to publish along with its children - /// Optional Id of the User issueing the publishing - /// True if publishing succeeded, otherwise False - public bool PublishWithChildren(IContent content, int userId = 0) - { - return PublishWithChildrenDo(content, false, userId); - } + /// + /// Publishes a object and all its children + /// + /// The to publish along with its children + /// Optional Id of the User issueing the publishing + /// True if publishing succeeded, otherwise False + public bool PublishWithChildren(IContent content, int userId = 0) + { + return PublishWithChildrenDo(content, false, userId); + } - /// - /// UnPublishes a single object - /// - /// The to publish - /// Optional Id of the User issueing the publishing - /// True if unpublishing succeeded, otherwise False - public bool UnPublish(IContent content, int userId = 0) - { - return UnPublishDo(content, false, userId); - } + /// + /// UnPublishes a single object + /// + /// The to publish + /// Optional Id of the User issueing the publishing + /// True if unpublishing succeeded, otherwise False + public bool UnPublish(IContent content, int userId = 0) + { + return UnPublishDo(content, false, userId); + } - /// - /// Saves and Publishes a single object - /// - /// The to save and publish - /// Optional Id of the User issueing the publishing + /// + /// Saves and Publishes a single object + /// + /// The to save and publish + /// Optional Id of the User issueing the publishing /// Optional boolean indicating whether or not to raise save events. - /// True if publishing succeeded, otherwise False + /// True if publishing succeeded, otherwise False public bool SaveAndPublish(IContent content, int userId = 0, bool raiseEvents = true) - { - return SaveAndPublishDo(content, false, userId, raiseEvents); - } + { + return SaveAndPublishDo(content, false, userId, raiseEvents); + } - /// - /// Saves a single object - /// - /// The to save - /// Optional Id of the User saving the Content + /// + /// Saves a single object + /// + /// The to save + /// Optional Id of the User saving the Content /// Optional boolean indicating whether or not to raise events. public void Save(IContent content, int userId = 0, bool raiseEvents = true) - { - Save(content, true, userId, raiseEvents); - } + { + Save(content, true, userId, raiseEvents); + } - /// - /// Saves a collection of objects. - /// - /// - /// If the collection of content contains new objects that references eachother by Id or ParentId, - /// then use the overload Save method with a collection of Lazy . - /// - /// Collection of to save - /// Optional Id of the User saving the Content + /// + /// Saves a collection of objects. + /// + /// + /// If the collection of content contains new objects that references eachother by Id or ParentId, + /// then use the overload Save method with a collection of Lazy . + /// + /// Collection of to save + /// Optional Id of the User saving the Content /// Optional boolean indicating whether or not to raise events. public void Save(IEnumerable contents, int userId = 0, bool raiseEvents = true) - { - if(raiseEvents) - { + { + if (raiseEvents) + { if (Saving.IsRaisedEventCancelled(new SaveEventArgs(contents), this)) - return; + return; } - using (new WriteLock(Locker)) - { - var containsNew = contents.Any(x => x.HasIdentity == false); + using (new WriteLock(Locker)) + { + var containsNew = contents.Any(x => x.HasIdentity == false); - var uow = _uowProvider.GetUnitOfWork(); - using (var repository = _repositoryFactory.CreateContentRepository(uow)) - { - if (containsNew) - { - foreach (var content in contents) - { - content.WriterId = userId; + var uow = _uowProvider.GetUnitOfWork(); + using (var repository = _repositoryFactory.CreateContentRepository(uow)) + { + if (containsNew) + { + foreach (var content in contents) + { + content.WriterId = userId; - //Only change the publish state if the "previous" version was actually published - if (content.Published) - content.ChangePublishedState(PublishedState.Saved); + //Only change the publish state if the "previous" version was actually published + if (content.Published) + content.ChangePublishedState(PublishedState.Saved); - repository.AddOrUpdate(content); - uow.Commit(); - } - } - else - { - foreach (var content in contents) - { - content.WriterId = userId; - repository.AddOrUpdate(content); - } - uow.Commit(); - } - } + repository.AddOrUpdate(content); + uow.Commit(); + } + } + else + { + foreach (var content in contents) + { + content.WriterId = userId; + repository.AddOrUpdate(content); + } + uow.Commit(); + } + } - if (raiseEvents) - Saved.RaiseEvent(new SaveEventArgs(contents, false), this); + if (raiseEvents) + Saved.RaiseEvent(new SaveEventArgs(contents, false), this); - Audit.Add(AuditTypes.Save, "Bulk Save content performed by user", userId == -1 ? 0 : userId, -1); - } - } - - /// - /// Deletes all content of specified type. All children of deleted content is moved to Recycle Bin. - /// - /// This needs extra care and attention as its potentially a dangerous and extensive operation - /// Id of the - /// Optional Id of the user issueing the delete operation - public void DeleteContentOfType(int contentTypeId, int userId = 0) - { - using (new WriteLock(Locker)) - { - using (var uow = _uowProvider.GetUnitOfWork()) - { - var repository = _repositoryFactory.CreateContentRepository(uow); - //NOTE What about content that has the contenttype as part of its composition? - var query = Query.Builder.Where(x => x.ContentTypeId == contentTypeId); - var contents = repository.GetByQuery(query); + Audit.Add(AuditTypes.Save, "Bulk Save content performed by user", userId == -1 ? 0 : userId, -1); + } + } - if (Deleting.IsRaisedEventCancelled(new DeleteEventArgs(contents), this)) - return; + /// + /// Deletes all content of specified type. All children of deleted content is moved to Recycle Bin. + /// + /// This needs extra care and attention as its potentially a dangerous and extensive operation + /// Id of the + /// Optional Id of the user issueing the delete operation + public void DeleteContentOfType(int contentTypeId, int userId = 0) + { + using (new WriteLock(Locker)) + { + using (var uow = _uowProvider.GetUnitOfWork()) + { + var repository = _repositoryFactory.CreateContentRepository(uow); + //NOTE What about content that has the contenttype as part of its composition? + var query = Query.Builder.Where(x => x.ContentTypeId == contentTypeId); + var contents = repository.GetByQuery(query); - foreach (var content in contents.OrderByDescending(x => x.ParentId)) - { - //Look for children of current content and move that to trash before the current content is deleted - var c = content; - var childQuery = Query.Builder.Where(x => x.Path.StartsWith(c.Path)); - var children = repository.GetByQuery(childQuery); + if (Deleting.IsRaisedEventCancelled(new DeleteEventArgs(contents), this)) + return; - foreach (var child in children) - { - if (child.ContentType.Id != contentTypeId) - MoveToRecycleBin(child, userId); - } + foreach (var content in contents.OrderByDescending(x => x.ParentId)) + { + //Look for children of current content and move that to trash before the current content is deleted + var c = content; + var childQuery = Query.Builder.Where(x => x.Path.StartsWith(c.Path)); + var children = repository.GetByQuery(childQuery); - //Permantly delete the content - Delete(content, userId); - } - } + foreach (var child in children) + { + if (child.ContentType.Id != contentTypeId) + MoveToRecycleBin(child, userId); + } - Audit.Add(AuditTypes.Delete, - string.Format("Delete Content of Type {0} performed by user", contentTypeId), - userId, -1); - } - } + //Permantly delete the content + Delete(content, userId); + } + } - /// + Audit.Add(AuditTypes.Delete, + string.Format("Delete Content of Type {0} performed by user", contentTypeId), + userId, -1); + } + } + + /// /// Permanently deletes an object as well as all of its Children. /// /// @@ -568,47 +568,47 @@ namespace Umbraco.Core.Services /// Please note that this method will completely remove the Content from the database /// The to delete /// Optional Id of the User deleting the Content - public void Delete(IContent content, int userId = 0) - { - using (new WriteLock(Locker)) - { - if (Deleting.IsRaisedEventCancelled(new DeleteEventArgs(content), this)) - return; + public void Delete(IContent content, int userId = 0) + { + using (new WriteLock(Locker)) + { + if (Deleting.IsRaisedEventCancelled(new DeleteEventArgs(content), this)) + return; - //Make sure that published content is unpublished before being deleted - if (HasPublishedVersion(content.Id)) - { - UnPublish(content, userId); - } + //Make sure that published content is unpublished before being deleted + if (HasPublishedVersion(content.Id)) + { + UnPublish(content, userId); + } - //Delete children before deleting the 'possible parent' - var children = GetChildren(content.Id); - foreach (var child in children) - { - Delete(child, userId); - } + //Delete children before deleting the 'possible parent' + var children = GetChildren(content.Id); + foreach (var child in children) + { + Delete(child, userId); + } - var uow = _uowProvider.GetUnitOfWork(); - using (var repository = _repositoryFactory.CreateContentRepository(uow)) - { - repository.Delete(content); - uow.Commit(); - } + var uow = _uowProvider.GetUnitOfWork(); + using (var repository = _repositoryFactory.CreateContentRepository(uow)) + { + repository.Delete(content); + uow.Commit(); + } - Deleted.RaiseEvent(new DeleteEventArgs(content, false), this); + Deleted.RaiseEvent(new DeleteEventArgs(content, false), this); - Audit.Add(AuditTypes.Delete, "Delete Content performed by user", userId, content.Id); - } - } + Audit.Add(AuditTypes.Delete, "Delete Content performed by user", userId, content.Id); + } + } - /// - /// Permanently deletes versions from an object prior to a specific date. - /// - /// Id of the object to delete versions from - /// Latest version date - /// Optional Id of the User deleting versions of a Content object - public void DeleteVersions(int id, DateTime versionDate, int userId = 0) - { + /// + /// Permanently deletes versions from an object prior to a specific date. + /// + /// Id of the object to delete versions from + /// Latest version date + /// Optional Id of the User deleting versions of a Content object + public void DeleteVersions(int id, DateTime versionDate, int userId = 0) + { //TODO: We should check if we are going to delete the most recent version because if that happens it means the // entity is completely deleted and we should raise the normal Deleting/Deleted event @@ -625,19 +625,19 @@ namespace Umbraco.Core.Services DeletedVersions.RaiseEvent(new DeleteRevisionsEventArgs(id, false, dateToRetain: versionDate), this); Audit.Add(AuditTypes.Delete, "Delete Content by version date performed by user", userId, -1); - } + } - /// - /// Permanently deletes specific version(s) from an object. - /// - /// Id of the object to delete a version from - /// Id of the version to delete - /// Boolean indicating whether to delete versions prior to the versionId - /// Optional Id of the User deleting versions of a Content object - public void DeleteVersion(int id, Guid versionId, bool deletePriorVersions, int userId = 0) - { - using (new WriteLock(Locker)) - { + /// + /// Permanently deletes specific version(s) from an object. + /// + /// Id of the object to delete a version from + /// Id of the version to delete + /// Boolean indicating whether to delete versions prior to the versionId + /// Optional Id of the User deleting versions of a Content object + public void DeleteVersion(int id, Guid versionId, bool deletePriorVersions, int userId = 0) + { + using (new WriteLock(Locker)) + { //TODO: We should check if we are going to delete the most recent version because if that happens it means the // entity is completely deleted and we should raise the normal Deleting/Deleted event @@ -660,19 +660,19 @@ namespace Umbraco.Core.Services DeletedVersions.RaiseEvent(new DeleteRevisionsEventArgs(id, false, specificVersion: versionId), this); Audit.Add(AuditTypes.Delete, "Delete Content by version performed by user", userId, -1); - } - } + } + } - /// - /// Deletes an object by moving it to the Recycle Bin - /// - /// Move an item to the Recycle Bin will result in the item being unpublished - /// The to delete - /// Optional Id of the User deleting the Content - public void MoveToRecycleBin(IContent content, int userId = 0) - { - using (new WriteLock(Locker)) - { + /// + /// Deletes an object by moving it to the Recycle Bin + /// + /// Move an item to the Recycle Bin will result in the item being unpublished + /// The to delete + /// Optional Id of the User deleting the Content + public void MoveToRecycleBin(IContent content, int userId = 0) + { + using (new WriteLock(Locker)) + { if (Trashing.IsRaisedEventCancelled(new MoveEventArgs(content, -20), this)) return; @@ -710,24 +710,24 @@ namespace Umbraco.Core.Services Trashed.RaiseEvent(new MoveEventArgs(content, false, -20), this); Audit.Add(AuditTypes.Move, "Move Content to Recycle Bin performed by user", userId, content.Id); - } - } + } + } - /// - /// Moves an object to a new location by changing its parent id. - /// - /// - /// If the object is already published it will be - /// published after being moved to its new location. Otherwise it'll just - /// be saved with a new parent id. - /// - /// The to move - /// Id of the Content's new Parent - /// Optional Id of the User moving the Content - public void Move(IContent content, int parentId, int userId = 0) - { - using (new WriteLock(Locker)) - { + /// + /// Moves an object to a new location by changing its parent id. + /// + /// + /// If the object is already published it will be + /// published after being moved to its new location. Otherwise it'll just + /// be saved with a new parent id. + /// + /// The to move + /// Id of the Content's new Parent + /// Optional Id of the User moving the Content + public void Move(IContent content, int parentId, int userId = 0) + { + using (new WriteLock(Locker)) + { //This ensures that the correct method is called if this method is used to Move to recycle bin. if (parentId == -20) { @@ -737,9 +737,9 @@ namespace Umbraco.Core.Services if (Moving.IsRaisedEventCancelled(new MoveEventArgs(content, parentId), this)) return; - + content.WriterId = userId; - if (parentId == -1) + if (parentId == -1) { content.Path = string.Concat("-1,", content.Id); content.Level = 1; @@ -806,36 +806,36 @@ namespace Umbraco.Core.Services Moved.RaiseEvent(new MoveEventArgs(content, false, parentId), this); Audit.Add(AuditTypes.Move, "Move Content performed by user", userId, content.Id); - } - } + } + } /// - /// Empties the Recycle Bin by deleting all that resides in the bin - /// - public void EmptyRecycleBin() - { - //TODO: Why don't we have a base class to share between MediaService/ContentService as some of this is exacty the same? + /// Empties the Recycle Bin by deleting all that resides in the bin + /// + public void EmptyRecycleBin() + { + //TODO: Why don't we have a base class to share between MediaService/ContentService as some of this is exacty the same? - var uow = _uowProvider.GetUnitOfWork(); - using (var repository = _repositoryFactory.CreateContentRepository(uow)) - { - var query = Query.Builder.Where(x => x.Trashed == true); - var contents = repository.GetByQuery(query).OrderByDescending(x => x.Level); + var uow = _uowProvider.GetUnitOfWork(); + using (var repository = _repositoryFactory.CreateContentRepository(uow)) + { + var query = Query.Builder.Where(x => x.Trashed == true); + var contents = repository.GetByQuery(query).OrderByDescending(x => x.Level); - foreach (var content in contents) - { - if (Deleting.IsRaisedEventCancelled(new DeleteEventArgs(content), this)) - continue; + foreach (var content in contents) + { + if (Deleting.IsRaisedEventCancelled(new DeleteEventArgs(content), this)) + continue; - repository.Delete(content); + repository.Delete(content); - Deleted.RaiseEvent(new DeleteEventArgs(content, false), this); - } - uow.Commit(); - } + Deleted.RaiseEvent(new DeleteEventArgs(content, false), this); + } + uow.Commit(); + } Audit.Add(AuditTypes.Delete, "Empty Recycle Bin performed by user", 0, -20); - } + } /// /// Copies an object by creating a new Content object of the same type and copies all data from the current @@ -850,7 +850,7 @@ namespace Umbraco.Core.Services { using (new WriteLock(Locker)) { - var copy = ((Content) content).Clone(); + var copy = ((Content)content).Clone(); copy.ParentId = parentId; // A copy should never be set to published automatically even if the original was. @@ -907,10 +907,10 @@ namespace Umbraco.Core.Services var tagsDataTypeId = new Guid("4023e540-92f5-11dd-ad8b-0800200c9a66"); if (content.Properties.Any(x => x.PropertyType.DataTypeId == tagsDataTypeId)) { - var tags = uow.Database.Fetch("WHERE nodeId = @Id", new {Id = content.Id}); + var tags = uow.Database.Fetch("WHERE nodeId = @Id", new { Id = content.Id }); foreach (var tag in tags) { - uow.Database.Insert(new TagRelationshipDto {NodeId = copy.Id, TagId = tag.TagId}); + uow.Database.Insert(new TagRelationshipDto { NodeId = copy.Id, TagId = tag.TagId }); } } } @@ -935,9 +935,9 @@ namespace Umbraco.Core.Services string.Format("Copied content with Id: '{0}' related to original content with Id: '{1}'", copy.Id, content.Id), copy.WriterId, copy.Id); } - + //Look for children and copy those as well - var children = GetChildren(content.Id); + var children = GetChildren(content.Id).OrderBy(x => x.SortOrder); foreach (var child in children) { Copy(child, copy.Id, relateToOriginal, userId); @@ -946,48 +946,48 @@ namespace Umbraco.Core.Services Copied.RaiseEvent(new CopyEventArgs(content, copy, false, parentId), this); Audit.Add(AuditTypes.Copy, "Copy Content performed by user", content.WriterId, content.Id); - + RuntimeCacheProvider.Current.Clear(); return copy; } } - /// - /// Sends an to Publication, which executes handlers and events for the 'Send to Publication' action. - /// - /// The to send to publication - /// Optional Id of the User issueing the send to publication - /// True if sending publication was succesfull otherwise false - internal bool SendToPublication(IContent content, int userId = 0) - { + /// + /// Sends an to Publication, which executes handlers and events for the 'Send to Publication' action. + /// + /// The to send to publication + /// Optional Id of the User issueing the send to publication + /// True if sending publication was succesfull otherwise false + internal bool SendToPublication(IContent content, int userId = 0) + { - if (SendingToPublish.IsRaisedEventCancelled(new SendToPublishEventArgs(content), this)) - return false; + if (SendingToPublish.IsRaisedEventCancelled(new SendToPublishEventArgs(content), this)) + return false; - //TODO: Do some stuff here.. RunActionHandlers + //TODO: Do some stuff here.. RunActionHandlers - SentToPublish.RaiseEvent(new SendToPublishEventArgs(content, false), this); + SentToPublish.RaiseEvent(new SendToPublishEventArgs(content, false), this); - Audit.Add(AuditTypes.SendToPublish, "Send to Publish performed by user", content.WriterId, content.Id); + Audit.Add(AuditTypes.SendToPublish, "Send to Publish performed by user", content.WriterId, content.Id); - return true; - } + return true; + } - /// - /// Rollback an object to a previous version. - /// This will create a new version, which is a copy of all the old data. - /// - /// - /// The way data is stored actually only allows us to rollback on properties - /// and not data like Name and Alias of the Content. - /// - /// Id of the being rolled back - /// Id of the version to rollback to - /// Optional Id of the User issueing the rollback of the Content - /// The newly created object - public IContent Rollback(int id, Guid versionId, int userId = 0) - { + /// + /// Rollback an object to a previous version. + /// This will create a new version, which is a copy of all the old data. + /// + /// + /// The way data is stored actually only allows us to rollback on properties + /// and not data like Name and Alias of the Content. + /// + /// Id of the being rolled back + /// Id of the version to rollback to + /// Optional Id of the User issueing the rollback of the Content + /// The newly created object + public IContent Rollback(int id, Guid versionId, int userId = 0) + { var content = GetByVersion(versionId); if (RollingBack.IsRaisedEventCancelled(new RollbackEventArgs(content), this)) @@ -1008,10 +1008,10 @@ namespace Umbraco.Core.Services Audit.Add(AuditTypes.RollBack, "Content rollback performed by user", content.WriterId, content.Id); return content; - } + } #region Internal Methods - + /// /// Internal method that Publishes a single object for legacy purposes. /// @@ -1048,15 +1048,15 @@ namespace Umbraco.Core.Services return UnPublishDo(content, omitCacheRefresh, userId); } - /// - /// Saves and Publishes a single object - /// - /// The to save and publish - /// Optional boolean to avoid having the cache refreshed when calling this Publish method. By default this method will not update the cache. - /// Optional Id of the User issueing the publishing + /// + /// Saves and Publishes a single object + /// + /// The to save and publish + /// Optional boolean to avoid having the cache refreshed when calling this Publish method. By default this method will not update the cache. + /// Optional Id of the User issueing the publishing /// Optional boolean indicating whether or not to raise save events. - /// True if publishing succeeded, otherwise False - internal bool SaveAndPublish(IContent content, bool omitCacheRefresh = true, int userId = 0, bool raiseEvents = true) + /// True if publishing succeeded, otherwise False + internal bool SaveAndPublish(IContent content, bool omitCacheRefresh = true, int userId = 0, bool raiseEvents = true) { return SaveAndPublishDo(content, omitCacheRefresh, userId, raiseEvents); } @@ -1246,138 +1246,138 @@ namespace Umbraco.Core.Services } return unpublished; - } + } } - /// - /// Saves and Publishes a single object - /// - /// The to save and publish - /// Optional boolean to avoid having the cache refreshed when calling this Publish method. By default this method will update the cache. - /// Optional Id of the User issueing the publishing + /// + /// Saves and Publishes a single object + /// + /// The to save and publish + /// Optional boolean to avoid having the cache refreshed when calling this Publish method. By default this method will update the cache. + /// Optional Id of the User issueing the publishing /// Optional boolean indicating whether or not to raise save events. - /// True if publishing succeeded, otherwise False - private bool SaveAndPublishDo(IContent content, bool omitCacheRefresh = false, int userId = 0, bool raiseEvents = true) + /// True if publishing succeeded, otherwise False + private bool SaveAndPublishDo(IContent content, bool omitCacheRefresh = false, int userId = 0, bool raiseEvents = true) { - if(raiseEvents) + if (raiseEvents) { if (Saving.IsRaisedEventCancelled(new SaveEventArgs(content), this)) - return false; + return false; } - using (new WriteLock(Locker)) - { - //Has this content item previously been published? If so, we don't need to refresh the children - var previouslyPublished = HasPublishedVersion(content.Id); - var validForPublishing = true; + using (new WriteLock(Locker)) + { + //Has this content item previously been published? If so, we don't need to refresh the children + var previouslyPublished = HasPublishedVersion(content.Id); + var validForPublishing = true; - //Check if parent is published (although not if its a root node) - if parent isn't published this Content cannot be published - if (content.ParentId != -1 && content.ParentId != -20 && IsPublishable(content) == false) - { - LogHelper.Info( - string.Format( - "Content '{0}' with Id '{1}' could not be published because its parent is not published.", - content.Name, content.Id)); - validForPublishing = false; - } + //Check if parent is published (although not if its a root node) - if parent isn't published this Content cannot be published + if (content.ParentId != -1 && content.ParentId != -20 && IsPublishable(content) == false) + { + LogHelper.Info( + string.Format( + "Content '{0}' with Id '{1}' could not be published because its parent is not published.", + content.Name, content.Id)); + validForPublishing = false; + } - //Content contains invalid property values and can therefore not be published - fire event? - if (!content.IsValid()) - { - LogHelper.Info( - string.Format( - "Content '{0}' with Id '{1}' could not be published because of invalid properties.", - content.Name, content.Id)); - validForPublishing = false; - } + //Content contains invalid property values and can therefore not be published - fire event? + if (!content.IsValid()) + { + LogHelper.Info( + string.Format( + "Content '{0}' with Id '{1}' could not be published because of invalid properties.", + content.Name, content.Id)); + validForPublishing = false; + } - //Publish and then update the database with new status - bool published = validForPublishing && _publishingStrategy.Publish(content, userId); + //Publish and then update the database with new status + bool published = validForPublishing && _publishingStrategy.Publish(content, userId); - var uow = _uowProvider.GetUnitOfWork(); - using (var repository = _repositoryFactory.CreateContentRepository(uow)) - { - //Since this is the Save and Publish method, the content should be saved even though the publish fails or isn't allowed - content.WriterId = userId; + var uow = _uowProvider.GetUnitOfWork(); + using (var repository = _repositoryFactory.CreateContentRepository(uow)) + { + //Since this is the Save and Publish method, the content should be saved even though the publish fails or isn't allowed + content.WriterId = userId; - repository.AddOrUpdate(content); + repository.AddOrUpdate(content); - uow.Commit(); + uow.Commit(); - var xml = content.ToXml(); - //Preview Xml - var previewPoco = new PreviewXmlDto - { - NodeId = content.Id, - Timestamp = DateTime.Now, - VersionId = content.Version, - Xml = xml.ToString(SaveOptions.None) - }; - var previewExists = - uow.Database.ExecuteScalar("SELECT COUNT(nodeId) FROM cmsPreviewXml WHERE nodeId = @Id AND versionId = @Version", - new {Id = content.Id, Version = content.Version}) != 0; - int previewResult = previewExists - ? uow.Database.Update( - "SET xml = @Xml, timestamp = @Timestamp WHERE nodeId = @Id AND versionId = @Version", - new - { - Xml = previewPoco.Xml, - Timestamp = previewPoco.Timestamp, - Id = previewPoco.NodeId, - Version = previewPoco.VersionId - }) - : Convert.ToInt32(uow.Database.Insert(previewPoco)); + var xml = content.ToXml(); + //Preview Xml + var previewPoco = new PreviewXmlDto + { + NodeId = content.Id, + Timestamp = DateTime.Now, + VersionId = content.Version, + Xml = xml.ToString(SaveOptions.None) + }; + var previewExists = + uow.Database.ExecuteScalar("SELECT COUNT(nodeId) FROM cmsPreviewXml WHERE nodeId = @Id AND versionId = @Version", + new { Id = content.Id, Version = content.Version }) != 0; + int previewResult = previewExists + ? uow.Database.Update( + "SET xml = @Xml, timestamp = @Timestamp WHERE nodeId = @Id AND versionId = @Version", + new + { + Xml = previewPoco.Xml, + Timestamp = previewPoco.Timestamp, + Id = previewPoco.NodeId, + Version = previewPoco.VersionId + }) + : Convert.ToInt32(uow.Database.Insert(previewPoco)); - if (published) - { - //Content Xml - var contentPoco = new ContentXmlDto {NodeId = content.Id, Xml = xml.ToString(SaveOptions.None)}; - var contentExists = uow.Database.ExecuteScalar("SELECT COUNT(nodeId) FROM cmsContentXml WHERE nodeId = @Id", new {Id = content.Id}) != 0; - int contentResult = contentExists - ? uow.Database.Update(contentPoco) - : Convert.ToInt32(uow.Database.Insert(contentPoco)); + if (published) + { + //Content Xml + var contentPoco = new ContentXmlDto { NodeId = content.Id, Xml = xml.ToString(SaveOptions.None) }; + var contentExists = uow.Database.ExecuteScalar("SELECT COUNT(nodeId) FROM cmsContentXml WHERE nodeId = @Id", new { Id = content.Id }) != 0; + int contentResult = contentExists + ? uow.Database.Update(contentPoco) + : Convert.ToInt32(uow.Database.Insert(contentPoco)); - } - } + } + } - if (raiseEvents) - Saved.RaiseEvent(new SaveEventArgs(content, false), this); + if (raiseEvents) + Saved.RaiseEvent(new SaveEventArgs(content, false), this); - //Save xml to db and call following method to fire event through PublishingStrategy to update cache - if (published && omitCacheRefresh == false) - _publishingStrategy.PublishingFinalized(content); + //Save xml to db and call following method to fire event through PublishingStrategy to update cache + if (published && omitCacheRefresh == false) + _publishingStrategy.PublishingFinalized(content); - //We need to check if children and their publish state to ensure that we 'republish' content that was previously published - if (published && omitCacheRefresh == false && previouslyPublished == false && HasChildren(content.Id)) - { - var descendants = GetPublishedDescendants(content); + //We need to check if children and their publish state to ensure that we 'republish' content that was previously published + if (published && omitCacheRefresh == false && previouslyPublished == false && HasChildren(content.Id)) + { + var descendants = GetPublishedDescendants(content); - _publishingStrategy.PublishingFinalized(descendants, false); - } + _publishingStrategy.PublishingFinalized(descendants, false); + } - Audit.Add(AuditTypes.Publish, "Save and Publish performed by user", userId, content.Id); + Audit.Add(AuditTypes.Publish, "Save and Publish performed by user", userId, content.Id); - return published; - } + return published; + } } - /// - /// Saves a single object - /// - /// The to save - /// Boolean indicating whether or not to change the Published state upon saving - /// Optional Id of the User saving the Content + /// + /// Saves a single object + /// + /// The to save + /// Boolean indicating whether or not to change the Published state upon saving + /// Optional Id of the User saving the Content /// Optional boolean indicating whether or not to raise events. - private void Save(IContent content, bool changeState, int userId = 0, bool raiseEvents = true) + private void Save(IContent content, bool changeState, int userId = 0, bool raiseEvents = true) { - if(raiseEvents) + if (raiseEvents) { if (Saving.IsRaisedEventCancelled(new SaveEventArgs(content), this)) - return; + return; } - using (new WriteLock(Locker)) - { + using (new WriteLock(Locker)) + { var uow = _uowProvider.GetUnitOfWork(); using (var repository = _repositoryFactory.CreateContentRepository(uow)) { @@ -1419,7 +1419,7 @@ namespace Umbraco.Core.Services Saved.RaiseEvent(new SaveEventArgs(content, false), this); Audit.Add(AuditTypes.Save, "Save Content performed by user", userId, content.Id); - } + } } /// @@ -1523,98 +1523,98 @@ namespace Umbraco.Core.Services #region Event Handlers /// - /// Occurs before Delete - /// - public static event TypedEventHandler> Deleting; + /// Occurs before Delete + /// + public static event TypedEventHandler> Deleting; - /// - /// Occurs after Delete - /// - public static event TypedEventHandler> Deleted; + /// + /// Occurs after Delete + /// + public static event TypedEventHandler> Deleted; - /// - /// Occurs before Delete Versions - /// - public static event TypedEventHandler DeletingVersions; + /// + /// Occurs before Delete Versions + /// + public static event TypedEventHandler DeletingVersions; - /// - /// Occurs after Delete Versions - /// - public static event TypedEventHandler DeletedVersions; + /// + /// Occurs after Delete Versions + /// + public static event TypedEventHandler DeletedVersions; - /// - /// Occurs before Save - /// - public static event TypedEventHandler> Saving; - - /// - /// Occurs after Save - /// - public static event TypedEventHandler> Saved; - - /// - /// Occurs before Create - /// - public static event TypedEventHandler> Creating; + /// + /// Occurs before Save + /// + public static event TypedEventHandler> Saving; - /// - /// Occurs after Create - /// + /// + /// Occurs after Save + /// + public static event TypedEventHandler> Saved; + + /// + /// Occurs before Create + /// + public static event TypedEventHandler> Creating; + + /// + /// Occurs after Create + /// /// /// Please note that the Content object has been created, but not saved /// so it does not have an identity yet (meaning no Id has been set). /// - public static event TypedEventHandler> Created; + public static event TypedEventHandler> Created; - /// - /// Occurs before Copy - /// - public static event TypedEventHandler> Copying; + /// + /// Occurs before Copy + /// + public static event TypedEventHandler> Copying; - /// - /// Occurs after Copy - /// - public static event TypedEventHandler> Copied; + /// + /// Occurs after Copy + /// + public static event TypedEventHandler> Copied; - /// - /// Occurs before Content is moved to Recycle Bin - /// - public static event TypedEventHandler> Trashing; + /// + /// Occurs before Content is moved to Recycle Bin + /// + public static event TypedEventHandler> Trashing; - /// - /// Occurs after Content is moved to Recycle Bin - /// - public static event TypedEventHandler> Trashed; + /// + /// Occurs after Content is moved to Recycle Bin + /// + public static event TypedEventHandler> Trashed; - /// - /// Occurs before Move - /// - public static event TypedEventHandler> Moving; + /// + /// Occurs before Move + /// + public static event TypedEventHandler> Moving; - /// - /// Occurs after Move - /// - public static event TypedEventHandler> Moved; + /// + /// Occurs after Move + /// + public static event TypedEventHandler> Moved; - /// - /// Occurs before Rollback - /// - public static event TypedEventHandler> RollingBack; + /// + /// Occurs before Rollback + /// + public static event TypedEventHandler> RollingBack; - /// - /// Occurs after Rollback - /// - public static event TypedEventHandler> RolledBack; + /// + /// Occurs after Rollback + /// + public static event TypedEventHandler> RolledBack; - /// - /// Occurs before Send to Publish - /// - public static event TypedEventHandler> SendingToPublish; + /// + /// Occurs before Send to Publish + /// + public static event TypedEventHandler> SendingToPublish; - /// - /// Occurs after Send to Publish - /// - public static event TypedEventHandler> SentToPublish; - #endregion - } + /// + /// Occurs after Send to Publish + /// + public static event TypedEventHandler> SentToPublish; + #endregion + } } \ No newline at end of file From 2d3eb8c208b5e67c31c272b53997c05c4c68740d Mon Sep 17 00:00:00 2001 From: Shannon Deminick Date: Tue, 23 Apr 2013 20:00:48 -1000 Subject: [PATCH 15/19] Working on #U4-493, updated ContentTypeControlNew and EditNodeTypeNew to use correct webforms class structures. Changed the saving logic in ContentTypeControlNew to use the page's async execution and changed the page to support async. Changed the page's async timeout to be 5 minutes. --- src/Umbraco.Web.UI/Umbraco.Web.UI.csproj | 14 + .../controls/ContentTypeControlNew.ascx | 2 +- .../controls/ContentTypeControlNew.ascx.cs | 11 + .../ContentTypeControlNew.ascx.designer.cs | 15 + .../umbraco/settings/EditNodeTypeNew.aspx | 7 +- .../umbraco/settings/EditNodeTypeNew.aspx.cs | 11 + .../settings/EditNodeTypeNew.aspx.designer.cs | 15 + src/Umbraco.Web/Umbraco.Web.csproj | 26 +- .../controls/ContentTypeControlNew.ascx | 106 --- .../controls/ContentTypeControlNew.ascx.cs | 713 +++++++++++++----- .../ContentTypeControlNew.ascx.designer.cs | 348 --------- .../GenericProperties/GenericProperty.ascx.cs | 23 +- .../umbraco/settings/EditNodeTypeNew.aspx | 58 -- .../umbraco/settings/EditNodeTypeNew.aspx.cs | 67 +- .../settings/EditNodeTypeNew.aspx.designer.cs | 42 -- src/umbraco.cms/businesslogic/web/Document.cs | 3 +- 16 files changed, 656 insertions(+), 805 deletions(-) create mode 100644 src/Umbraco.Web.UI/umbraco/controls/ContentTypeControlNew.ascx.cs create mode 100644 src/Umbraco.Web.UI/umbraco/controls/ContentTypeControlNew.ascx.designer.cs create mode 100644 src/Umbraco.Web.UI/umbraco/settings/EditNodeTypeNew.aspx.cs create mode 100644 src/Umbraco.Web.UI/umbraco/settings/EditNodeTypeNew.aspx.designer.cs delete mode 100644 src/Umbraco.Web/umbraco.presentation/umbraco/controls/ContentTypeControlNew.ascx delete mode 100644 src/Umbraco.Web/umbraco.presentation/umbraco/controls/ContentTypeControlNew.ascx.designer.cs delete mode 100644 src/Umbraco.Web/umbraco.presentation/umbraco/settings/EditNodeTypeNew.aspx delete mode 100644 src/Umbraco.Web/umbraco.presentation/umbraco/settings/EditNodeTypeNew.aspx.designer.cs diff --git a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj index f5431c626e..22d4393e0c 100644 --- a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj +++ b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj @@ -296,6 +296,13 @@ loadStarterKits.ascx + + ContentTypeControlNew.ascx + ASPXCodeBehind + + + ContentTypeControlNew.ascx + create.aspx ASPXCodeBehind @@ -350,6 +357,13 @@ QuickSearch.ascx + + EditNodeTypeNew.aspx + ASPXCodeBehind + + + EditNodeTypeNew.aspx + ASPXCodeBehind diff --git a/src/Umbraco.Web.UI/umbraco/controls/ContentTypeControlNew.ascx b/src/Umbraco.Web.UI/umbraco/controls/ContentTypeControlNew.ascx index d0d0899bd7..2f0bad8371 100644 --- a/src/Umbraco.Web.UI/umbraco/controls/ContentTypeControlNew.ascx +++ b/src/Umbraco.Web.UI/umbraco/controls/ContentTypeControlNew.ascx @@ -1,5 +1,5 @@ <%@ Control Language="c#" AutoEventWireup="True" Codebehind="ContentTypeControlNew.ascx.cs" - Inherits="umbraco.controls.ContentTypeControlNew" TargetSchema="http://schemas.microsoft.com/intellisense/ie5" %> + Inherits="Umbraco.Web.UI.Umbraco.Controls.ContentTypeControlNew" TargetSchema="http://schemas.microsoft.com/intellisense/ie5" %> <%@ Register TagPrefix="cc1" Namespace="umbraco.uicontrols" Assembly="controls" %> <%@ Register TagPrefix="cc2" Namespace="umbraco.uicontrols" Assembly="controls" %> diff --git a/src/Umbraco.Web.UI/umbraco/controls/ContentTypeControlNew.ascx.cs b/src/Umbraco.Web.UI/umbraco/controls/ContentTypeControlNew.ascx.cs new file mode 100644 index 0000000000..c3459b752e --- /dev/null +++ b/src/Umbraco.Web.UI/umbraco/controls/ContentTypeControlNew.ascx.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web; + +namespace Umbraco.Web.UI.Umbraco.Controls +{ + public partial class ContentTypeControlNew : global::umbraco.controls.ContentTypeControlNew + { + } +} \ No newline at end of file diff --git a/src/Umbraco.Web.UI/umbraco/controls/ContentTypeControlNew.ascx.designer.cs b/src/Umbraco.Web.UI/umbraco/controls/ContentTypeControlNew.ascx.designer.cs new file mode 100644 index 0000000000..582c67837d --- /dev/null +++ b/src/Umbraco.Web.UI/umbraco/controls/ContentTypeControlNew.ascx.designer.cs @@ -0,0 +1,15 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace Umbraco.Web.UI.Umbraco.Controls { + + + public partial class ContentTypeControlNew { + } +} diff --git a/src/Umbraco.Web.UI/umbraco/settings/EditNodeTypeNew.aspx b/src/Umbraco.Web.UI/umbraco/settings/EditNodeTypeNew.aspx index 73975e64f2..2199af68c6 100644 --- a/src/Umbraco.Web.UI/umbraco/settings/EditNodeTypeNew.aspx +++ b/src/Umbraco.Web.UI/umbraco/settings/EditNodeTypeNew.aspx @@ -1,5 +1,5 @@ <%@ Page Language="c#" CodeBehind="EditNodeTypeNew.aspx.cs" AutoEventWireup="True" - Trace="false" Inherits="umbraco.settings.EditContentTypeNew" MasterPageFile="../masterpages/umbracoPage.Master" %> + Async="true" AsyncTimeOut="300" Trace="true" Inherits="Umbraco.Web.UI.Umbraco.Settings.EditNodeTypeNew" MasterPageFile="../masterpages/umbracoPage.Master" %> <%@ Register TagPrefix="cc1" Namespace="umbraco.uicontrols" Assembly="controls" %> <%@ Register TagPrefix="uc1" TagName="ContentTypeControlNew" Src="../controls/ContentTypeControlNew.ascx" %> @@ -9,7 +9,7 @@ jQuery(document).ready(function () { // Auto selection/de-selection of default template based on allow templates - jQuery("#<%= templateList.ClientID %> input[type='checkbox']").on("change", function () { + jQuery("#<%= templateList.ClientID %> input[type='checkbox']").on("change", function() { var checkbox = jQuery(this); var ddl = jQuery("#<%= ddlTemplates.ClientID %>"); // If default template is not set, and an allowed template is selected, auto-select the default template @@ -17,7 +17,8 @@ if (ddl.val() == "0") { ddl.val(checkbox.val()); } - } else { + } + else { // If allowed template has been de-selected, and it's selected as the default, then de-select the default template if (ddl.val() == checkbox.val()) { ddl.val("0"); diff --git a/src/Umbraco.Web.UI/umbraco/settings/EditNodeTypeNew.aspx.cs b/src/Umbraco.Web.UI/umbraco/settings/EditNodeTypeNew.aspx.cs new file mode 100644 index 0000000000..f5705d25de --- /dev/null +++ b/src/Umbraco.Web.UI/umbraco/settings/EditNodeTypeNew.aspx.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web; + +namespace Umbraco.Web.UI.Umbraco.Settings +{ + public partial class EditNodeTypeNew : global::umbraco.settings.EditContentTypeNew + { + } +} \ No newline at end of file diff --git a/src/Umbraco.Web.UI/umbraco/settings/EditNodeTypeNew.aspx.designer.cs b/src/Umbraco.Web.UI/umbraco/settings/EditNodeTypeNew.aspx.designer.cs new file mode 100644 index 0000000000..349f5daab1 --- /dev/null +++ b/src/Umbraco.Web.UI/umbraco/settings/EditNodeTypeNew.aspx.designer.cs @@ -0,0 +1,15 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace Umbraco.Web.UI.Umbraco.Settings { + + + public partial class EditNodeTypeNew { + } +} diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index a66e7c2dd1..ff7d27beec 100644 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -348,6 +348,9 @@ ASPXCodeBehind + + ASPXCodeBehind + ASPXCodeBehind @@ -385,6 +388,9 @@ ASPXCodeBehind + + ASPXCodeBehind + ASPXCodeBehind @@ -677,13 +683,6 @@ UploadMediaImage.ascx - - ContentTypeControlNew.ascx - ASPXCodeBehind - - - ContentTypeControlNew.ascx - GenericProperty.ascx @@ -1495,13 +1494,6 @@ EditMediaType.aspx - - EditNodeTypeNew.aspx - ASPXCodeBehind - - - EditNodeTypeNew.aspx - editScript.aspx ASPXCodeBehind @@ -1864,9 +1856,6 @@ - - ASPXCodeBehind - ASPXCodeBehind @@ -2038,9 +2027,6 @@ - - ASPXCodeBehind - ASPXCodeBehind diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/controls/ContentTypeControlNew.ascx b/src/Umbraco.Web/umbraco.presentation/umbraco/controls/ContentTypeControlNew.ascx deleted file mode 100644 index d0d0899bd7..0000000000 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/controls/ContentTypeControlNew.ascx +++ /dev/null @@ -1,106 +0,0 @@ -<%@ Control Language="c#" AutoEventWireup="True" Codebehind="ContentTypeControlNew.ascx.cs" - Inherits="umbraco.controls.ContentTypeControlNew" TargetSchema="http://schemas.microsoft.com/intellisense/ie5" %> -<%@ Register TagPrefix="cc1" Namespace="umbraco.uicontrols" Assembly="controls" %> -<%@ Register TagPrefix="cc2" Namespace="umbraco.uicontrols" Assembly="controls" %> - - - - - - - - -

<%=umbraco.ui.GetText("settings", "contentTypeEnabled")%>
<%=umbraco.ui.GetText("settings", "contentTypeUses")%> <%=umbraco.ui.GetText("settings", "asAContentMasterType")%>

-
- - - -   - - - - - - - - - - - - - - - - - - - - - - -

-

-
-
- - - - - - - - - - - - - - - - - -
- -
-
- -
- -
-
- - - -
-
- - - - - - - - - - - - -

Master Content Type enabled
This Content Type uses as a Master Content Type. Properties from Master Content Types are not shown and can only be edited on the Master Content Type itself

-
- - -
- - -
-
-
- \ No newline at end of file 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 a14f1d13c5..7ebbc278c7 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/controls/ContentTypeControlNew.ascx.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/controls/ContentTypeControlNew.ascx.cs @@ -1,14 +1,17 @@ -using System; +using System; using System.Collections; using System.Collections.Generic; using System.Data; using System.IO; using System.Linq; +using System.Threading.Tasks; +using System.Web; using System.Web.UI; using System.Web.UI.HtmlControls; using System.Web.UI.WebControls; using ClientDependency.Core; using Umbraco.Core; +using umbraco.BusinessLogic; using umbraco.cms.helpers; using umbraco.cms.presentation.Trees; using umbraco.controls.GenericProperties; @@ -50,45 +53,45 @@ namespace umbraco.controls // "Generic properties" tab public uicontrols.TabPage GenericPropertiesTabPage; - public GenericProperties.GenericPropertyWrapper gp; private ArrayList _genericProperties = new ArrayList(); private ArrayList _sortLists = new ArrayList(); protected System.Web.UI.WebControls.DataGrid dgGeneralTabProperties; + //the async saving task + private Action _asyncSaveTask; + override protected void OnInit(EventArgs e) { base.OnInit(e); - - int docTypeId = getDocTypeId(); + + int docTypeId = GetDocTypeId(); _contentType = new cms.businesslogic.ContentType(docTypeId); - setupInfoPane(); + SetupInfoPane(); if (!HideStructure) { - setupStructurePane(); + SetupStructurePane(); } - setupGenericPropertiesPane(); - setupTabPane(); + SetupGenericPropertiesPane(); + SetupTabPane(); } - private int getDocTypeId() + private int GetDocTypeId() { return int.Parse(Request.QueryString["id"]); } protected void Page_Load(object sender, System.EventArgs e) { - - - pp_newTab.Text = ui.Text("newtab", umbraco.BasePages.UmbracoEnsuredPage.CurrentUser); - pp_alias.Text = umbraco.ui.Text("alias", umbraco.BasePages.UmbracoEnsuredPage.CurrentUser); - pp_name.Text = umbraco.ui.Text("name", umbraco.BasePages.UmbracoEnsuredPage.CurrentUser); - pp_allowedChildren.Text = umbraco.ui.Text("allowedchildnodetypes", umbraco.BasePages.UmbracoEnsuredPage.CurrentUser); - pp_description.Text = umbraco.ui.Text("editcontenttype", "description"); - pp_icon.Text = umbraco.ui.Text("icon", umbraco.BasePages.UmbracoEnsuredPage.CurrentUser); - pp_thumbnail.Text = umbraco.ui.Text("editcontenttype", "thumbnail"); + pp_newTab.Text = ui.Text("newtab", CurrentUser); + pp_alias.Text = umbraco.ui.Text("alias", CurrentUser); + pp_name.Text = umbraco.ui.Text("name", CurrentUser); + pp_allowedChildren.Text = umbraco.ui.Text("allowedchildnodetypes", CurrentUser); + pp_description.Text = umbraco.ui.Text("editcontenttype", "description", CurrentUser); + pp_icon.Text = umbraco.ui.Text("icon", CurrentUser); + pp_thumbnail.Text = umbraco.ui.Text("editcontenttype", "thumbnail", CurrentUser); // we'll disable this... @@ -104,52 +107,138 @@ namespace umbraco.controls theClientId.Text = this.ClientID; } - protected void save_click(object sender, System.Web.UI.ImageClickEventArgs e) + //SD: this is temporary in v4, in v6 we have a proper user control hierarchy + //containing this property. + //this is required due to this issue: http://issues.umbraco.org/issue/u4-493 + //because we need to execute some code in async but due to the localization + //framework requiring an httpcontext.current, it will not work. + //http://issues.umbraco.org/issue/u4-2143 + //so, we are going to make a property here and ensure that the basepage has + //resolved the user before we execute the async task so that in this method + //our calls to ui.text will include the current user and not rely on the + //httpcontext.current. This also improves performance: + // http://issues.umbraco.org/issue/U4-2142 + private User CurrentUser { - // 2011 01 06 - APN - Modified method to update Xml caches if a doctype alias changed, - // also added calls to update the tree if the name has changed - // --- + get { return ((BasePage)Page).getUser(); } + } + + /// + /// Called asynchronously in order to persist all of the data to the database + /// + /// + /// + /// + /// + /// + /// + /// This can be a long running operation depending on how many content nodes exist and if the node type alias + /// has changed as this will need to regenerate XML for all of the nodes. + /// + private IAsyncResult BeginAsyncSaveOperation(object sender, EventArgs e, AsyncCallback cb, object state) + { + Trace.Write("ContentTypeControlNew", "Start async operation"); + + //get the args from the async state + var args = (SaveClickEventArgs)state; + + //start the task + var result = _asyncSaveTask.BeginInvoke(args, cb, args); + return result; + } + + /// + /// Occurs once the async database save operation has completed + /// + /// + /// + /// This updates the UI elements + /// + private void EndAsyncSaveOperation(IAsyncResult ar) + { + Trace.Write("ContentTypeControlNew", "ending async operation"); + + //get the args from the async state + var args = (SaveClickEventArgs)ar.AsyncState; - // Keep a reference of the original doctype alias and name - var originalDocTypeAlias = _contentType.Alias; var originalDocTypeName = _contentType.Text; + var docTypeNameChanged = (string.Compare(originalDocTypeName, _contentType.Text, StringComparison.OrdinalIgnoreCase) != 0); - _contentType.Text = txtName.Text; - _contentType.Alias = txtAlias.Text; - _contentType.IconUrl = ddlIcons.SelectedValue; - _contentType.Description = description.Text; - _contentType.Thumbnail = ddlThumbnails.SelectedValue; - SaveClickEventArgs ea = new SaveClickEventArgs("Saved"); - ea.IconType = umbraco.BasePages.BasePage.speechBubbleIcon.success; - - saveProperties(ref ea); - - SaveTabs(); - - SaveAllowedChildTypes(); - - // reload content type (due to caching) - _contentType = new ContentType(_contentType.Id); - - // Check if the doctype alias has changed as a result of either the user input or - // the alias checking performed upon saving - var docTypeAliasChanged = (string.Compare(originalDocTypeAlias, _contentType.Alias, true) != 0); - var docTypeNameChanged = (string.Compare(originalDocTypeName, _contentType.Text, true) != 0); - - // 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 (docTypeAliasChanged) - RegenerateXmlCaches(); - - bindDataGenericProperties(true); + BindDataGenericProperties(true); // we need to re-bind the alias as the SafeAlias method can have changed it txtAlias.Text = _contentType.Alias; - RaiseBubbleEvent(new object(), ea); + RaiseBubbleEvent(new object(), args); if (docTypeNameChanged) UpdateTreeNode(); + + Trace.Write("ContentTypeControlNew", "async operation ended"); + + //complete it + _asyncSaveTask.EndInvoke(ar); + } + + private void HandleAsyncSaveTimeout(IAsyncResult ar) + { + Trace.Write("ContentTypeControlNew", "async operation timed out!"); + } + + /// + /// The save button click event handlers + /// + /// + /// + protected void save_click(object sender, System.Web.UI.ImageClickEventArgs e) + { + + //event args to be passed in to the async method + var eventArgs = new SaveClickEventArgs("Saved") + { + IconType = BasePage.speechBubbleIcon.success + }; + + //Add the async operation to the page + Page.RegisterAsyncTask(new PageAsyncTask(BeginAsyncSaveOperation, EndAsyncSaveOperation, HandleAsyncSaveTimeout, eventArgs)); + + //create the save task to be executed async + _asyncSaveTask = args => + { + Trace.Write("ContentTypeControlNew", "executing task"); + + // Keep a reference of the original doctype alias and name + var originalDocTypeAlias = _contentType.Alias; + + _contentType.Text = txtName.Text; + _contentType.Alias = txtAlias.Text; + _contentType.IconUrl = ddlIcons.SelectedValue; + _contentType.Description = description.Text; + _contentType.Thumbnail = ddlThumbnails.SelectedValue; + + SaveProperties(args); + + SaveTabs(); + + SaveAllowedChildTypes(); + + // reload content type (due to caching) + _contentType = new ContentType(_contentType.Id); + + // Check if the doctype alias has changed as a result of either the user input or + // the alias checking performed upon saving + var docTypeAliasChanged = (string.Compare(originalDocTypeAlias, _contentType.Alias, StringComparison.OrdinalIgnoreCase) != 0); + + // 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 (docTypeAliasChanged) + RegenerateXmlCaches(); + + Trace.Write("ContentTypeControlNew", "task completing"); + }; + + //execute the async tasks + Page.ExecuteRegisteredAsyncTasks(); } /// @@ -171,7 +260,7 @@ namespace umbraco.controls #region "Info" Pane - private void setupInfoPane() + private void SetupInfoPane() { InfoTabPage = TabView1.NewTabPage("Info"); InfoTabPage.Controls.Add(pnlInfo); @@ -182,7 +271,7 @@ namespace umbraco.controls Save.Click += save_click; Save.ImageUrl = UmbracoPath + "/images/editor/save.gif"; - Save.AlternateText = ui.Text("save"); + Save.AlternateText = ui.Text("save", CurrentUser); Save.ID = "save"; var dirInfo = new DirectoryInfo(UmbracoContext.Current.Server.MapPath(SystemDirectories.Umbraco + "/images/umbraco")); @@ -198,8 +287,8 @@ namespace umbraco.controls foreach (var iconClass in CMSNode.DefaultIconClasses.Where(iconClass => iconClass.Equals(".sprNew", StringComparison.InvariantCultureIgnoreCase) == false)) { // Still shows the selected even if we tell it to hide sprite duplicates so as not to break an existing selection - if (_contentType.IconUrl.Equals(iconClass, StringComparison.InvariantCultureIgnoreCase) == false - && UmbracoSettings.IconPickerBehaviour == IconPickerBehaviour.HideSpriteDuplicates + if (_contentType.IconUrl.Equals(iconClass, StringComparison.InvariantCultureIgnoreCase) == false + && UmbracoSettings.IconPickerBehaviour == IconPickerBehaviour.HideSpriteDuplicates && diskFileNames.Contains(IconClassToIconFileName(iconClass))) continue; @@ -296,7 +385,7 @@ jQuery(document).ready(function() {{ refreshDropDowns(); }}); #region "Structure" Pane - private void setupStructurePane() + private void SetupStructurePane() { dualAllowedContentTypes.ID = "allowedContentTypes"; dualAllowedContentTypes.Width = 175; @@ -347,7 +436,7 @@ jQuery(document).ready(function() {{ refreshDropDowns(); }}); #endregion #region "Generic properties" Pane - private void setupGenericPropertiesPane() + private void SetupGenericPropertiesPane() { GenericPropertiesTabPage = TabView1.NewTabPage("Generic properties"); GenericPropertiesTabPage.Style.Add("text-align", "center"); @@ -358,7 +447,7 @@ jQuery(document).ready(function() {{ refreshDropDowns(); }}); Save.ImageUrl = UmbracoPath + "/images/editor/save.gif"; //dlTabs.ItemCommand += new DataListCommandEventHandler(dlTabs_ItemCommand); - bindDataGenericProperties(false); + BindDataGenericProperties(false); } protected void dgTabs_itemdatabound(object sender, DataGridItemEventArgs e) @@ -372,7 +461,7 @@ jQuery(document).ready(function() {{ refreshDropDowns(); }}); } } - private void bindDataGenericProperties(bool Refresh) + private void BindDataGenericProperties(bool Refresh) { cms.businesslogic.ContentType.TabI[] tabs = _contentType.getVirtualTabs; cms.businesslogic.datatype.DataTypeDefinition[] dtds = cms.businesslogic.datatype.DataTypeDefinition.GetAll(); @@ -480,14 +569,14 @@ jQuery(document).ready(function() {{ refreshDropDowns(); }}); if (!hasProperties) { - addNoPropertiesDefinedMessage(); + AddNoPropertiesDefinedMessage(); } PropertyTypes.Controls.Add(new LiteralControl("")); } else { - addNoPropertiesDefinedMessage(); + AddNoPropertiesDefinedMessage(); PropertyTypes.Controls.Add(new LiteralControl("")); } } @@ -565,7 +654,7 @@ jQuery(document).ready(function() {{ refreshDropDowns(); }}); } - private void addNoPropertiesDefinedMessage() + private void AddNoPropertiesDefinedMessage() { PropertyTypes.Controls.Add(new LiteralControl("
No properties defined on this tab. Click on the \"add a new property\" link at the top to create a new property.
")); } @@ -575,92 +664,17 @@ jQuery(document).ready(function() {{ refreshDropDowns(); }}); GenericProperties.GenericPropertyWrapper gpw = (GenericProperties.GenericPropertyWrapper)sender; gpw.GenricPropertyControl.PropertyType.delete(); _contentType = ContentType.GetContentType(_contentType.Id); - this.bindDataGenericProperties(true); + this.BindDataGenericProperties(true); } - - - private void _old_bindDataGenericProperties() - { - - // Data bind create new - gp.GenricPropertyControl.Tabs = _contentType.getVirtualTabs; - gp.GenricPropertyControl.DataTypeDefinitions = cms.businesslogic.datatype.DataTypeDefinition.GetAll(); - - DataSet ds = new DataSet(); - - DataTable dtP = new DataTable("Properties"); - DataTable dtT = new DataTable("Tabs"); - - ds.Tables.Add(dtP); - ds.Tables.Add(dtT); - - dtP.Columns.Add("id"); - dtP.Columns.Add("tabid"); - dtP.Columns.Add("alias"); - dtP.Columns.Add("name"); - dtP.Columns.Add("type"); - dtP.Columns.Add("tab"); - - dtT.Columns.Add("tabid"); - dtT.Columns.Add("TabName"); - dtT.Columns.Add("genericProperties"); - - Hashtable inTab = new Hashtable(); - foreach (cms.businesslogic.ContentType.TabI tb in _contentType.getVirtualTabs.ToList()) - { - DataRow dr = dtT.NewRow(); - dr["TabName"] = tb.GetRawCaption(); - dr["tabid"] = tb.Id; - dtT.Rows.Add(dr); - - // zb-00036 #29889 : fix property types getter - foreach (cms.businesslogic.propertytype.PropertyType pt in tb.GetPropertyTypes(_contentType.Id)) - { - DataRow dr1 = dtP.NewRow(); - dr1["alias"] = pt.Alias; - dr1["tabid"] = tb.Id; - dr1["name"] = pt.GetRawName(); - dr1["type"] = pt.DataTypeDefinition.Id; - dr1["tab"] = tb.GetRawCaption(); - dr1["id"] = pt.Id.ToString(); - dtP.Rows.Add(dr1); - inTab.Add(pt.Id.ToString(), true); - } - } - - DataRow dr2 = dtT.NewRow(); - dr2["TabName"] = "General properties"; - dr2["tabid"] = 0; - dtT.Rows.Add(dr2); - - foreach (cms.businesslogic.propertytype.PropertyType pt in _contentType.PropertyTypes) - { - if (!inTab.ContainsKey(pt.Id.ToString())) - { - DataRow dr1 = dtP.NewRow(); - dr1["alias"] = pt.Alias; - dr1["tabid"] = 0; - dr1["name"] = pt.GetRawName(); - dr1["type"] = pt.DataTypeDefinition.Id; - dr1["tab"] = "General properties"; - dr1["id"] = pt.Id.ToString(); - dtP.Rows.Add(dr1); - } - } - - - ds.Relations.Add(new DataRelation("tabidrelation", dtT.Columns["tabid"], dtP.Columns["tabid"], false)); - } - - - private void saveProperties(ref SaveClickEventArgs e) + + private void SaveProperties(SaveClickEventArgs e) { this.CreateChildControls(); GenericProperties.GenericProperty gpData = gp.GenricPropertyControl; if (gpData.Name.Trim() != "" && gpData.Alias.Trim() != "") { - if (doesPropertyTypeAliasExist(gpData)) + if (DoesPropertyTypeAliasExist(gpData)) { string[] info = { gpData.Name, gpData.Type.ToString() }; cms.businesslogic.propertytype.PropertyType pt = _contentType.AddPropertyType(cms.businesslogic.datatype.DataTypeDefinition.GetDataTypeDefinition(gpData.Type), Casing.SafeAliasWithForcingCheck(gpData.Alias.Trim()), gpData.Name); @@ -678,7 +692,7 @@ jQuery(document).ready(function() {{ refreshDropDowns(); }}); } else { - e.Message = ui.Text("contentTypeDublicatePropertyType"); + e.Message = ui.Text("contentTypeDublicatePropertyType", CurrentUser); e.IconType = umbraco.BasePages.BasePage.speechBubbleIcon.warning; } } @@ -722,7 +736,7 @@ jQuery(document).ready(function() {{ refreshDropDowns(); }}); } } - private bool doesPropertyTypeAliasExist(GenericProperty gpData) + private bool DoesPropertyTypeAliasExist(GenericProperty gpData) { bool hasAlias = _contentType.getPropertyType(Casing.SafeAliasWithForcingCheck(gpData.Alias.Trim())) != null; ContentType ct = _contentType; @@ -738,41 +752,7 @@ jQuery(document).ready(function() {{ refreshDropDowns(); }}); { return (dv.Count == 0); } - private void dlTabs_ItemCommand(object source, DataListCommandEventArgs e) - { - if (e.CommandName == "Delete") - { - _contentType.DeleteVirtualTab(int.Parse(e.CommandArgument.ToString())); - } - - if (e.CommandName == "MoveDown") - { - int TabId = int.Parse(e.CommandArgument.ToString()); - foreach (cms.businesslogic.ContentType.TabI t in _contentType.getVirtualTabs.ToList()) - { - if (t.Id == TabId) - { - t.MoveDown(); - } - } - } - - if (e.CommandName == "MoveUp") - { - int TabId = int.Parse(e.CommandArgument.ToString()); - foreach (cms.businesslogic.ContentType.TabI t in _contentType.getVirtualTabs.ToList()) - { - if (t.Id == TabId) - { - t.MoveUp(); - } - } - } - bindTabs(); - bindDataGenericProperties(false); - } - - + protected void dgGenericPropertiesOfTab_itemcommand(object sender, DataGridCommandEventArgs e) { // Delete propertytype from contenttype @@ -780,9 +760,9 @@ jQuery(document).ready(function() {{ refreshDropDowns(); }}); { int propertyId = int.Parse(e.Item.Cells[0].Text); cms.businesslogic.propertytype.PropertyType pt = cms.businesslogic.propertytype.PropertyType.GetPropertyType(propertyId); - RaiseBubbleEvent(new object(), new SaveClickEventArgs("Property ´" + pt.GetRawName() + "´ deleted")); + RaiseBubbleEvent(new object(), new SaveClickEventArgs("Property ´" + pt.GetRawName() + "´ deleted")); pt.delete(); - bindDataGenericProperties(false); + BindDataGenericProperties(false); } } @@ -800,7 +780,7 @@ jQuery(document).ready(function() {{ refreshDropDowns(); }}); #endregion #region "Tab" Pane - private void setupTabPane() + private void SetupTabPane() { uicontrols.TabPage tp = TabView1.NewTabPage("Tabs"); @@ -811,10 +791,10 @@ jQuery(document).ready(function() {{ refreshDropDowns(); }}); Save.Click += new System.Web.UI.ImageClickEventHandler(save_click); Save.ID = "SaveButton"; Save.ImageUrl = UmbracoPath + "/images/editor/save.gif"; - bindTabs(); + BindTabs(); } - private void bindTabs() + private void BindTabs() { DataTable dt = new DataTable(); dt.Columns.Add("name"); @@ -851,7 +831,7 @@ jQuery(document).ready(function() {{ refreshDropDowns(); }}); get { if (dgTabs.DataSource == null) - bindTabs(); + BindTabs(); DataTable dt = new DataTable(); dt.Columns.Add("name"); @@ -874,26 +854,26 @@ jQuery(document).ready(function() {{ refreshDropDowns(); }}); } } - private DataTable _DataTypeTable; + private DataTable _dataTypeTable; public DataTable DataTypeTable { get { - if (_DataTypeTable == null) + if (_dataTypeTable == null) { - _DataTypeTable = new DataTable(); - _DataTypeTable.Columns.Add("name"); - _DataTypeTable.Columns.Add("id"); + _dataTypeTable = new DataTable(); + _dataTypeTable.Columns.Add("name"); + _dataTypeTable.Columns.Add("id"); foreach (cms.businesslogic.datatype.DataTypeDefinition DataType in cms.businesslogic.datatype.DataTypeDefinition.GetAll()) { - DataRow dr = _DataTypeTable.NewRow(); + DataRow dr = _dataTypeTable.NewRow(); dr["name"] = DataType.Text; dr["id"] = DataType.Id.ToString(); - _DataTypeTable.Rows.Add(dr); + _dataTypeTable.Rows.Add(dr); } } - return _DataTypeTable; + return _dataTypeTable; } } @@ -904,14 +884,14 @@ jQuery(document).ready(function() {{ refreshDropDowns(); }}); { _contentType.AddVirtualTab(txtNewTab.Text); _contentType = new ContentType(_contentType.Id); - SaveClickEventArgs ea = new SaveClickEventArgs(ui.Text("contentTypeTabCreated")); + SaveClickEventArgs ea = new SaveClickEventArgs(ui.Text("contentTypeTabCreated", CurrentUser)); ea.IconType = umbraco.BasePages.BasePage.speechBubbleIcon.success; RaiseBubbleEvent(new object(), ea); txtNewTab.Text = ""; - bindTabs(); - bindDataGenericProperties(true); + BindTabs(); + BindDataGenericProperties(true); } Page.ClientScript.RegisterStartupScript(this.GetType(), "dropDowns", @" @@ -927,7 +907,7 @@ Umbraco.Controls.TabView.onActiveTabChange(function(tabviewid, tabid, tabs) { { _contentType.DeleteVirtualTab(int.Parse(e.Item.Cells[0].Text)); - SaveClickEventArgs ea = new SaveClickEventArgs(ui.Text("contentTypeTabDeleted")); + SaveClickEventArgs ea = new SaveClickEventArgs(ui.Text("contentTypeTabDeleted", CurrentUser)); ea.IconType = umbraco.BasePages.BasePage.speechBubbleIcon.success; RaiseBubbleEvent(new object(), ea); @@ -935,8 +915,8 @@ Umbraco.Controls.TabView.onActiveTabChange(function(tabviewid, tabid, tabs) { } - bindTabs(); - bindDataGenericProperties(true); + BindTabs(); + BindDataGenericProperties(true); } @@ -959,5 +939,338 @@ Umbraco.Controls.TabView.onActiveTabChange(function(tabviewid, tabid, tabs) { #endregion + /// + /// TabView1 control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::umbraco.uicontrols.TabView TabView1; + + /// + /// pnlGeneral control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.WebControls.Panel pnlGeneral; + + /// + /// pnlTab control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.WebControls.Panel pnlTab; + + /// + /// PaneTabsInherited control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::umbraco.uicontrols.Pane PaneTabsInherited; + + /// + /// tabsMasterContentTypeName control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.WebControls.Literal tabsMasterContentTypeName; + + /// + /// Pane2 control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::umbraco.uicontrols.Pane Pane2; + + /// + /// pp_newTab control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::umbraco.uicontrols.PropertyPanel pp_newTab; + + /// + /// txtNewTab control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.WebControls.TextBox txtNewTab; + + /// + /// btnNewTab control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.WebControls.Button btnNewTab; + + /// + /// Pane1 control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::umbraco.uicontrols.Pane Pane1; + + /// + /// dgTabs control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.WebControls.DataGrid dgTabs; + + /// + /// lttNoTabs control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.WebControls.Literal lttNoTabs; + + /// + /// pnlInfo control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.WebControls.Panel pnlInfo; + + /// + /// Pane3 control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::umbraco.uicontrols.Pane Pane3; + + /// + /// pp_name control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::umbraco.uicontrols.PropertyPanel pp_name; + + /// + /// txtName control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.WebControls.TextBox txtName; + + /// + /// RequiredFieldValidator1 control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.WebControls.RequiredFieldValidator RequiredFieldValidator1; + + /// + /// pp_alias control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::umbraco.uicontrols.PropertyPanel pp_alias; + + /// + /// txtAlias control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.WebControls.TextBox txtAlias; + + /// + /// pp_icon control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::umbraco.uicontrols.PropertyPanel pp_icon; + + /// + /// ddlIcons control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.WebControls.DropDownList ddlIcons; + + /// + /// pp_thumbnail control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::umbraco.uicontrols.PropertyPanel pp_thumbnail; + + /// + /// ddlThumbnails control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.WebControls.DropDownList ddlThumbnails; + + /// + /// pp_description control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::umbraco.uicontrols.PropertyPanel pp_description; + + /// + /// description control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.WebControls.TextBox description; + + /// + /// pnlStructure control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.WebControls.Panel pnlStructure; + + /// + /// Pane5 control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::umbraco.uicontrols.Pane Pane5; + + /// + /// pp_allowedChildren control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::umbraco.uicontrols.PropertyPanel pp_allowedChildren; + + /// + /// lstAllowedContentTypes control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.WebControls.CheckBoxList lstAllowedContentTypes; + + /// + /// PlaceHolderAllowedContentTypes control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.WebControls.PlaceHolder PlaceHolderAllowedContentTypes; + + /// + /// pnlProperties control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.WebControls.Panel pnlProperties; + + /// + /// PanePropertiesInherited control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::umbraco.uicontrols.Pane PanePropertiesInherited; + + /// + /// propertiesMasterContentTypeName control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.WebControls.Literal propertiesMasterContentTypeName; + + /// + /// Pane4 control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::umbraco.uicontrols.Pane Pane4; + + /// + /// PropertyTypeNew control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.WebControls.PlaceHolder PropertyTypeNew; + + /// + /// PropertyTypes control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.WebControls.PlaceHolder PropertyTypes; + + /// + /// theClientId control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.WebControls.Literal theClientId; + } } \ No newline at end of file diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/controls/ContentTypeControlNew.ascx.designer.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/controls/ContentTypeControlNew.ascx.designer.cs deleted file mode 100644 index bc732a166a..0000000000 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/controls/ContentTypeControlNew.ascx.designer.cs +++ /dev/null @@ -1,348 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace umbraco.controls { - - - public partial class ContentTypeControlNew { - - /// - /// TabView1 control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::umbraco.uicontrols.TabView TabView1; - - /// - /// pnlGeneral control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::System.Web.UI.WebControls.Panel pnlGeneral; - - /// - /// pnlTab control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::System.Web.UI.WebControls.Panel pnlTab; - - /// - /// PaneTabsInherited control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::umbraco.uicontrols.Pane PaneTabsInherited; - - /// - /// tabsMasterContentTypeName control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::System.Web.UI.WebControls.Literal tabsMasterContentTypeName; - - /// - /// Pane2 control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::umbraco.uicontrols.Pane Pane2; - - /// - /// pp_newTab control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::umbraco.uicontrols.PropertyPanel pp_newTab; - - /// - /// txtNewTab control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::System.Web.UI.WebControls.TextBox txtNewTab; - - /// - /// btnNewTab control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::System.Web.UI.WebControls.Button btnNewTab; - - /// - /// Pane1 control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::umbraco.uicontrols.Pane Pane1; - - /// - /// dgTabs control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::System.Web.UI.WebControls.DataGrid dgTabs; - - /// - /// lttNoTabs control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::System.Web.UI.WebControls.Literal lttNoTabs; - - /// - /// pnlInfo control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::System.Web.UI.WebControls.Panel pnlInfo; - - /// - /// Pane3 control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::umbraco.uicontrols.Pane Pane3; - - /// - /// pp_name control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::umbraco.uicontrols.PropertyPanel pp_name; - - /// - /// txtName control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::System.Web.UI.WebControls.TextBox txtName; - - /// - /// RequiredFieldValidator1 control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::System.Web.UI.WebControls.RequiredFieldValidator RequiredFieldValidator1; - - /// - /// pp_alias control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::umbraco.uicontrols.PropertyPanel pp_alias; - - /// - /// txtAlias control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::System.Web.UI.WebControls.TextBox txtAlias; - - /// - /// pp_icon control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::umbraco.uicontrols.PropertyPanel pp_icon; - - /// - /// ddlIcons control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::System.Web.UI.WebControls.DropDownList ddlIcons; - - /// - /// pp_thumbnail control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::umbraco.uicontrols.PropertyPanel pp_thumbnail; - - /// - /// ddlThumbnails control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::System.Web.UI.WebControls.DropDownList ddlThumbnails; - - /// - /// pp_description control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::umbraco.uicontrols.PropertyPanel pp_description; - - /// - /// description control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::System.Web.UI.WebControls.TextBox description; - - /// - /// pnlStructure control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::System.Web.UI.WebControls.Panel pnlStructure; - - /// - /// Pane5 control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::umbraco.uicontrols.Pane Pane5; - - /// - /// pp_allowedChildren control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::umbraco.uicontrols.PropertyPanel pp_allowedChildren; - - /// - /// lstAllowedContentTypes control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::System.Web.UI.WebControls.CheckBoxList lstAllowedContentTypes; - - /// - /// PlaceHolderAllowedContentTypes control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::System.Web.UI.WebControls.PlaceHolder PlaceHolderAllowedContentTypes; - - /// - /// pnlProperties control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::System.Web.UI.WebControls.Panel pnlProperties; - - /// - /// PanePropertiesInherited control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::umbraco.uicontrols.Pane PanePropertiesInherited; - - /// - /// propertiesMasterContentTypeName control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::System.Web.UI.WebControls.Literal propertiesMasterContentTypeName; - - /// - /// Pane4 control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::umbraco.uicontrols.Pane Pane4; - - /// - /// PropertyTypeNew control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::System.Web.UI.WebControls.PlaceHolder PropertyTypeNew; - - /// - /// PropertyTypes control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::System.Web.UI.WebControls.PlaceHolder PropertyTypes; - - /// - /// theClientId control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::System.Web.UI.WebControls.Literal theClientId; - } -} diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/controls/GenericProperties/GenericProperty.ascx.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/controls/GenericProperties/GenericProperty.ascx.cs index 1e9ccb0a45..f8cfb11234 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/controls/GenericProperties/GenericProperty.ascx.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/controls/GenericProperties/GenericProperty.ascx.cs @@ -1,8 +1,9 @@ using System; using System.Web.UI.WebControls; using ClientDependency.Core; +using Umbraco.Core.IO; using umbraco.BasePages; -using umbraco.IO; +using umbraco.BusinessLogic; namespace umbraco.controls.GenericProperties { @@ -134,6 +135,22 @@ namespace umbraco.controls.GenericProperties } + //SD: this is temporary in v4, in v6 we have a proper user control hierarchy + //containing this property. + //this is required due to this issue: http://issues.umbraco.org/issue/u4-493 + //because we need to execute some code in async but due to the localization + //framework requiring an httpcontext.current, it will not work. + //http://issues.umbraco.org/issue/u4-2143 + //so, we are going to make a property here and ensure that the basepage has + //resolved the user before we execute the async task so that in this method + //our calls to ui.text will include the current user and not rely on the + //httpcontext.current. This also makes it perform better: + // http://issues.umbraco.org/issue/U4-2142 + private User CurrentUser + { + get { return ((BasePage) Page).getUser(); } + } + public void UpdateInterface() { // Name and alias @@ -148,11 +165,11 @@ namespace umbraco.controls.GenericProperties DeleteButton.Visible = true; DeleteButton.ImageUrl = SystemDirectories.Umbraco + "/images/delete_button.png"; DeleteButton.Attributes.Add("style", "float: right; cursor: hand;"); - DeleteButton.Attributes.Add("onclick", "return confirm('" + ui.Text("areyousure") + "');"); + DeleteButton.Attributes.Add("onclick", "return confirm('" + ui.Text("areyousure", CurrentUser) + "');"); DeleteButton2.Visible = true; DeleteButton2.ImageUrl = SystemDirectories.Umbraco + "/images/delete_button.png"; DeleteButton2.Attributes.Add("style", "float: right; cursor: hand;"); - DeleteButton2.Attributes.Add("onclick", "return confirm('" + ui.Text("areyousure") + "');"); + DeleteButton2.Attributes.Add("onclick", "return confirm('" + ui.Text("areyousure", CurrentUser) + "');"); } else { diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/settings/EditNodeTypeNew.aspx b/src/Umbraco.Web/umbraco.presentation/umbraco/settings/EditNodeTypeNew.aspx deleted file mode 100644 index 73975e64f2..0000000000 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/settings/EditNodeTypeNew.aspx +++ /dev/null @@ -1,58 +0,0 @@ -<%@ Page Language="c#" CodeBehind="EditNodeTypeNew.aspx.cs" AutoEventWireup="True" - Trace="false" Inherits="umbraco.settings.EditContentTypeNew" MasterPageFile="../masterpages/umbracoPage.Master" %> - -<%@ Register TagPrefix="cc1" Namespace="umbraco.uicontrols" Assembly="controls" %> -<%@ Register TagPrefix="uc1" TagName="ContentTypeControlNew" Src="../controls/ContentTypeControlNew.ascx" %> - - - - - - - - - -
- -
-
- - - -
- -
diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/settings/EditNodeTypeNew.aspx.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/settings/EditNodeTypeNew.aspx.cs index 0c3be42e00..8b9c8871b5 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/settings/EditNodeTypeNew.aspx.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/settings/EditNodeTypeNew.aspx.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections; using System.ComponentModel; using System.Data; @@ -24,11 +24,8 @@ namespace umbraco.settings } protected controls.ContentTypeControlNew ContentTypeControlNew1; - cms.businesslogic.web.DocumentType dt; - - - private DataTable dtTemplates = new DataTable(); - + DocumentType _dt; + override protected void OnInit(EventArgs e) { ContentTypeControlNew1.InfoTabPage.Controls.Add(tmpPane); @@ -37,25 +34,24 @@ namespace umbraco.settings protected void Page_Load(object sender, System.EventArgs e) { - dt = new DocumentType(int.Parse(Request.QueryString["id"])); + _dt = new DocumentType(int.Parse(Request.QueryString["id"])); if (!Page.IsPostBack) { - bindTemplates(); + BindTemplates(); ClientTools .SetActiveTreeType(TreeDefinitionCollection.Instance.FindTree().Tree.Alias) - .SyncTree("-1,init," + dt.Path.Replace("-1,", ""), false); + .SyncTree("-1,init," + _dt.Path.Replace("-1,", ""), false); } } - - private void bindTemplates() + private void BindTemplates() { var templates = (from t in cms.businesslogic.template.Template.GetAllAsList() - join at in dt.allowedTemplates on t.Id equals at.Id into at_l + join at in _dt.allowedTemplates on t.Id equals at.Id into at_l from at in at_l.DefaultIfEmpty() select new { @@ -77,7 +73,7 @@ namespace umbraco.settings ddlTemplates.Enabled = templates.Any(); ddlTemplates.Items.Clear(); - ddlTemplates.Items.Insert(0, new ListItem(ui.Text("choose") + "...", "0")); + ddlTemplates.Items.Insert(0, new ListItem(ui.Text("choose", getUser()) + "...", "0")); ddlTemplates.Items.AddRange(templates.ConvertAll(item => { ListItem li = new ListItem(); @@ -86,7 +82,7 @@ namespace umbraco.settings return li; }).ToArray()); - var ddlTemplatesSelect = ddlTemplates.Items.FindByValue(dt.DefaultTemplate.ToString()); + var ddlTemplatesSelect = ddlTemplates.Items.FindByValue(_dt.DefaultTemplate.ToString()); if (ddlTemplatesSelect != null) ddlTemplatesSelect.Selected = true; } @@ -96,39 +92,39 @@ namespace umbraco.settings bool handled = false; if (args is controls.SaveClickEventArgs) { - controls.SaveClickEventArgs e = (controls.SaveClickEventArgs)args; + var e = (controls.SaveClickEventArgs)args; if (e.Message == "Saved") { int dtid = 0; if (int.TryParse(Request.QueryString["id"], out dtid)) new cms.businesslogic.web.DocumentType(dtid).Save(); - ClientTools.ShowSpeechBubble(e.IconType, ui.Text("contentTypeSavedHeader"), ""); + ClientTools.ShowSpeechBubble(e.IconType, ui.Text("contentTypeSavedHeader", getUser()), ""); - ArrayList tmp = new ArrayList(); + var tmp = new ArrayList(); foreach (ListItem li in templateList.Items) { if (li.Selected) tmp.Add(new cms.businesslogic.template.Template(int.Parse(li.Value))); } - cms.businesslogic.template.Template[] tt = new cms.businesslogic.template.Template[tmp.Count]; + var tt = new cms.businesslogic.template.Template[tmp.Count]; for (int i = 0; i < tt.Length; i++) { tt[i] = (cms.businesslogic.template.Template)tmp[i]; } - dt.allowedTemplates = tt; + _dt.allowedTemplates = tt; - if (dt.allowedTemplates.Length > 0 && ddlTemplates.SelectedIndex >= 0) + if (_dt.allowedTemplates.Length > 0 && ddlTemplates.SelectedIndex >= 0) { - dt.DefaultTemplate = int.Parse(ddlTemplates.SelectedValue); + _dt.DefaultTemplate = int.Parse(ddlTemplates.SelectedValue); } else - dt.RemoveDefaultTemplate(); + _dt.RemoveDefaultTemplate(); - bindTemplates(); + BindTemplates(); } else { @@ -147,6 +143,31 @@ namespace umbraco.settings } } + /// + /// tmpPane control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::umbraco.uicontrols.Pane tmpPane; + /// + /// templateList control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.WebControls.CheckBoxList templateList; + + /// + /// ddlTemplates control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.WebControls.DropDownList ddlTemplates; } } diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/settings/EditNodeTypeNew.aspx.designer.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/settings/EditNodeTypeNew.aspx.designer.cs deleted file mode 100644 index 19f03326bd..0000000000 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/settings/EditNodeTypeNew.aspx.designer.cs +++ /dev/null @@ -1,42 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace umbraco.settings { - - - public partial class EditContentTypeNew { - - /// - /// tmpPane control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::umbraco.uicontrols.Pane tmpPane; - - /// - /// templateList control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::System.Web.UI.WebControls.CheckBoxList templateList; - - /// - /// ddlTemplates control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::System.Web.UI.WebControls.DropDownList ddlTemplates; - } -} diff --git a/src/umbraco.cms/businesslogic/web/Document.cs b/src/umbraco.cms/businesslogic/web/Document.cs index b006f220f1..c9412a2fc5 100644 --- a/src/umbraco.cms/businesslogic/web/Document.cs +++ b/src/umbraco.cms/businesslogic/web/Document.cs @@ -3,6 +3,7 @@ using System.Collections; using System.Collections.Generic; using System.Linq; using System.Runtime.CompilerServices; +using System.Threading; using System.Web; using System.Xml; using Umbraco.Core.IO; @@ -627,7 +628,7 @@ order by {1} return tmp; } - + [MethodImpl(MethodImplOptions.Synchronized)] public static void RePublishAll() { XmlDocument xd = new XmlDocument(); From 8416764a830c36ba6eca1c9394a3cc5fb03df916 Mon Sep 17 00:00:00 2001 From: Shannon Deminick Date: Tue, 23 Apr 2013 20:01:26 -1000 Subject: [PATCH 16/19] removed the trace from the page --- src/Umbraco.Web.UI/umbraco/settings/EditNodeTypeNew.aspx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI/umbraco/settings/EditNodeTypeNew.aspx b/src/Umbraco.Web.UI/umbraco/settings/EditNodeTypeNew.aspx index 2199af68c6..cdda810a57 100644 --- a/src/Umbraco.Web.UI/umbraco/settings/EditNodeTypeNew.aspx +++ b/src/Umbraco.Web.UI/umbraco/settings/EditNodeTypeNew.aspx @@ -1,5 +1,5 @@ <%@ Page Language="c#" CodeBehind="EditNodeTypeNew.aspx.cs" AutoEventWireup="True" - Async="true" AsyncTimeOut="300" Trace="true" Inherits="Umbraco.Web.UI.Umbraco.Settings.EditNodeTypeNew" MasterPageFile="../masterpages/umbracoPage.Master" %> + Async="true" AsyncTimeOut="300" Trace="false" Inherits="Umbraco.Web.UI.Umbraco.Settings.EditNodeTypeNew" MasterPageFile="../masterpages/umbracoPage.Master" %> <%@ Register TagPrefix="cc1" Namespace="umbraco.uicontrols" Assembly="controls" %> <%@ Register TagPrefix="uc1" TagName="ContentTypeControlNew" Src="../controls/ContentTypeControlNew.ascx" %> From 52163494db26bdc6dce7281d8bed404b010010c6 Mon Sep 17 00:00:00 2001 From: Shannon Deminick Date: Tue, 23 Apr 2013 20:19:48 -1000 Subject: [PATCH 17/19] changed the async state object to be a custom class to hold the original values of alias/text --- .../controls/ContentTypeControlNew.ascx.cs | 64 +++++++++++-------- 1 file changed, 39 insertions(+), 25 deletions(-) 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 7ebbc278c7..1b879b8665 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/controls/ContentTypeControlNew.ascx.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/controls/ContentTypeControlNew.ascx.cs @@ -59,7 +59,7 @@ namespace umbraco.controls protected System.Web.UI.WebControls.DataGrid dgGeneralTabProperties; //the async saving task - private Action _asyncSaveTask; + private Action _asyncSaveTask; override protected void OnInit(EventArgs e) { @@ -123,6 +123,31 @@ namespace umbraco.controls get { return ((BasePage)Page).getUser(); } } + /// + /// A class to track the async state for saving the doc type + /// + private class SaveAsyncState + { + public SaveAsyncState(SaveClickEventArgs saveArgs, string originalAlias, string originalName) + { + SaveArgs = saveArgs; + OriginalAlias = originalAlias; + OriginalName = originalName; + } + + public SaveClickEventArgs SaveArgs { get; private set; } + public string OriginalAlias { get; private set; } + public string OriginalName { get; private set; } + public bool HasAliasChanged(ContentType contentType) + { + return (string.Compare(OriginalAlias, contentType.Alias, StringComparison.OrdinalIgnoreCase) != 0); + } + public bool HasNameChanged(ContentType contentType) + { + return (string.Compare(OriginalName, contentType.Text, StringComparison.OrdinalIgnoreCase) != 0); + } + } + /// /// Called asynchronously in order to persist all of the data to the database /// @@ -140,7 +165,7 @@ namespace umbraco.controls Trace.Write("ContentTypeControlNew", "Start async operation"); //get the args from the async state - var args = (SaveClickEventArgs)state; + var args = (SaveAsyncState)state; //start the task var result = _asyncSaveTask.BeginInvoke(args, cb, args); @@ -159,19 +184,16 @@ namespace umbraco.controls Trace.Write("ContentTypeControlNew", "ending async operation"); //get the args from the async state - var args = (SaveClickEventArgs)ar.AsyncState; - - var originalDocTypeName = _contentType.Text; - var docTypeNameChanged = (string.Compare(originalDocTypeName, _contentType.Text, StringComparison.OrdinalIgnoreCase) != 0); + var state = (SaveAsyncState)ar.AsyncState; BindDataGenericProperties(true); // we need to re-bind the alias as the SafeAlias method can have changed it txtAlias.Text = _contentType.Alias; - RaiseBubbleEvent(new object(), args); + RaiseBubbleEvent(new object(), state.SaveArgs); - if (docTypeNameChanged) + if (state.HasNameChanged(_contentType)) UpdateTreeNode(); Trace.Write("ContentTypeControlNew", "async operation ended"); @@ -193,30 +215,26 @@ namespace umbraco.controls protected void save_click(object sender, System.Web.UI.ImageClickEventArgs e) { - //event args to be passed in to the async method - var eventArgs = new SaveClickEventArgs("Saved") - { - IconType = BasePage.speechBubbleIcon.success - }; + var state = new SaveAsyncState(new SaveClickEventArgs("Saved") + { + IconType = BasePage.speechBubbleIcon.success + }, _contentType.Alias, _contentType.Text); //Add the async operation to the page - Page.RegisterAsyncTask(new PageAsyncTask(BeginAsyncSaveOperation, EndAsyncSaveOperation, HandleAsyncSaveTimeout, eventArgs)); + Page.RegisterAsyncTask(new PageAsyncTask(BeginAsyncSaveOperation, EndAsyncSaveOperation, HandleAsyncSaveTimeout, state)); //create the save task to be executed async - _asyncSaveTask = args => + _asyncSaveTask = asyncState => { Trace.Write("ContentTypeControlNew", "executing task"); - // Keep a reference of the original doctype alias and name - var originalDocTypeAlias = _contentType.Alias; - _contentType.Text = txtName.Text; _contentType.Alias = txtAlias.Text; _contentType.IconUrl = ddlIcons.SelectedValue; _contentType.Description = description.Text; _contentType.Thumbnail = ddlThumbnails.SelectedValue; - SaveProperties(args); + SaveProperties(asyncState.SaveArgs); SaveTabs(); @@ -224,14 +242,10 @@ namespace umbraco.controls // reload content type (due to caching) _contentType = new ContentType(_contentType.Id); - - // Check if the doctype alias has changed as a result of either the user input or - // the alias checking performed upon saving - var docTypeAliasChanged = (string.Compare(originalDocTypeAlias, _contentType.Alias, StringComparison.OrdinalIgnoreCase) != 0); - + // 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 (docTypeAliasChanged) + if (asyncState.HasAliasChanged(_contentType)) RegenerateXmlCaches(); Trace.Write("ContentTypeControlNew", "task completing"); From 1e0a4690fc570a0b7a9348b9235c00ed600d96fb Mon Sep 17 00:00:00 2001 From: Shannon Deminick Date: Tue, 23 Apr 2013 20:31:32 -1000 Subject: [PATCH 18/19] Added an error log if timed out --- .../umbraco/controls/ContentTypeControlNew.ascx.cs | 6 ++++++ 1 file changed, 6 insertions(+) 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 1b879b8665..638a7eb7f6 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/controls/ContentTypeControlNew.ascx.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/controls/ContentTypeControlNew.ascx.cs @@ -11,6 +11,7 @@ using System.Web.UI.HtmlControls; using System.Web.UI.WebControls; using ClientDependency.Core; using Umbraco.Core; +using Umbraco.Core.Logging; using umbraco.BusinessLogic; using umbraco.cms.helpers; using umbraco.cms.presentation.Trees; @@ -205,6 +206,11 @@ namespace umbraco.controls private void HandleAsyncSaveTimeout(IAsyncResult ar) { Trace.Write("ContentTypeControlNew", "async operation timed out!"); + + LogHelper.Error( + "The content type saving operation timed out", + new TimeoutException("The content type saving operation timed out. This could cause problems because the xml for the content node might not have been generated. ")); + } /// From 4bfb8569c8cc5700234663da061c187c55bc2aa8 Mon Sep 17 00:00:00 2001 From: Shannon Deminick Date: Tue, 23 Apr 2013 21:37:03 -1000 Subject: [PATCH 19/19] Fixed up merge issues --- .../umbraco/settings/views/EditView.aspx.cs | 3 +- .../controls/ContentTypeControlNew.ascx.cs | 204 ++++++++++-------- .../umbraco/create/MediaTypeTasks.cs | 6 +- .../umbraco/settings/EditNodeTypeNew.aspx.cs | 27 +++ src/umbraco.cms/businesslogic/web/Document.cs | 4 +- 5 files changed, 151 insertions(+), 93 deletions(-) diff --git a/src/Umbraco.Web.UI/umbraco/settings/views/EditView.aspx.cs b/src/Umbraco.Web.UI/umbraco/settings/views/EditView.aspx.cs index 0a184c9e04..9d6db3c41a 100644 --- a/src/Umbraco.Web.UI/umbraco/settings/views/EditView.aspx.cs +++ b/src/Umbraco.Web.UI/umbraco/settings/views/EditView.aspx.cs @@ -7,6 +7,7 @@ using System.Web.UI; using System.Web.UI.WebControls; using Umbraco.Core.IO; using Umbraco.Web.Trees; +using Umbraco.Web.UI.Controls; using umbraco; using umbraco.BasePages; using umbraco.cms.businesslogic.template; @@ -166,7 +167,7 @@ namespace Umbraco.Web.UI.Umbraco.Settings.Views 640, 550); umbDictionary.AltText = "Insert umbraco dictionary item"; - var macroSplitButton = new Controls.InsertMacroSplitButton + var macroSplitButton = new InsertMacroSplitButton { ClientCallbackInsertMacroMarkup = "function(alias) {editViewEditor.insertMacroMarkup(alias);}", ClientCallbackOpenMacroModel = "function(alias) {editViewEditor.openMacroModal(alias);}" 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 500f55c2a8..25285355c1 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/controls/ContentTypeControlNew.ascx.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/controls/ContentTypeControlNew.ascx.cs @@ -11,7 +11,9 @@ using System.Web.UI.HtmlControls; using System.Web.UI.WebControls; using ClientDependency.Core; using Umbraco.Core; +using Umbraco.Core.Logging; using Umbraco.Core.Models; +using umbraco.BusinessLogic; using umbraco.cms.businesslogic; using umbraco.cms.businesslogic.propertytype; using umbraco.cms.businesslogic.web; @@ -123,23 +125,33 @@ namespace umbraco.controls /// private class SaveAsyncState { - public SaveAsyncState(SaveClickEventArgs saveArgs, string originalAlias, string originalName) + public SaveAsyncState( + SaveClickEventArgs saveArgs, + string originalAlias, + string originalName, + string newAlias, + string newName) { SaveArgs = saveArgs; OriginalAlias = originalAlias; OriginalName = originalName; + NewAlias = newAlias; + NewName = newName; } public SaveClickEventArgs SaveArgs { get; private set; } public string OriginalAlias { get; private set; } public string OriginalName { get; private set; } - public bool HasAliasChanged(ContentType contentType) + public string NewAlias { get; private set; } + public string NewName { get; private set; } + + public bool HasAliasChanged() { - return (string.Compare(OriginalAlias, contentType.Alias, StringComparison.OrdinalIgnoreCase) != 0); + return (string.Compare(OriginalAlias, NewAlias, StringComparison.OrdinalIgnoreCase) != 0); } - public bool HasNameChanged(ContentType contentType) + public bool HasNameChanged() { - return (string.Compare(OriginalName, contentType.Text, StringComparison.OrdinalIgnoreCase) != 0); + return (string.Compare(OriginalName, NewName, StringComparison.OrdinalIgnoreCase) != 0); } } @@ -181,6 +193,9 @@ namespace umbraco.controls //get the args from the async state var state = (SaveAsyncState)ar.AsyncState; + // reload content type (due to caching) + LoadContentType(); + BindTabs(); BindDataGenericProperties(true); // we need to re-bind the alias as the SafeAlias method can have changed it @@ -188,7 +203,7 @@ namespace umbraco.controls RaiseBubbleEvent(new object(), state.SaveArgs); - if (state.HasNameChanged(_contentType)) + if (state.HasNameChanged()) UpdateTreeNode(); Trace.Write("ContentTypeControlNew", "async operation ended"); @@ -212,13 +227,13 @@ namespace umbraco.controls ///
/// /// - protected void save_click(object sender, System.Web.UI.ImageClickEventArgs e) + protected void save_click(object sender, ImageClickEventArgs e) { var state = new SaveAsyncState(new SaveClickEventArgs("Saved") { IconType = BasePage.speechBubbleIcon.success - }, _contentType.Alias, _contentType.Text); + }, _contentType.Alias, _contentType.Text, txtAlias.Text, txtName.Text); //Add the async operation to the page Page.RegisterAsyncTask(new PageAsyncTask(BeginAsyncSaveOperation, EndAsyncSaveOperation, HandleAsyncSaveTimeout, state)); @@ -228,88 +243,80 @@ namespace umbraco.controls { Trace.Write("ContentTypeControlNew", "executing task"); - // Check if the doctype alias has changed as a result of either the user input or - // the alias checking performed upon saving - var docTypeAliasChanged = (string.Compare(originalDocTypeAlias, txtAlias.Text, true) != 0); - var docTypeNameChanged = (string.Compare(originalDocTypeName, txtName.Text, true) != 0); - - var ea = new SaveClickEventArgs("Saved"); - ea.IconType = BasePage.speechBubbleIcon.success; - - //NOTE The saving of the 5 properties (Name, Alias, Icon, Description and Thumbnail) are divided - //to avoid the multiple cache flushing when each property is set using the legacy ContentType class, - //which has been reduced to the else-clause. - //For IContentType and IMediaType the cache will only be flushed upon saving. - if (_contentType.ContentTypeItem is IContentType || _contentType.ContentTypeItem is IMediaType) - { - _contentType.ContentTypeItem.Name = txtName.Text; - _contentType.ContentTypeItem.Alias = txtAlias.Text; - _contentType.ContentTypeItem.Icon = ddlIcons.SelectedValue; - _contentType.ContentTypeItem.Description = description.Text; - _contentType.ContentTypeItem.Thumbnail = ddlThumbnails.SelectedValue; - _contentType.ContentTypeItem.AllowedAsRoot = allowAtRoot.Checked; - - int i = 0; - var ids = SaveAllowedChildTypes(); - _contentType.ContentTypeItem.AllowedContentTypes = ids.Select(x => new ContentTypeSort { Id = new Lazy(() => x), SortOrder = i++ }); - - var tabs = SaveTabs(); - foreach (var tab in tabs) - { - if (_contentType.ContentTypeItem.PropertyGroups.Contains(tab.Item2)) + //NOTE The saving of the 5 properties (Name, Alias, Icon, Description and Thumbnail) are divided + //to avoid the multiple cache flushing when each property is set using the legacy ContentType class, + //which has been reduced to the else-clause. + //For IContentType and IMediaType the cache will only be flushed upon saving. + if (_contentType.ContentTypeItem is IContentType || _contentType.ContentTypeItem is IMediaType) { - _contentType.ContentTypeItem.PropertyGroups[tab.Item2].SortOrder = tab.Item3; + _contentType.ContentTypeItem.Name = txtName.Text; + _contentType.ContentTypeItem.Alias = txtAlias.Text; + _contentType.ContentTypeItem.Icon = ddlIcons.SelectedValue; + _contentType.ContentTypeItem.Description = description.Text; + _contentType.ContentTypeItem.Thumbnail = ddlThumbnails.SelectedValue; + _contentType.ContentTypeItem.AllowedAsRoot = allowAtRoot.Checked; + + int i = 0; + var ids = SaveAllowedChildTypes(); + _contentType.ContentTypeItem.AllowedContentTypes = ids.Select(x => new ContentTypeSort {Id = new Lazy(() => x), SortOrder = i++}); + + var tabs = SaveTabs(); + foreach (var tab in tabs) + { + if (_contentType.ContentTypeItem.PropertyGroups.Contains(tab.Item2)) + { + _contentType.ContentTypeItem.PropertyGroups[tab.Item2].SortOrder = tab.Item3; + } + else + { + _contentType.ContentTypeItem.PropertyGroups.Add(new PropertyGroup {Id = tab.Item1, Name = tab.Item2, SortOrder = tab.Item3}); + } + } + + SavePropertyType(asyncState.SaveArgs, _contentType.ContentTypeItem); + UpdatePropertyTypes(_contentType.ContentTypeItem); + + if (DocumentTypeCallback != null) + { + var documentType = _contentType as DocumentType; + if (documentType != null) + { + var result = DocumentTypeCallback(documentType); + } + } + + _contentType.Save(); } - else + else //Legacy approach for supporting MemberType { - _contentType.ContentTypeItem.PropertyGroups.Add(new PropertyGroup { Id = tab.Item1, Name = tab.Item2, SortOrder = tab.Item3 }); + if (asyncState.HasNameChanged()) + _contentType.Text = txtName.Text; + + if (asyncState.HasAliasChanged()) + _contentType.Alias = txtAlias.Text; + + _contentType.IconUrl = ddlIcons.SelectedValue; + _contentType.Description = description.Text; + _contentType.Thumbnail = ddlThumbnails.SelectedValue; + + SavePropertyTypesLegacy(asyncState.SaveArgs); + + var tabs = SaveTabs(); + foreach (var tab in tabs) + { + _contentType.SetTabName(tab.Item1, tab.Item2); + _contentType.SetTabSortOrder(tab.Item1, tab.Item3); + } + + _contentType.AllowedChildContentTypeIDs = SaveAllowedChildTypes(); + _contentType.AllowAtRoot = allowAtRoot.Checked; + + _contentType.Save(); } - } - SavePropertyType(ref ea, _contentType.ContentTypeItem); - UpdatePropertyTypes(_contentType.ContentTypeItem); - - if (DocumentTypeCallback != null) - { - var documentType = _contentType as DocumentType; - if (documentType != null) - { - var result = DocumentTypeCallback(documentType); - } - } - - _contentType.Save(); - } - else //Legacy approach for supporting MemberType - { - if (docTypeNameChanged) - _contentType.Text = txtName.Text; - - if (docTypeAliasChanged) - _contentType.Alias = txtAlias.Text; - - _contentType.IconUrl = ddlIcons.SelectedValue; - _contentType.Description = description.Text; - _contentType.Thumbnail = ddlThumbnails.SelectedValue; - - SavePropertyTypesLegacy(ref ea); - - var tabs = SaveTabs(); - foreach (var tab in tabs) - { - _contentType.SetTabName(tab.Item1, tab.Item2); - _contentType.SetTabSortOrder(tab.Item1, tab.Item3); - } - - _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(_contentType)) + if (asyncState.HasAliasChanged()) RegenerateXmlCaches(); Trace.Write("ContentTypeControlNew", "task completing"); @@ -741,7 +748,7 @@ jQuery(document).ready(function() {{ refreshDropDowns(); }}); } - private void SavePropertyType(ref SaveClickEventArgs e, IContentTypeComposition contentTypeItem) + private void SavePropertyType(SaveClickEventArgs e, IContentTypeComposition contentTypeItem) { this.CreateChildControls(); @@ -870,7 +877,7 @@ jQuery(document).ready(function() {{ refreshDropDowns(); }}); } } - private void SavePropertyTypesLegacy(ref SaveClickEventArgs e) + private void SavePropertyTypesLegacy(SaveClickEventArgs e) { this.CreateChildControls(); @@ -1455,6 +1462,33 @@ Umbraco.Controls.TabView.onActiveTabChange(function(tabviewid, tabid, tabs) { /// protected global::System.Web.UI.WebControls.Panel pnlStructure; + /// + /// Pane6 control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::umbraco.uicontrols.Pane Pane6; + + /// + /// pp_Root control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::umbraco.uicontrols.PropertyPanel pp_Root; + + /// + /// allowAtRoot control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.WebControls.CheckBox allowAtRoot; + /// /// Pane5 control. /// diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/create/MediaTypeTasks.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/create/MediaTypeTasks.cs index 0f8a4a44d9..9a187a32ca 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/create/MediaTypeTasks.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/create/MediaTypeTasks.cs @@ -45,11 +45,7 @@ namespace umbraco { var mediaType = cms.businesslogic.media.MediaType.MakeNew(User.GetUser(_userID), Alias.Replace("'", "''")); mediaType.IconUrl = UmbracoSettings.IconPickerBehaviour == IconPickerBehaviour.HideFileDuplicates ? ".sprTreeFolder" : "folder.gif"; - - m_returnUrl = string.Format("settings/editMediaType.aspx?id={0}", mediaType.Id); - var mediaType = cms.businesslogic.media.MediaType.MakeNew(User.GetUser(_userID), Alias.Replace("'", "''"), - ParentID); - + if (ParentID != -1) { mediaType.MasterContentType = ParentID; diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/settings/EditNodeTypeNew.aspx.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/settings/EditNodeTypeNew.aspx.cs index 5cc89fe6ec..3dd21c5082 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/settings/EditNodeTypeNew.aspx.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/settings/EditNodeTypeNew.aspx.cs @@ -133,5 +133,32 @@ namespace umbraco.settings if (ddlTemplatesSelect != null) ddlTemplatesSelect.Selected = true; } + + /// + /// tmpPane control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::umbraco.uicontrols.Pane tmpPane; + + /// + /// templateList control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.WebControls.CheckBoxList templateList; + + /// + /// ddlTemplates control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.WebControls.DropDownList ddlTemplates; } } diff --git a/src/umbraco.cms/businesslogic/web/Document.cs b/src/umbraco.cms/businesslogic/web/Document.cs index 936f7882e7..49835a2a68 100644 --- a/src/umbraco.cms/businesslogic/web/Document.cs +++ b/src/umbraco.cms/businesslogic/web/Document.cs @@ -402,9 +402,9 @@ namespace umbraco.cms.businesslogic.web var children = ApplicationContext.Current.Services.ContentService.GetChildrenByName(NodeId, searchString); return children.Select(x => new Document(x)).ToList(); } - - [MethodImpl(MethodImplOptions.Synchronized)] + [Obsolete("Obsolete, Use Umbraco.Core.Services.ContentService.RePublishAll()", false)] + [MethodImpl(MethodImplOptions.Synchronized)] public static void RePublishAll() { XmlDocument xd = new XmlDocument();