diff --git a/src/Umbraco.Core/Models/ContentTypeBase.cs b/src/Umbraco.Core/Models/ContentTypeBase.cs index 0159621a9e..d2fd56f0b6 100644 --- a/src/Umbraco.Core/Models/ContentTypeBase.cs +++ b/src/Umbraco.Core/Models/ContentTypeBase.cs @@ -442,7 +442,7 @@ namespace Umbraco.Core.Models oldPropertyGroup.PropertyTypes.RemoveItem(propertyTypeAlias); } - propertyType.PropertyGroupId = default(int); + propertyType.PropertyGroupId = new Lazy(() => default(int)); propertyType.ResetDirtyProperties(); var propertyGroup = PropertyGroups.First(x => x.Name == propertyGroupName); diff --git a/src/Umbraco.Core/Models/ContentTypeCompositionBase.cs b/src/Umbraco.Core/Models/ContentTypeCompositionBase.cs index 72c0a6f72a..02a5e7d8f7 100644 --- a/src/Umbraco.Core/Models/ContentTypeCompositionBase.cs +++ b/src/Umbraco.Core/Models/ContentTypeCompositionBase.cs @@ -140,8 +140,8 @@ namespace Umbraco.Core.Models if (CompositionPropertyGroups.Any(x => x.Name == groupName)) { - var first = CompositionPropertyGroups.First(x => x.Name == groupName && x.ParentId.HasValue == false); - propertyGroup.ParentId = first.Id; + var firstGroup = CompositionPropertyGroups.First(x => x.Name == groupName && x.ParentId.HasValue == false); + propertyGroup.SetLazyParentId(new Lazy(() => firstGroup.Id)); } if (PropertyGroups.Any()) @@ -166,7 +166,7 @@ namespace Umbraco.Core.Models { if (PropertyGroups.Contains(propertyGroupName)) { - propertyType.PropertyGroupId = PropertyGroups[propertyGroupName].Id; + propertyType.PropertyGroupId = new Lazy(() => PropertyGroups[propertyGroupName].Id); PropertyGroups[propertyGroupName].PropertyTypes.Add(propertyType); } else @@ -179,7 +179,8 @@ namespace Umbraco.Core.Models { var parentPropertyGroup = CompositionPropertyGroups.First(x => x.Name == propertyGroupName && x.ParentId.HasValue == false); propertyGroup.SortOrder = parentPropertyGroup.SortOrder; - propertyGroup.ParentId = parentPropertyGroup.Id; + //propertyGroup.ParentId = parentPropertyGroup.Id; + propertyGroup.SetLazyParentId(new Lazy(() => parentPropertyGroup.Id)); } PropertyGroups.Add(propertyGroup); diff --git a/src/Umbraco.Core/Models/ContentTypeSort.cs b/src/Umbraco.Core/Models/ContentTypeSort.cs index 009abc110c..6790f15fb0 100644 --- a/src/Umbraco.Core/Models/ContentTypeSort.cs +++ b/src/Umbraco.Core/Models/ContentTypeSort.cs @@ -8,6 +8,17 @@ namespace Umbraco.Core.Models /// public class ContentTypeSort : IValueObject { + public ContentTypeSort() + { + } + + public ContentTypeSort(Lazy id, int sortOrder, string @alias) + { + Id = id; + SortOrder = sortOrder; + Alias = alias; + } + /// /// Gets or sets the Id of the ContentType /// diff --git a/src/Umbraco.Core/Models/PropertyGroup.cs b/src/Umbraco.Core/Models/PropertyGroup.cs index b17f7246c3..044ecd164e 100644 --- a/src/Umbraco.Core/Models/PropertyGroup.cs +++ b/src/Umbraco.Core/Models/PropertyGroup.cs @@ -15,7 +15,7 @@ namespace Umbraco.Core.Models public class PropertyGroup : Entity, IEquatable { private string _name; - private int? _parentId; + private Lazy _parentId; private int _sortOrder; private PropertyTypeCollection _propertyTypes; @@ -64,14 +64,16 @@ namespace Umbraco.Core.Models [DataMember] public int? ParentId { - get { return _parentId; } + get + { + if (_parentId == null) + return default(int?); + return _parentId.Value; + } set { - SetPropertyValueAndDetectChanges(o => - { - _parentId = value; - return _parentId; - }, _parentId, ParentIdSelector); + _parentId = new Lazy(() => value); + OnPropertyChanged(ParentIdSelector); } } @@ -106,6 +108,15 @@ namespace Umbraco.Core.Models } } + /// + /// Sets the ParentId from the lazy integer id + /// + /// Id of the Parent + internal void SetLazyParentId(Lazy id) + { + _parentId = id; + } + public bool Equals(PropertyGroup other) { //Check whether the compared object is null. diff --git a/src/Umbraco.Core/Models/PropertyType.cs b/src/Umbraco.Core/Models/PropertyType.cs index 2db3d4bd1c..512fc993ce 100644 --- a/src/Umbraco.Core/Models/PropertyType.cs +++ b/src/Umbraco.Core/Models/PropertyType.cs @@ -19,7 +19,7 @@ namespace Umbraco.Core.Models private string _alias; private string _description; private int _dataTypeDefinitionId; - private int _propertyGroupId; + private Lazy _propertyGroupId; private Guid _dataTypeId; private DataTypeDatabaseType _dataTypeDatabaseType; private bool _mandatory; @@ -62,7 +62,7 @@ namespace Umbraco.Core.Models private static readonly PropertyInfo HelpTextSelector = ExpressionHelper.GetPropertyInfo(x => x.HelpText); private static readonly PropertyInfo SortOrderSelector = ExpressionHelper.GetPropertyInfo(x => x.SortOrder); private static readonly PropertyInfo ValidationRegExpSelector = ExpressionHelper.GetPropertyInfo(x => x.ValidationRegExp); - private static readonly PropertyInfo PropertyGroupIdSelector = ExpressionHelper.GetPropertyInfo(x => x.PropertyGroupId); + private static readonly PropertyInfo PropertyGroupIdSelector = ExpressionHelper.GetPropertyInfo>(x => x.PropertyGroupId); /// /// Gets of Sets the Name of the PropertyType @@ -172,7 +172,7 @@ namespace Umbraco.Core.Models /// Gets or Sets the PropertyGroup's Id for which this PropertyType belongs /// [DataMember] - internal int PropertyGroupId + internal Lazy PropertyGroupId { get { return _propertyGroupId; } set diff --git a/src/Umbraco.Core/Models/Template.cs b/src/Umbraco.Core/Models/Template.cs index 63062eee84..be111bfc26 100644 --- a/src/Umbraco.Core/Models/Template.cs +++ b/src/Umbraco.Core/Models/Template.cs @@ -124,18 +124,7 @@ namespace Umbraco.Core.Models } [DataMember] - internal int MasterTemplateId - { - get { return _masterTemplateId; } - set - { - SetPropertyValueAndDetectChanges(o => - { - _masterTemplateId = value; - return _masterTemplateId; - }, _masterTemplateId, MasterTemplateIdSelector); - } - } + internal Lazy MasterTemplateId { get; set; } [DataMember] internal string MasterTemplateAlias diff --git a/src/Umbraco.Core/Persistence/Factories/PropertyGroupFactory.cs b/src/Umbraco.Core/Persistence/Factories/PropertyGroupFactory.cs index 45d2c41275..68d3a0c299 100644 --- a/src/Umbraco.Core/Persistence/Factories/PropertyGroupFactory.cs +++ b/src/Umbraco.Core/Persistence/Factories/PropertyGroupFactory.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Linq; using Umbraco.Core.Models; using Umbraco.Core.Models.Rdbms; @@ -44,6 +45,7 @@ namespace Umbraco.Core.Persistence.Factories var typeDtos = groupDto.PropertyTypeDtos.Where(x => x.Id > 0); foreach (var typeDto in typeDtos) { + var tempGroupDto = groupDto; var propertyType = new PropertyType(typeDto.DataTypeDto.ControlId, typeDto.DataTypeDto.DbType.EnumParse(true)) { @@ -56,7 +58,7 @@ namespace Umbraco.Core.Persistence.Factories Mandatory = typeDto.Mandatory, SortOrder = typeDto.SortOrder, ValidationRegExp = typeDto.ValidationRegExp, - PropertyGroupId = groupDto.Id + PropertyGroupId = new Lazy(() => tempGroupDto.Id) }; //on initial construction we don't want to have dirty properties tracked // http://issues.umbraco.org/issue/U4-1946 diff --git a/src/Umbraco.Core/Persistence/Factories/TemplateFactory.cs b/src/Umbraco.Core/Persistence/Factories/TemplateFactory.cs index b7d10a0d83..ae2c2831f8 100644 --- a/src/Umbraco.Core/Persistence/Factories/TemplateFactory.cs +++ b/src/Umbraco.Core/Persistence/Factories/TemplateFactory.cs @@ -29,16 +29,20 @@ namespace Umbraco.Core.Persistence.Factories public Template BuildEntity(TemplateDto dto) { var template = new Template(string.Empty, dto.NodeDto.Text, dto.Alias) - { - CreateDate = dto.NodeDto.CreateDate, - Id = dto.NodeId, - Key = dto.NodeDto.UniqueId.Value, - CreatorId = dto.NodeDto.UserId.Value, - Level = dto.NodeDto.Level, - ParentId = dto.NodeDto.ParentId, - SortOrder = dto.NodeDto.SortOrder, - NodePath = dto.NodeDto.Path - }; + { + CreateDate = dto.NodeDto.CreateDate, + Id = dto.NodeId, + Key = dto.NodeDto.UniqueId.Value, + CreatorId = dto.NodeDto.UserId.Value, + Level = dto.NodeDto.Level, + ParentId = dto.NodeDto.ParentId, + SortOrder = dto.NodeDto.SortOrder, + NodePath = dto.NodeDto.Path + }; + + if(dto.Master.HasValue) + template.MasterTemplateId = new Lazy(() => dto.Master.Value); + //on initial construction we don't want to have dirty properties tracked // http://issues.umbraco.org/issue/U4-1946 template.ResetDirtyProperties(false); @@ -54,6 +58,11 @@ namespace Umbraco.Core.Persistence.Factories NodeDto = BuildNodeDto(entity) }; + if (entity.MasterTemplateId != null && entity.MasterTemplateId.Value != default(int)) + { + dto.Master = entity.MasterTemplateId.Value; + } + if (entity.HasIdentity) { dto.NodeId = entity.Id; diff --git a/src/Umbraco.Core/Persistence/Repositories/ContentTypeBaseRepository.cs b/src/Umbraco.Core/Persistence/Repositories/ContentTypeBaseRepository.cs index 179db898df..03e72d0e91 100644 --- a/src/Umbraco.Core/Persistence/Repositories/ContentTypeBaseRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/ContentTypeBaseRepository.cs @@ -122,7 +122,12 @@ namespace Umbraco.Core.Persistence.Repositories //Insert collection of allowed content types foreach (var allowedContentType in entity.AllowedContentTypes) { - Database.Insert(new ContentTypeAllowedContentTypeDto { Id = entity.Id, AllowedId = allowedContentType.Id.Value, SortOrder = allowedContentType.SortOrder }); + Database.Insert(new ContentTypeAllowedContentTypeDto + { + Id = entity.Id, + AllowedId = allowedContentType.Id.Value, + SortOrder = allowedContentType.SortOrder + }); } var propertyFactory = new PropertyGroupFactory(nodeDto.NodeId); @@ -139,14 +144,18 @@ namespace Umbraco.Core.Persistence.Repositories foreach (var propertyType in propertyGroup.PropertyTypes) { if (propertyType.IsPropertyDirty("PropertyGroupId") == false) - propertyType.PropertyGroupId = propertyGroup.Id; + { + var tempGroup = propertyGroup; + propertyType.PropertyGroupId = new Lazy(() => tempGroup.Id); + } } } //Insert PropertyTypes foreach (var propertyType in entity.PropertyTypes) { - var propertyTypeDto = propertyFactory.BuildPropertyTypeDto(propertyType.PropertyGroupId, propertyType); + var tabId = propertyType.PropertyGroupId != null ? propertyType.PropertyGroupId.Value : default(int); + var propertyTypeDto = propertyFactory.BuildPropertyTypeDto(tabId, propertyType); int typePrimaryKey = Convert.ToInt32(Database.Insert(propertyTypeDto)); propertyType.Id = typePrimaryKey; //Set Id on new PropertyType @@ -286,15 +295,18 @@ namespace Umbraco.Core.Persistence.Repositories foreach (var propertyType in propertyGroup.PropertyTypes) { if (propertyType.IsPropertyDirty("PropertyGroupId") == false) - propertyType.PropertyGroupId = propertyGroup.Id; + { + var tempGroup = propertyGroup; + propertyType.PropertyGroupId = new Lazy(() => tempGroup.Id); + } } } //Run through all PropertyTypes to insert or update entries foreach (var propertyType in entity.PropertyTypes) { - var propertyTypeDto = propertyGroupFactory.BuildPropertyTypeDto(propertyType.PropertyGroupId, - propertyType); + var tabId = propertyType.PropertyGroupId != null ? propertyType.PropertyGroupId.Value : default(int); + var propertyTypeDto = propertyGroupFactory.BuildPropertyTypeDto(tabId, propertyType); int typePrimaryKey = propertyType.HasIdentity ? Database.Update(propertyTypeDto) : Convert.ToInt32(Database.Insert(propertyTypeDto)); diff --git a/src/Umbraco.Core/Persistence/Repositories/TemplateRepository.cs b/src/Umbraco.Core/Persistence/Repositories/TemplateRepository.cs index 72860be994..44112a10c8 100644 --- a/src/Umbraco.Core/Persistence/Repositories/TemplateRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/TemplateRepository.cs @@ -72,7 +72,7 @@ namespace Umbraco.Core.Persistence.Repositories { var masterTemplate = Get(dto.Master.Value); template.MasterTemplateAlias = masterTemplate.Alias; - template.MasterTemplateId = dto.Master.Value; + template.MasterTemplateId = new Lazy(() => dto.Master.Value); } if (_viewsFileSystem.FileExists(csViewName)) @@ -177,11 +177,13 @@ namespace Umbraco.Core.Persistence.Repositories { if (entity.GetTypeOfRenderingEngine() == RenderingEngine.Mvc) { - _viewsFileSystem.AddFile(entity.Name, stream, true); + string viewName = string.Concat(entity.Alias, ".cshtml"); + _viewsFileSystem.AddFile(viewName, stream, true); } else { - _masterpagesFileSystem.AddFile(entity.Name, stream, true); + string masterpageName = string.Concat(entity.Alias, ".master"); + _masterpagesFileSystem.AddFile(masterpageName, stream, true); } } @@ -228,11 +230,13 @@ namespace Umbraco.Core.Persistence.Repositories { if (entity.GetTypeOfRenderingEngine() == RenderingEngine.Mvc) { - _viewsFileSystem.AddFile(entity.Name, stream, true); + string viewName = string.Concat(entity.Alias, ".cshtml"); + _viewsFileSystem.AddFile(viewName, stream, true); } else { - _masterpagesFileSystem.AddFile(entity.Name, stream, true); + string masterpageName = string.Concat(entity.Alias, ".master"); + _masterpagesFileSystem.AddFile(masterpageName, stream, true); } } @@ -333,8 +337,8 @@ namespace Umbraco.Core.Persistence.Repositories public ITemplate Get(string alias) { - var sql = GetBaseQuery(false); - sql.Where("cmsTemplate.alias = @Alias", new { Alias = alias }); + var sql = GetBaseQuery(false) + .Where(x => x.Alias == alias); var dto = Database.Fetch(sql).FirstOrDefault(); diff --git a/src/Umbraco.Core/Services/ContentService.cs b/src/Umbraco.Core/Services/ContentService.cs index c6cd7de277..0036e10724 100644 --- a/src/Umbraco.Core/Services/ContentService.cs +++ b/src/Umbraco.Core/Services/ContentService.cs @@ -68,27 +68,8 @@ namespace Umbraco.Core.Services /// public IContent CreateContent(string name, int parentId, string contentTypeAlias, int userId = 0) { - IContentType contentType = null; - IContent content = null; - - var uow = _uowProvider.GetUnitOfWork(); - using (var repository = _repositoryFactory.CreateContentTypeRepository(uow)) - { - var query = Query.Builder.Where(x => x.Alias == contentTypeAlias); - var contentTypes = repository.GetByQuery(query); - - if (!contentTypes.Any()) - throw new Exception(string.Format("No ContentType matching the passed in Alias: '{0}' was found", - contentTypeAlias)); - - contentType = contentTypes.First(); - - if (contentType == null) - throw new Exception(string.Format("ContentType matching the passed in Alias: '{0}' was null", - contentTypeAlias)); - } - - content = new Content(name, parentId, contentType); + IContentType contentType = FindContentTypeByAlias(contentTypeAlias); + IContent content = new Content(name, parentId, contentType); if (Creating.IsRaisedEventCancelled(new NewEventArgs(content, contentTypeAlias, parentId), this)) return content; @@ -114,27 +95,8 @@ namespace Umbraco.Core.Services /// public IContent CreateContent(string name, IContent parent, string contentTypeAlias, int userId = 0) { - IContentType contentType = null; - IContent content = null; - - var uow = _uowProvider.GetUnitOfWork(); - using (var repository = _repositoryFactory.CreateContentTypeRepository(uow)) - { - var query = Query.Builder.Where(x => x.Alias == contentTypeAlias); - var contentTypes = repository.GetByQuery(query); - - if (!contentTypes.Any()) - throw new Exception(string.Format("No ContentType matching the passed in Alias: '{0}' was found", - contentTypeAlias)); - - contentType = contentTypes.First(); - - if (contentType == null) - throw new Exception(string.Format("ContentType matching the passed in Alias: '{0}' was null", - contentTypeAlias)); - } - - content = new Content(name, parent, contentType); + IContentType contentType = FindContentTypeByAlias(contentTypeAlias); + IContent content = new Content(name, parent, contentType); if (Creating.IsRaisedEventCancelled(new NewEventArgs(content, contentTypeAlias, parent), this)) return content; @@ -1585,6 +1547,28 @@ namespace Umbraco.Core.Services return true; } + private IContentType FindContentTypeByAlias(string contentTypeAlias) + { + using (var repository = _repositoryFactory.CreateContentTypeRepository(_uowProvider.GetUnitOfWork())) + { + var query = Query.Builder.Where(x => x.Alias == contentTypeAlias); + var types = repository.GetByQuery(query); + + if (!types.Any()) + throw new Exception( + string.Format("No ContentType matching the passed in Alias: '{0}' was found", + contentTypeAlias)); + + var contentType = types.First(); + + if (contentType == null) + throw new Exception(string.Format("ContentType matching the passed in Alias: '{0}' was null", + contentTypeAlias)); + + return contentType; + } + } + #endregion #region Event Handlers diff --git a/src/Umbraco.Core/Services/ContentTypeService.cs b/src/Umbraco.Core/Services/ContentTypeService.cs index 6afc43d9d8..f037d25bc2 100644 --- a/src/Umbraco.Core/Services/ContentTypeService.cs +++ b/src/Umbraco.Core/Services/ContentTypeService.cs @@ -1,7 +1,9 @@ using System; using System.Collections.Generic; +using System.Data; using System.Linq; using System.Text; +using System.Xml.Linq; using System.Threading; using Umbraco.Core.Auditing; using Umbraco.Core.Configuration; @@ -560,7 +562,7 @@ namespace Umbraco.Core.Services } return dtd.ToString(); } - + #region Event Handlers /// diff --git a/src/Umbraco.Core/Services/DataTypeService.cs b/src/Umbraco.Core/Services/DataTypeService.cs index 50ef680d1c..0b22d74070 100644 --- a/src/Umbraco.Core/Services/DataTypeService.cs +++ b/src/Umbraco.Core/Services/DataTypeService.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Threading; using Umbraco.Core.Auditing; using Umbraco.Core.Events; using Umbraco.Core.Models; @@ -19,6 +20,7 @@ namespace Umbraco.Core.Services { private readonly RepositoryFactory _repositoryFactory; private readonly IDatabaseUnitOfWorkProvider _uowProvider; + private static readonly ReaderWriterLockSlim Locker = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion); public DataTypeService() : this(new RepositoryFactory()) @@ -105,11 +107,26 @@ namespace Umbraco.Core.Services /// An enumerable list of string values public IEnumerable GetPreValuesByDataTypeId(int id) { - var uow = _uowProvider.GetUnitOfWork(); - var dtos = uow.Database.Fetch("WHERE datatypeNodeId = @Id", new {Id = id}); - var list = dtos.Select(x => x.Value).ToList(); - uow.Dispose(); - return list; + using (var uow = _uowProvider.GetUnitOfWork()) + { + var dtos = uow.Database.Fetch("WHERE datatypeNodeId = @Id", new {Id = id}); + var list = dtos.Select(x => x.Value).ToList(); + return list; + } + } + + /// + /// Gets a specific PreValue by its Id + /// + /// Id of the PreValue to retrieve the value from + /// PreValue as a string + public string GetPreValueAsString(int id) + { + using (var uow = _uowProvider.GetUnitOfWork()) + { + var dto = uow.Database.FirstOrDefault("WHERE id = @Id", new { Id = id }); + return dto != null ? dto.Value : string.Empty; + } } /// @@ -121,18 +138,84 @@ namespace Umbraco.Core.Services { if (Saving.IsRaisedEventCancelled(new SaveEventArgs(dataTypeDefinition), this)) return; - - var uow = _uowProvider.GetUnitOfWork(); - using (var repository = _repositoryFactory.CreateDataTypeDefinitionRepository(uow)) - { - dataTypeDefinition.CreatorId = userId; - repository.AddOrUpdate(dataTypeDefinition); - uow.Commit(); - Saved.RaiseEvent(new SaveEventArgs(dataTypeDefinition, false), this); - } + using (new WriteLock(Locker)) + { + var uow = _uowProvider.GetUnitOfWork(); + using (var repository = _repositoryFactory.CreateDataTypeDefinitionRepository(uow)) + { + dataTypeDefinition.CreatorId = userId; + repository.AddOrUpdate(dataTypeDefinition); + uow.Commit(); - Audit.Add(AuditTypes.Save, string.Format("Save DataTypeDefinition performed by user"), userId, dataTypeDefinition.Id); + Saved.RaiseEvent(new SaveEventArgs(dataTypeDefinition, false), this); + } + } + + Audit.Add(AuditTypes.Save, string.Format("Save DataTypeDefinition performed by user"), userId, dataTypeDefinition.Id); + } + + /// + /// Saves a collection of + /// + /// to save + /// Id of the user issueing the save + public void Save(IEnumerable dataTypeDefinitions, int userId = 0) + { + if (Saving.IsRaisedEventCancelled(new SaveEventArgs(dataTypeDefinitions), this)) + return; + + using (new WriteLock(Locker)) + { + var uow = _uowProvider.GetUnitOfWork(); + using (var repository = _repositoryFactory.CreateDataTypeDefinitionRepository(uow)) + { + foreach (var dataTypeDefinition in dataTypeDefinitions) + { + dataTypeDefinition.CreatorId = userId; + repository.AddOrUpdate(dataTypeDefinition); + } + uow.Commit(); + + Saved.RaiseEvent(new SaveEventArgs(dataTypeDefinitions, false), this); + } + } + Audit.Add(AuditTypes.Save, string.Format("Save DataTypeDefinition performed by user"), userId, -1); + } + + /// + /// Saves a list of PreValues for a given DataTypeDefinition + /// + /// Id of the DataTypeDefinition to save PreValues for + /// List of string values to save + public void SavePreValues(int id, IEnumerable values) + { + using (new WriteLock(Locker)) + { + using (var uow = _uowProvider.GetUnitOfWork()) + { + var sortOrderObj = + uow.Database.ExecuteScalar( + "SELECT max(sortorder) FROM cmsDataTypePreValues WHERE datatypeNodeId = @DataTypeId", new { DataTypeId = id }); + int sortOrder; + if (sortOrderObj == null || int.TryParse(sortOrderObj.ToString(), out sortOrder) == false) + { + sortOrder = 1; + } + + using (var transaction = uow.Database.GetTransaction()) + { + foreach (var value in values) + { + var dto = new DataTypePreValueDto { DataTypeNodeId = id, Value = value, SortOrder = sortOrder }; + uow.Database.Insert(dto); + sortOrder++; + } + + transaction.Complete(); + } + } + } } /// diff --git a/src/Umbraco.Core/Services/FileService.cs b/src/Umbraco.Core/Services/FileService.cs index ace5d1d612..53ac74b3a2 100644 --- a/src/Umbraco.Core/Services/FileService.cs +++ b/src/Umbraco.Core/Services/FileService.cs @@ -255,6 +255,31 @@ namespace Umbraco.Core.Services Audit.Add(AuditTypes.Save, string.Format("Save Template performed by user"), userId, template.Id); } + /// + /// Saves a collection of objects + /// + /// List of to save + /// Optional id of the user + public void SaveTemplate(IEnumerable templates, int userId = 0) + { + if (SavingTemplate.IsRaisedEventCancelled(new SaveEventArgs(templates), this)) + return; + + var uow = _dataUowProvider.GetUnitOfWork(); + using (var repository = _repositoryFactory.CreateTemplateRepository(uow)) + { + foreach (var template in templates) + { + repository.AddOrUpdate(template); + } + uow.Commit(); + + SavedTemplate.RaiseEvent(new SaveEventArgs(templates, false), this); + } + + Audit.Add(AuditTypes.Save, string.Format("Save Template performed by user"), userId, -1); + } + /// /// Deletes a template by its alias /// diff --git a/src/Umbraco.Core/Services/IContentService.cs b/src/Umbraco.Core/Services/IContentService.cs index ee6960f6af..aa4c5d9a73 100644 --- a/src/Umbraco.Core/Services/IContentService.cs +++ b/src/Umbraco.Core/Services/IContentService.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Xml.Linq; using Umbraco.Core.Models; namespace Umbraco.Core.Services diff --git a/src/Umbraco.Core/Services/IContentTypeService.cs b/src/Umbraco.Core/Services/IContentTypeService.cs index 15ee5d949c..9e7849e33c 100644 --- a/src/Umbraco.Core/Services/IContentTypeService.cs +++ b/src/Umbraco.Core/Services/IContentTypeService.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Xml.Linq; using Umbraco.Core.Models; namespace Umbraco.Core.Services diff --git a/src/Umbraco.Core/Services/IDataTypeService.cs b/src/Umbraco.Core/Services/IDataTypeService.cs index 15ee44298b..5fac95a25c 100644 --- a/src/Umbraco.Core/Services/IDataTypeService.cs +++ b/src/Umbraco.Core/Services/IDataTypeService.cs @@ -38,6 +38,13 @@ namespace Umbraco.Core.Services /// Id of the user issueing the save void Save(IDataTypeDefinition dataTypeDefinition, int userId = 0); + /// + /// Saves a collection of + /// + /// to save + /// Id of the user issueing the save + void Save(IEnumerable dataTypeDefinitions, int userId = 0); + /// /// Deletes an /// @@ -75,5 +82,19 @@ namespace Umbraco.Core.Services /// Id of the to retrieve prevalues from /// An enumerable list of string values IEnumerable GetPreValuesByDataTypeId(int id); + + /// + /// Saves a list of PreValues for a given DataTypeDefinition + /// + /// Id of the DataTypeDefinition to save PreValues for + /// List of string values to save + void SavePreValues(int id, IEnumerable values); + + /// + /// Gets a specific PreValue by its Id + /// + /// Id of the PreValue to retrieve the value from + /// PreValue as a string + string GetPreValueAsString(int id); } } \ No newline at end of file diff --git a/src/Umbraco.Core/Services/IFileService.cs b/src/Umbraco.Core/Services/IFileService.cs index d4ee7fd71e..baf2126b20 100644 --- a/src/Umbraco.Core/Services/IFileService.cs +++ b/src/Umbraco.Core/Services/IFileService.cs @@ -116,5 +116,12 @@ namespace Umbraco.Core.Services /// to validate /// True if Script is valid, otherwise false bool ValidateTemplate(ITemplate template); + + /// + /// Saves a collection of objects + /// + /// List of to save + /// Optional id of the user + void SaveTemplate(IEnumerable templates, int userId = 0); } } \ No newline at end of file diff --git a/src/Umbraco.Core/Services/PackagingService.cs b/src/Umbraco.Core/Services/PackagingService.cs new file mode 100644 index 0000000000..8d67e7ab1d --- /dev/null +++ b/src/Umbraco.Core/Services/PackagingService.cs @@ -0,0 +1,614 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text.RegularExpressions; +using System.Threading; +using System.Xml.Linq; +using Umbraco.Core.IO; +using Umbraco.Core.Logging; +using Umbraco.Core.Models; +using Umbraco.Core.Persistence; +using Umbraco.Core.Persistence.Querying; +using Umbraco.Core.Persistence.UnitOfWork; + +namespace Umbraco.Core.Services +{ + public class PackagingService : IService + { + private readonly IContentService _contentService; + private readonly IContentTypeService _contentTypeService; + private readonly IMediaService _mediaService; + private readonly IDataTypeService _dataTypeService; + private readonly IFileService _fileService; + private readonly RepositoryFactory _repositoryFactory; + private readonly IDatabaseUnitOfWorkProvider _uowProvider; + private Dictionary _importedContentTypes; + //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); + + public PackagingService(IContentService contentService, IContentTypeService contentTypeService, IMediaService mediaService, IDataTypeService dataTypeService, IFileService fileService, RepositoryFactory repositoryFactory, IDatabaseUnitOfWorkProvider uowProvider) + { + _contentService = contentService; + _contentTypeService = contentTypeService; + _mediaService = mediaService; + _dataTypeService = dataTypeService; + _fileService = fileService; + _repositoryFactory = repositoryFactory; + _uowProvider = uowProvider; + + _importedContentTypes = new Dictionary(); + } + + #region Content + + /// + /// Imports and saves package xml as + /// + /// Xml to import + /// Optional parent Id for the content being imported + /// Optional Id of the user performing the import + /// An enumrable list of generated content + public IEnumerable ImportContent(XElement element, int parentId = -1, int userId = 0) + { + var name = element.Name.LocalName; + if (name.Equals("DocumentSet")) + { + //This is a regular deep-structured import + var roots = from doc in element.Elements() + where (string)doc.Attribute("isDoc") == "" + select doc; + + var contents = ParseDocumentRootXml(roots, parentId); + _contentService.Save(contents, userId); + + return contents; + } + + var attribute = element.Attribute("isDoc"); + if (attribute != null) + { + //This is a single doc import + var elements = new List { element }; + var contents = ParseDocumentRootXml(elements, parentId); + _contentService.Save(contents, userId); + + return contents; + } + + throw new ArgumentException( + "The passed in XElement is not valid! It does not contain a root element called " + + "'DocumentSet' (for structured imports) nor is the first element a Document (for single document import)."); + } + + private IEnumerable ParseDocumentRootXml(IEnumerable roots, int parentId) + { + var contents = new List(); + foreach (var root in roots) + { + bool isLegacySchema = root.Name.LocalName.ToLowerInvariant().Equals("node"); + string contentTypeAlias = isLegacySchema + ? root.Attribute("nodeTypeAlias").Value + : root.Name.LocalName; + + if (_importedContentTypes.ContainsKey(contentTypeAlias) == false) + { + var contentType = FindContentTypeByAlias(contentTypeAlias); + _importedContentTypes.Add(contentTypeAlias, contentType); + } + + var content = CreateContentFromXml(root, _importedContentTypes[contentTypeAlias], null, parentId, isLegacySchema); + contents.Add(content); + + var children = from child in root.Elements() + where (string)child.Attribute("isDoc") == "" + select child; + if (children.Any()) + contents.AddRange(CreateContentFromXml(children, content, isLegacySchema)); + } + return contents; + } + + private IEnumerable CreateContentFromXml(IEnumerable children, IContent parent, bool isLegacySchema) + { + var list = new List(); + foreach (var child in children) + { + string contentTypeAlias = isLegacySchema + ? child.Attribute("nodeTypeAlias").Value + : child.Name.LocalName; + + if (_importedContentTypes.ContainsKey(contentTypeAlias) == false) + { + var contentType = FindContentTypeByAlias(contentTypeAlias); + _importedContentTypes.Add(contentTypeAlias, contentType); + } + + //Create and add the child to the list + var content = CreateContentFromXml(child, _importedContentTypes[contentTypeAlias], parent, default(int), isLegacySchema); + list.Add(content); + + //Recursive call + XElement child1 = child; + var grandChildren = from grand in child1.Elements() + where (string)grand.Attribute("isDoc") == "" + select grand; + + if (grandChildren.Any()) + list.AddRange(CreateContentFromXml(grandChildren, content, isLegacySchema)); + } + + return list; + } + + private IContent CreateContentFromXml(XElement element, IContentType contentType, IContent parent, int parentId, bool isLegacySchema) + { + var id = element.Attribute("id").Value; + var level = element.Attribute("level").Value; + var sortOrder = element.Attribute("sortOrder").Value; + var nodeName = element.Attribute("nodeName").Value; + var path = element.Attribute("path").Value; + var template = element.Attribute("template").Value; + + var properties = from property in element.Elements() + where property.Attribute("isDoc") == null + select property; + + IContent content = parent == null + ? new Content(nodeName, parentId, contentType) + { + Level = int.Parse(level), + SortOrder = int.Parse(sortOrder) + } + : new Content(nodeName, parent, contentType) + { + Level = int.Parse(level), + SortOrder = int.Parse(sortOrder) + }; + + foreach (var property in properties) + { + string propertyTypeAlias = isLegacySchema ? property.Attribute("alias").Value : property.Name.LocalName; + if (content.HasProperty(propertyTypeAlias)) + content.SetValue(propertyTypeAlias, property.Value); + } + + return content; + } + + public XElement Export(IContent content, bool deep = false) + { + throw new NotImplementedException(); + } + + #endregion + + #region ContentTypes + + /// + /// Imports and saves package xml as + /// + /// Xml to import + /// + /// An enumrable list of generated ContentTypes + public IEnumerable ImportContentTypes(XElement element, int userId = 0) + { + var name = element.Name.LocalName; + if (name.Equals("DocumentTypes") == false && name.Equals("DocumentType")) + { + throw new ArgumentException("The passed in XElement is not valid! It does not contain a root element called 'DocumentTypes' for multiple imports or 'DocumentType' for a single import."); + } + + _importedContentTypes = new Dictionary(); + var documentTypes = name.Equals("DocumentTypes") + ? (from doc in element.Elements("DocumentType") select doc).ToList() + : new List {element.Element("DocumentType")}; + //NOTE it might be an idea to sort the doctype XElements based on dependencies + //before creating the doc types - should also allow for a better structure/inheritance support. + foreach (var documentType in documentTypes) + { + var alias = documentType.Element("Info").Element("Alias").Value; + if (_importedContentTypes.ContainsKey(alias) == false) + { + var contentType = _contentTypeService.GetContentType(alias); + _importedContentTypes.Add(alias, contentType == null + ? CreateContentTypeFromXml(documentType) + : UpdateContentTypeFromXml(documentType, contentType)); + } + } + + 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) + { + 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); + } + //Update ContentTypes with a newly added structure/list of allowed children + if(updatedContentTypes.Any()) + _contentTypeService.Save(updatedContentTypes, userId); + + return list; + } + + private IContentType CreateContentTypeFromXml(XElement documentType) + { + var infoElement = documentType.Element("Info"); + + //Name of the master corresponds to the parent + var masterElement = infoElement.Element("Master"); + IContentType parent = null; + if (masterElement != null) + { + var masterAlias = masterElement.Value; + parent = _importedContentTypes.ContainsKey(masterAlias) + ? _importedContentTypes[masterAlias] + : _contentTypeService.GetContentType(masterAlias); + } + + var contentType = parent == null + ? new ContentType(-1) + { + Alias = infoElement.Element("Alias").Value + } + : new ContentType(parent) + { + Alias = infoElement.Element("Alias").Value + }; + + if (parent != null) + contentType.AddContentType(parent); + + return UpdateContentTypeFromXml(documentType, contentType); + } + + private IContentType UpdateContentTypeFromXml(XElement documentType, IContentType contentType) + { + var infoElement = documentType.Element("Info"); + var defaultTemplateElement = infoElement.Element("DefaultTemplate"); + + contentType.Name = infoElement.Element("Name").Value; + contentType.Icon = infoElement.Element("Icon").Value; + contentType.Thumbnail = infoElement.Element("Thumbnail").Value; + contentType.Description = infoElement.Element("Description").Value; + contentType.AllowedAsRoot = infoElement.Element("AllowAtRoot").Value.ToLowerInvariant().Equals("true"); + + UpdateContentTypesAllowedTemplates(contentType, infoElement.Element("AllowedTemplates"), defaultTemplateElement); + UpdateContentTypesTabs(contentType, documentType.Element("Tab")); + UpdateContentTypesProperties(contentType, documentType.Element("GenericProperties")); + + return contentType; + } + + private void UpdateContentTypesAllowedTemplates(IContentType contentType, + XElement allowedTemplatesElement, XElement defaultTemplateElement) + { + if (allowedTemplatesElement != null && allowedTemplatesElement.Elements("Template").Any()) + { + var allowedTemplates = contentType.AllowedTemplates.ToList(); + foreach (var templateElement in allowedTemplatesElement.Elements("Template")) + { + var alias = templateElement.Value; + var template = _fileService.GetTemplate(alias); + if (template != null) + { + allowedTemplates.Add(template); + } + else + { + LogHelper.Warn( + string.Format( + "Packager: Error handling allowed templates. Template with alias '{0}' could not be found.", + alias)); + } + } + + contentType.AllowedTemplates = allowedTemplates; + } + + if (string.IsNullOrEmpty(defaultTemplateElement.Value) == false) + { + var defaultTemplate = _fileService.GetTemplate(defaultTemplateElement.Value); + if (defaultTemplate != null) + { + contentType.SetDefaultTemplate(defaultTemplate); + } + else + { + LogHelper.Warn( + string.Format( + "Packager: Error handling default template. Default template with alias '{0}' could not be found.", + defaultTemplateElement.Value)); + } + } + } + + private void UpdateContentTypesTabs(IContentType contentType, XElement tabElement) + { + if(tabElement == null) + return; + + var tabs = tabElement.Elements("Tab"); + foreach (var tab in tabs) + { + var id = tab.Element("Id").Value;//Do we need to use this for tracking? + var caption = tab.Element("Caption").Value; + if (contentType.PropertyGroups.Contains(caption) == false) + { + contentType.AddPropertyGroup(caption); + } + } + } + + private void UpdateContentTypesProperties(IContentType contentType, XElement genericPropertiesElement) + { + var properties = genericPropertiesElement.Elements("GenericProperty"); + foreach (var property in properties) + { + var dataTypeId = new Guid(property.Element("Type").Value);//The DataType's Control Id + var dataTypeDefinitionId = new Guid(property.Element("Definition").Value);//Unique Id for a DataTypeDefinition + + var dataTypeDefinition = _dataTypeService.GetDataTypeDefinitionById(dataTypeDefinitionId); + //If no DataTypeDefinition with the guid from the xml wasn't found OR the ControlId on the DataTypeDefinition didn't match the DataType Id + //We look up a DataTypeDefinition that matches + if (dataTypeDefinition == null || dataTypeDefinition.ControlId != dataTypeId) + { + var dataTypeDefinitions = _dataTypeService.GetDataTypeDefinitionByControlId(dataTypeId); + if (dataTypeDefinitions != null && dataTypeDefinitions.Any()) + { + dataTypeDefinition = dataTypeDefinitions.First(); + } + else + { + throw new Exception( + String.Format( + "Packager: Error handling creation of PropertyType '{0}'. Could not find DataTypeDefintion with unique id '{1}' nor one referencing the DataType with control id '{2}'.", + property.Element("Name").Value, dataTypeDefinitionId, dataTypeId)); + } + } + + var propertyType = new PropertyType(dataTypeDefinition) + { + Alias = property.Element("Alias").Value, + Name = property.Element("Name").Value, + Description = property.Element("Description").Value, + Mandatory = property.Element("Mandatory").Value.ToLowerInvariant().Equals("true"), + ValidationRegExp = property.Element("Validation").Value + }; + + var helpTextElement = property.Element("HelpText"); + if (helpTextElement != null) + { + propertyType.HelpText = helpTextElement.Value; + } + + var tab = property.Element("Tab").Value; + if (string.IsNullOrEmpty(tab)) + { + contentType.AddPropertyType(propertyType); + } + else + { + contentType.AddPropertyType(propertyType, tab); + } + } + } + + private IContentType UpdateContentTypesStructure(IContentType contentType, XElement structureElement) + { + var allowedChildren = contentType.AllowedContentTypes.ToList(); + int sortOrder = allowedChildren.Any() ? allowedChildren.Last().SortOrder : 0; + foreach (var element in structureElement.Elements("DocumentType")) + { + var alias = element.Value; + if (_importedContentTypes.ContainsKey(alias)) + { + var allowedChild = _importedContentTypes[alias]; + allowedChildren.Add(new ContentTypeSort(new Lazy(() => allowedChild.Id), sortOrder, allowedChild.Alias)); + sortOrder++; + } + else + { + LogHelper.Warn( + string.Format( + "Packager: Error handling DocumentType structure. DocumentType with alias '{0}' could not be found and was not added to the structure for '{1}'.", + alias, contentType.Alias)); + } + } + + contentType.AllowedContentTypes = allowedChildren; + return contentType; + } + + private IContentType FindContentTypeByAlias(string contentTypeAlias) + { + using (var repository = _repositoryFactory.CreateContentTypeRepository(_uowProvider.GetUnitOfWork())) + { + var query = Query.Builder.Where(x => x.Alias == contentTypeAlias); + var types = repository.GetByQuery(query); + + if (!types.Any()) + throw new Exception( + string.Format("No ContentType matching the passed in Alias: '{0}' was found", + contentTypeAlias)); + + var contentType = types.First(); + + if (contentType == null) + throw new Exception(string.Format("ContentType matching the passed in Alias: '{0}' was null", + contentTypeAlias)); + + return contentType; + } + } + + #endregion + + #region DataTypes + + /// + /// Imports and saves package xml as + /// + /// Xml to import + /// + /// An enumrable list of generated DataTypeDefinitions + public IEnumerable ImportDataTypeDefinitions(XElement element, int userId = 0) + { + var name = element.Name.LocalName; + if (name.Equals("DataTypes") == false) + { + throw new ArgumentException("The passed in XElement is not valid! It does not contain a root element called 'DataTypes'."); + } + + var dataTypes = new Dictionary(); + var dataTypeElements = element.Elements("DataType").ToList(); + foreach (var dataTypeElement in dataTypeElements) + { + var dataTypeDefinitionName = dataTypeElement.Attribute("Name").Value; + var dataTypeId = new Guid(dataTypeElement.Attribute("Id").Value); + var dataTypeDefinitionId = new Guid(dataTypeElement.Attribute("Definition").Value); + + var definition = _dataTypeService.GetDataTypeDefinitionById(dataTypeDefinitionId); + if (definition == null) + { + var dataTypeDefinition = new DataTypeDefinition(-1, dataTypeId) { Key = dataTypeDefinitionId, Name = dataTypeDefinitionName }; + dataTypes.Add(dataTypeDefinitionName, dataTypeDefinition); + } + } + + var list = dataTypes.Select(x => x.Value).ToList(); + _dataTypeService.Save(list, userId); + + SavePrevaluesFromXml(list, dataTypeElements); + + return list; + } + + private void SavePrevaluesFromXml(List dataTypes, IEnumerable dataTypeElements) + { + foreach (var dataTypeElement in dataTypeElements) + { + var prevaluesElement = dataTypeElement.Element("PreValues"); + if (prevaluesElement == null) continue; + + var dataTypeDefinitionName = dataTypeElement.Attribute("Name").Value; + var dataTypeDefinition = dataTypes.First(x => x.Name == dataTypeDefinitionName); + + var values = prevaluesElement.Elements("PreValue").Select(prevalue => prevalue.Attribute("Value").Value).ToList(); + _dataTypeService.SavePreValues(dataTypeDefinition.Id, values); + } + } + #endregion + + #region Dictionary Items + #endregion + + #region Files + #endregion + + #region Languages + #endregion + + #region Macros + #endregion + + #region Media + #endregion + + #region MediaTypes + #endregion + + #region Package Manifest + #endregion + + #region Templates + + /// + /// Imports and saves package xml as + /// + /// Xml to import + /// Optional user id + /// An enumrable list of generated Templates + public IEnumerable ImportTemplates(XElement element, int userId = 0) + { + var name = element.Name.LocalName; + if (name.Equals("Templates") == false && name.Equals("Template")) + { + throw new ArgumentException("The passed in XElement is not valid! It does not contain a root element called 'Templates' for multiple imports or 'Template' for a single import."); + } + + var templates = new List(); + var templateElements = name.Equals("Templates") + ? (from doc in element.Elements("Template") select doc).ToList() + : new List { element.Element("Template") }; + + var fields = new List>(); + foreach (XElement tempElement in templateElements) + { + var dependencies = new List(); + if(tempElement.Element("Master") != null && string.IsNullOrEmpty(tempElement.Element("Master").Value) == false) + dependencies.Add(tempElement.Element("Master").Value); + + var field = new TopologicalSorter.DependencyField + { + Alias = tempElement.Element("Alias").Value, + Item = new Lazy(() => tempElement), + DependsOn = dependencies.ToArray() + }; + + fields.Add(field); + } + //Sort templates by dependencies to a potential master template + var sortedElements = TopologicalSorter.GetSortedItems(fields); + foreach (var templateElement in sortedElements) + { + var templateName = templateElement.Element("Name").Value; + var alias = templateElement.Element("Alias").Value; + var design = templateElement.Element("Design").Value; + var masterElement = templateElement.Element("Master"); + + var isMasterPage = IsMasterPageSyntax(design); + var path = isMasterPage ? MasterpagePath(alias) : ViewPath(alias); + + var template = new Template(path, templateName, alias) { Content = design }; + if (masterElement != null && string.IsNullOrEmpty(masterElement.Value) == false) + { + template.MasterTemplateAlias = masterElement.Value; + var masterTemplate = templates.FirstOrDefault(x => x.Alias == masterElement.Value); + if(masterTemplate != null) + template.MasterTemplateId = new Lazy(() => masterTemplate.Id); + } + templates.Add(template); + } + + _fileService.SaveTemplate(templates, userId); + return templates; + } + + private bool IsMasterPageSyntax(string code) + { + return Regex.IsMatch(code, @"<%@\s*Master", RegexOptions.IgnoreCase) || + code.InvariantContains(" _dataTypeService; private Lazy _fileService; private Lazy _localizationService; + private Lazy _packagingService; private Lazy _serverRegistrationService; private Lazy _entityService; @@ -76,6 +77,8 @@ namespace Umbraco.Core.Services if(_localizationService == null) _localizationService = new Lazy(() => new LocalizationService(provider, repositoryFactory.Value)); + if(_packagingService == null) + _packagingService = new Lazy(() => new PackagingService(_contentService.Value, _contentTypeService.Value, _mediaService.Value, _dataTypeService.Value, _fileService.Value, repositoryFactory.Value, provider)); if (_entityService == null) _entityService = new Lazy(() => new EntityService(provider, repositoryFactory.Value)); } @@ -144,6 +147,14 @@ namespace Umbraco.Core.Services get { return _mediaService.Value; } } + /// + /// Gets the + /// + public PackagingService PackagingService + { + get { return _packagingService.Value; } + } + /// /// Gets the /// diff --git a/src/Umbraco.Core/TopologicalSorter.cs b/src/Umbraco.Core/TopologicalSorter.cs new file mode 100644 index 0000000000..56cdc73051 --- /dev/null +++ b/src/Umbraco.Core/TopologicalSorter.cs @@ -0,0 +1,173 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Umbraco.Core +{ + internal class TopologicalSorter + { + private readonly int[] _vertices; // list of vertices + private readonly int[,] _matrix; // adjacency matrix + private int _numVerts; // current number of vertices + private readonly int[] _sortedArray; + + public TopologicalSorter(int size) + { + _vertices = new int[size]; + _matrix = new int[size, size]; + _numVerts = 0; + for (int i = 0; i < size; i++) + for (int j = 0; j < size; j++) + _matrix[i, j] = 0; + _sortedArray = new int[size]; // sorted vert labels + } + + #region Public Methods + + public int AddVertex(int vertex) + { + _vertices[_numVerts++] = vertex; + return _numVerts - 1; + } + + public void AddEdge(int start, int end) + { + _matrix[start, end] = 1; + } + + public int[] Sort() // toplogical sort + { + while (_numVerts > 0) // while vertices remain, + { + // get a vertex with no successors, or -1 + int currentVertex = NoSuccessors(); + if (currentVertex == -1) // must be a cycle + throw new Exception("Graph has cycles"); + + // insert vertex label in sorted array (start at end) + _sortedArray[_numVerts - 1] = _vertices[currentVertex]; + + DeleteVertex(currentVertex); // delete vertex + } + + // vertices all gone; return sortedArray + return _sortedArray; + } + + #endregion + + #region Private Helper Methods + + // returns vert with no successors (or -1 if no such verts) + private int NoSuccessors() + { + for (int row = 0; row < _numVerts; row++) + { + bool isEdge = false; // edge from row to column in adjMat + for (int col = 0; col < _numVerts; col++) + { + if (_matrix[row, col] > 0) // if edge to another, + { + isEdge = true; + break; // this vertex has a successor try another + } + } + if (!isEdge) // if no edges, has no successors + return row; + } + return -1; // no + } + + private void DeleteVertex(int delVert) + { + // if not last vertex, delete from vertexList + if (delVert != _numVerts - 1) + { + for (int j = delVert; j < _numVerts - 1; j++) + _vertices[j] = _vertices[j + 1]; + + for (int row = delVert; row < _numVerts - 1; row++) + MoveRowUp(row, _numVerts); + + for (int col = delVert; col < _numVerts - 1; col++) + MoveColLeft(col, _numVerts - 1); + } + _numVerts--; // one less vertex + } + + private void MoveRowUp(int row, int length) + { + for (int col = 0; col < length; col++) + _matrix[row, col] = _matrix[row + 1, col]; + } + + private void MoveColLeft(int col, int length) + { + for (int row = 0; row < length; row++) + _matrix[row, col] = _matrix[row, col + 1]; + } + + #endregion + + #region Internal Staic methods + internal static IEnumerable GetSortedItems(List> fields) where T : class + { + int[] sortOrder = GetTopologicalSortOrder(fields); + var list = new List(); + for (int i = 0; i < sortOrder.Length; i++) + { + var field = fields[sortOrder[i]]; + list.Add(field.Item.Value); + } + list.Reverse(); + return list; + } + + internal static int[] GetTopologicalSortOrder(List> fields) where T : class + { + var g = new TopologicalSorter(fields.Count()); + var indexes = new Dictionary(); + + //add vertices + for (int i = 0; i < fields.Count(); i++) + { + indexes[fields[i].Alias.ToLower()] = g.AddVertex(i); + } + + //add edges + for (int i = 0; i < fields.Count; i++) + { + if (fields[i].DependsOn != null) + { + for (int j = 0; j < fields[i].DependsOn.Length; j++) + { + g.AddEdge(i, + indexes[fields[i].DependsOn[j].ToLower()]); + } + } + } + + int[] result = g.Sort(); + return result; + } + #endregion + + internal class DependencyField where T : class + { + public DependencyField() + { + } + + public DependencyField(string @alias, string[] dependsOn, Lazy item) + { + Alias = alias; + DependsOn = dependsOn; + Item = item; + } + + public string Alias { get; set; } + public string[] DependsOn { get; set; } + public Lazy Item { get; set; } + } + } +} \ No newline at end of file diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index 06999311dc..8c26a1824c 100644 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -702,9 +702,11 @@ + + diff --git a/src/Umbraco.Tests/Persistence/Repositories/ContentTypeRepositoryTest.cs b/src/Umbraco.Tests/Persistence/Repositories/ContentTypeRepositoryTest.cs index d020228361..c02030d75e 100644 --- a/src/Umbraco.Tests/Persistence/Repositories/ContentTypeRepositoryTest.cs +++ b/src/Umbraco.Tests/Persistence/Repositories/ContentTypeRepositoryTest.cs @@ -249,17 +249,18 @@ namespace Umbraco.Tests.Persistence.Repositories SortOrder = 1, DataTypeDefinitionId = -88 }; - var list = new List {urlAlias}; - ((ContentType) contentType).PropertyTypes = list; + + var addedPropertyType = contentType.AddPropertyType(urlAlias); repository.AddOrUpdate(contentType); unitOfWork.Commit(); // Assert var updated = repository.Get(1046); + Assert.That(addedPropertyType, Is.True); Assert.That(updated.PropertyGroups.Count(), Is.EqualTo(2)); Assert.That(updated.PropertyTypes.Count(), Is.EqualTo(5)); Assert.That(updated.PropertyTypes.Any(x => x.Alias == "urlAlias"), Is.True); - Assert.AreEqual(updated.PropertyTypes.First(x => x.Alias == "urlAlias").PropertyGroupId, default(int)); + Assert.That(updated.PropertyTypes.First(x => x.Alias == "urlAlias").PropertyGroupId, Is.Null); } [Test] diff --git a/src/Umbraco.Tests/Services/Importing/ImportResources.Designer.cs b/src/Umbraco.Tests/Services/Importing/ImportResources.Designer.cs new file mode 100644 index 0000000000..fe580b782b --- /dev/null +++ b/src/Umbraco.Tests/Services/Importing/ImportResources.Designer.cs @@ -0,0 +1,140 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.18033 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace Umbraco.Tests.Services.Importing { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class ImportResources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal ImportResources() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Umbraco.Tests.Services.Importing.ImportResources", typeof(ImportResources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized string similar to <?xml version="1.0" encoding="UTF-8" standalone="no"?> + ///<umbPackage> + /// <files /> + /// <info> + /// <package> + /// <name>DocTypeError</name> + /// <version>1</version> + /// <license url="http://www.opensource.org/licenses/mit-license.php">Personal license</license> + /// <url>http://www.iseli-webconsulting.de</url> + /// <requirements> + /// <major>3</major> + /// <minor>0</minor> + /// <patch>0</patch> + /// </requirements> + /// </package> + /// <author> + /// <name>Iseli Webconsulting</name> [rest of string was truncated]";. + /// + internal static string InheritedDocTypes_Package { + get { + return ResourceManager.GetString("InheritedDocTypes_Package", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to <?xml version="1.0" encoding="UTF-8" standalone="no"?> + ///<umbPackage> + /// <files> + /// <file> + /// <guid>Map.cshtml</guid> + /// <orgPath>/macroScripts</orgPath> + /// <orgName>Map.cshtml</orgName> + /// </file> + /// <file> + /// <guid>AccountController.cs</guid> + /// <orgPath>/App_Code</orgPath> + /// <orgName>AccountController.cs</orgName> + /// </file> + /// <file> + /// <guid>ContactController.cs</guid> + /// <orgPath>/App_Code</orgPath> + /// <orgName>ContactController.cs</orgName> + /// </file> + /// [rest of string was truncated]";. + /// + internal static string StandardMvc_Package { + get { + return ResourceManager.GetString("StandardMvc_Package", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to <?xml version="1.0" encoding="UTF-8" standalone="no"?> + ///<umbPackage> + /// <files> + /// <file> + /// <guid>uBlogsy.BusinessLogic.dll</guid> + /// <orgPath>/bin</orgPath> + /// <orgName>uBlogsy.BusinessLogic.dll</orgName> + /// </file> + /// <file> + /// <guid>uBlogsy.BusinessLogic.pdb</guid> + /// <orgPath>/bin</orgPath> + /// <orgName>uBlogsy.BusinessLogic.pdb</orgName> + /// </file> + /// <file> + /// <guid>uBlogsy.Common.dll</guid> + /// <orgPath>/bin</orgPath> + /// <orgName>uBlogsy.Common.dll</orgNam [rest of string was truncated]";. + /// + internal static string uBlogsy_Package { + get { + return ResourceManager.GetString("uBlogsy_Package", resourceCulture); + } + } + } +} diff --git a/src/Umbraco.Tests/Services/Importing/ImportResources.resx b/src/Umbraco.Tests/Services/Importing/ImportResources.resx new file mode 100644 index 0000000000..6fd3b9cf87 --- /dev/null +++ b/src/Umbraco.Tests/Services/Importing/ImportResources.resx @@ -0,0 +1,130 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + inheriteddoctypes-package.xml;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 + + + standardmvc-package.xml;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 + + + ublogsy-package.xml;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 + + \ No newline at end of file diff --git a/src/Umbraco.Tests/Services/Importing/InheritedDocTypes-Package.xml b/src/Umbraco.Tests/Services/Importing/InheritedDocTypes-Package.xml new file mode 100644 index 0000000000..29e1f62b6b --- /dev/null +++ b/src/Umbraco.Tests/Services/Importing/InheritedDocTypes-Package.xml @@ -0,0 +1,445 @@ + + + + + + DocTypeError + 1 + Personal license + http://www.iseli-webconsulting.de + + 3 + 0 + 0 + + + + Iseli Webconsulting + http://www.iseli-webconsulting.de + + + + + + + MR Basisseite + MRBasePage + folder.gif + folder.png + Basistyp für alle Seiten der MR-Racing Website. + False + + + + + + + + Beschreibung + description + 60b7dabf-99cd-41eb-b8e9-4d2e669bbde9 + 1251c96c-185c-4e9b-93f4-b48205573cbd + Metadaten + False + + + + + + Keywords + keywords + 60b7dabf-99cd-41eb-b8e9-4d2e669bbde9 + 1251c96c-185c-4e9b-93f4-b48205573cbd + Metadaten + False + + + + + + In der Navigation ausblenden + hideInNavigation + 38b352c1-e9f8-4fd8-9324-9a2eab06d97a + 92897bc6-a5f3-4ffe-ae27-f2e7e33dda49 + + + False + + + + + + + + 6 + Metadaten + + + + + + MR Startseite + MRStartPage + folder.gif + folder.png + Die Startseite des Internetauftritts von MR Racing. + True + MRBasePage + + + + MRStartPage + + + MRContentPage + MRNewsSummary + + + + Facebook App ID + facebookAppID + ec15c1e5-9d90-422a-aa52-4f7622c63bea + 0cc0eba1-9960-42c9-bf9b-60e150b429ae + Facebook + False + + + + + + Facebook Like URL + facebookLikeUrl + ec15c1e5-9d90-422a-aa52-4f7622c63bea + 0cc0eba1-9960-42c9-bf9b-60e150b429ae + Facebook + False + + + + + + Facebook Seite URL + facebookSiteUrl + ec15c1e5-9d90-422a-aa52-4f7622c63bea + 0cc0eba1-9960-42c9-bf9b-60e150b429ae + Facebook + False + + + + + + Titel der Webseite + websiteTitle + ec15c1e5-9d90-422a-aa52-4f7622c63bea + 0cc0eba1-9960-42c9-bf9b-60e150b429ae + Metadaten + True + + + + + + Autor + author + ec15c1e5-9d90-422a-aa52-4f7622c63bea + 0cc0eba1-9960-42c9-bf9b-60e150b429ae + Metadaten + False + + + + + + Generator + generator + ec15c1e5-9d90-422a-aa52-4f7622c63bea + 0cc0eba1-9960-42c9-bf9b-60e150b429ae + Metadaten + False + + + + + + Web-Autor + webAuthor + ec15c1e5-9d90-422a-aa52-4f7622c63bea + 0cc0eba1-9960-42c9-bf9b-60e150b429ae + Metadaten + False + + + + + + Titel + titleBoxRight + ec15c1e5-9d90-422a-aa52-4f7622c63bea + 0cc0eba1-9960-42c9-bf9b-60e150b429ae + Angebot Rechts + False + + + + + + Newstitel + newsTitle + ec15c1e5-9d90-422a-aa52-4f7622c63bea + 0cc0eba1-9960-42c9-bf9b-60e150b429ae + News + True + + + + + + Anzanl News + numberOfNews + 1413afcb-d19a-4173-8e9a-68288d2a73b8 + 2e6d3631-066e-44b8-aec4-96f09099b2b5 + News + True + + + + + + Link + linkBoxRight + 158aa029-24ed-4948-939e-c3da209e5fba + a6857c73-d6e9-480c-b6e6-f15f6ad11125 + Angebot Rechts + False + + + + + + Bild + imageBoxRight + ead69342-f06d-4253-83ac-28000225583b + 93929b9a-93a2-4e2a-b239-d99334440a59 + Angebot Rechts + False + + + + + + Bildbreite + imageWidthBoxRight + 1413afcb-d19a-4173-8e9a-68288d2a73b8 + 2e6d3631-066e-44b8-aec4-96f09099b2b5 + Angebot Rechts + False + ^([6-9][0-9]|1[0-9]{2}|2[0-7][0-9]|280)$ + + + + Inhalt + contentBoxRight + 60b7dabf-99cd-41eb-b8e9-4d2e669bbde9 + 1251c96c-185c-4e9b-93f4-b48205573cbd + Angebot Rechts + False + + + + + + Titel + titleBoxMiddle + ec15c1e5-9d90-422a-aa52-4f7622c63bea + 0cc0eba1-9960-42c9-bf9b-60e150b429ae + Angebot Mitte + False + + + + + + Link + linkBoxMiddle + 158aa029-24ed-4948-939e-c3da209e5fba + a6857c73-d6e9-480c-b6e6-f15f6ad11125 + Angebot Mitte + False + + + + + + Bild + imageBoxMiddle + ead69342-f06d-4253-83ac-28000225583b + 93929b9a-93a2-4e2a-b239-d99334440a59 + Angebot Mitte + False + + + + + + Bildbreite + imageWidthBoxMiddle + 1413afcb-d19a-4173-8e9a-68288d2a73b8 + 2e6d3631-066e-44b8-aec4-96f09099b2b5 + Angebot Mitte + False + ^([6-9][0-9]|1[0-9]{2}|2[0-7][0-9]|280)$ + + + + Inhalt + contentBoxMiddle + 60b7dabf-99cd-41eb-b8e9-4d2e669bbde9 + 1251c96c-185c-4e9b-93f4-b48205573cbd + Angebot Mitte + False + + + + + + Titel + titleBoxLeft + ec15c1e5-9d90-422a-aa52-4f7622c63bea + 0cc0eba1-9960-42c9-bf9b-60e150b429ae + Angebot Links + False + + + + + + Link + linkBoxLeft + 158aa029-24ed-4948-939e-c3da209e5fba + a6857c73-d6e9-480c-b6e6-f15f6ad11125 + Angebot Links + False + + + + + + Bild + imageBoxLeft + ead69342-f06d-4253-83ac-28000225583b + 93929b9a-93a2-4e2a-b239-d99334440a59 + Angebot Links + False + + + + + + Bildbreite + imageWidthBoxLeft + 1413afcb-d19a-4173-8e9a-68288d2a73b8 + 2e6d3631-066e-44b8-aec4-96f09099b2b5 + Angebot Links + False + ^([6-9][0-9]|1[0-9]{2}|2[0-7][0-9]|280)$ + + + + Inhalt + contentBoxLeft + 60b7dabf-99cd-41eb-b8e9-4d2e669bbde9 + 1251c96c-185c-4e9b-93f4-b48205573cbd + Angebot Links + False + + + + + + Inhaltstitel + contentTitle + ec15c1e5-9d90-422a-aa52-4f7622c63bea + 0cc0eba1-9960-42c9-bf9b-60e150b429ae + Inhalt + False + + + + + + Inhaltstitel verbergen + hideContentTitle + 38b352c1-e9f8-4fd8-9324-9a2eab06d97a + 92897bc6-a5f3-4ffe-ae27-f2e7e33dda49 + Inhalt + False + + + + + + Inhaltspadding weglassen + hideContentPadding + 38b352c1-e9f8-4fd8-9324-9a2eab06d97a + 92897bc6-a5f3-4ffe-ae27-f2e7e33dda49 + Inhalt + False + + + + + + Inhalt + content + 5e9b75ae-face-41c8-b47e-5f4b0fd82f83 + ca90c950-0aff-4e72-b976-a30b1ac57dad + Inhalt + False + + + + + + + + 9 + Inhalt + + + 10 + Angebot Links + + + 11 + Angebot Mitte + + + 12 + Angebot Rechts + + + 13 + News + + + 14 + Facebook + + + 15 + Metadaten + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Umbraco.Tests/Services/Importing/PackageImportTests.cs b/src/Umbraco.Tests/Services/Importing/PackageImportTests.cs new file mode 100644 index 0000000000..287ebd0c94 --- /dev/null +++ b/src/Umbraco.Tests/Services/Importing/PackageImportTests.cs @@ -0,0 +1,192 @@ +using System.Linq; +using System.Xml.Linq; +using NUnit.Framework; + +namespace Umbraco.Tests.Services.Importing +{ + [TestFixture, RequiresSTA] + public class PackageImportTests : BaseServiceTest + { + [SetUp] + public override void Initialize() + { + base.Initialize(); + } + + [TearDown] + public override void TearDown() + { + base.TearDown(); + } + + [Test] + public void PackagingService_Can_Import_uBlogsy_ContentTypes_And_Verify_Structure() + { + // Arrange + string strXml = ImportResources.uBlogsy_Package; + var xml = XElement.Parse(strXml); + var dataTypeElement = xml.Descendants("DataTypes").First(); + var templateElement = xml.Descendants("Templates").First(); + var docTypeElement = xml.Descendants("DocumentTypes").First(); + var packagingService = ServiceContext.PackagingService; + + // Act + var dataTypes = packagingService.ImportDataTypeDefinitions(dataTypeElement); + var templates = packagingService.ImportTemplates(templateElement); + var contentTypes = packagingService.ImportContentTypes(docTypeElement); + + var numberOfTemplates = (from doc in templateElement.Elements("Template") select doc).Count(); + var numberOfDocTypes = (from doc in docTypeElement.Elements("DocumentType") select doc).Count(); + + // Assert + Assert.That(dataTypes.Any(), Is.True); + Assert.That(templates.Any(), Is.True); + Assert.That(templates.Count(), Is.EqualTo(numberOfTemplates)); + Assert.That(contentTypes.Any(), Is.True); + Assert.That(contentTypes.Count(), Is.EqualTo(numberOfDocTypes)); + + var uBlogsyBaseDocType = contentTypes.First(x => x.Alias == "uBlogsyBaseDocType"); + Assert.That(uBlogsyBaseDocType.PropertyTypes.Count(), Is.EqualTo(5)); + Assert.That(uBlogsyBaseDocType.PropertyGroups.Any(), Is.False); + + var uBlogsyBasePage = contentTypes.First(x => x.Alias == "uBlogsyBasePage"); + Assert.That(uBlogsyBasePage.ContentTypeCompositionExists("uBlogsyBaseDocType"), Is.True); + Assert.That(uBlogsyBasePage.PropertyTypes.Count(), Is.EqualTo(7)); + Assert.That(uBlogsyBasePage.PropertyGroups.Count(), Is.EqualTo(3)); + Assert.That(uBlogsyBasePage.PropertyGroups["Content"].PropertyTypes.Count(), Is.EqualTo(3)); + Assert.That(uBlogsyBasePage.PropertyGroups["SEO"].PropertyTypes.Count(), Is.EqualTo(3)); + Assert.That(uBlogsyBasePage.PropertyGroups["Navigation"].PropertyTypes.Count(), Is.EqualTo(1)); + Assert.That(uBlogsyBasePage.CompositionPropertyTypes.Count(), Is.EqualTo(12)); + + var uBlogsyLanding = contentTypes.First(x => x.Alias == "uBlogsyLanding"); + Assert.That(uBlogsyLanding.ContentTypeCompositionExists("uBlogsyBasePage"), Is.True); + Assert.That(uBlogsyLanding.ContentTypeCompositionExists("uBlogsyBaseDocType"), Is.True); + Assert.That(uBlogsyLanding.PropertyTypes.Count(), Is.EqualTo(5)); + Assert.That(uBlogsyLanding.PropertyGroups.Count(), Is.EqualTo(2)); + Assert.That(uBlogsyLanding.CompositionPropertyTypes.Count(), Is.EqualTo(17)); + Assert.That(uBlogsyLanding.CompositionPropertyGroups.Count(), Is.EqualTo(5)); + } + + [Test] + public void PackagingService_Can_Import_Inherited_ContentTypes_And_Verify_PropertyGroups_And_PropertyTypes() + { + // Arrange + string strXml = ImportResources.InheritedDocTypes_Package; + var xml = XElement.Parse(strXml); + var dataTypeElement = xml.Descendants("DataTypes").First(); + var templateElement = xml.Descendants("Templates").First(); + var docTypeElement = xml.Descendants("DocumentTypes").First(); + var packagingService = ServiceContext.PackagingService; + + // Act + var dataTypes = packagingService.ImportDataTypeDefinitions(dataTypeElement); + var templates = packagingService.ImportTemplates(templateElement); + var contentTypes = packagingService.ImportContentTypes(docTypeElement); + + var numberOfDocTypes = (from doc in docTypeElement.Elements("DocumentType") select doc).Count(); + + // Assert + Assert.That(dataTypes.Any(), Is.False); + Assert.That(templates.Any(), Is.False); + Assert.That(contentTypes.Any(), Is.True); + Assert.That(contentTypes.Count(), Is.EqualTo(numberOfDocTypes)); + + var mRBasePage = contentTypes.First(x => x.Alias == "MRBasePage"); + Assert.That(mRBasePage.PropertyTypes.Count(), Is.EqualTo(3)); + Assert.That(mRBasePage.PropertyGroups.Count(), Is.EqualTo(1)); + Assert.That(mRBasePage.PropertyGroups["Metadaten"].PropertyTypes.Count(), Is.EqualTo(2)); + + var mRStartPage = contentTypes.First(x => x.Alias == "MRStartPage"); + Assert.That(mRStartPage.ContentTypeCompositionExists("MRBasePage"), Is.True); + Assert.That(mRStartPage.PropertyTypes.Count(), Is.EqualTo(28)); + Assert.That(mRStartPage.PropertyGroups.Count(), Is.EqualTo(7)); + + var propertyGroups = mRStartPage.CompositionPropertyGroups.Where(x => x.Name == "Metadaten"); + var propertyTypes = propertyGroups.SelectMany(x => x.PropertyTypes); + Assert.That(propertyGroups.Count(), Is.EqualTo(2)); + Assert.That(propertyTypes.Count(), Is.EqualTo(6)); + } + + [Test] + public void PackagingService_Can_Import_Template_Package_Xml() + { + // Arrange + string strXml = ImportResources.StandardMvc_Package; + var xml = XElement.Parse(strXml); + var element = xml.Descendants("Templates").First(); + var packagingService = ServiceContext.PackagingService; + + // Act + var templates = packagingService.ImportTemplates(element); + var numberOfTemplates = (from doc in element.Elements("Template") select doc).Count(); + + // Assert + Assert.That(templates, Is.Not.Null); + Assert.That(templates.Any(), Is.True); + Assert.That(templates.Count(), Is.EqualTo(numberOfTemplates)); + } + + [Test] + public void PackagingService_Can_Import_StandardMvc_ContentTypes_Package_Xml() + { + // Arrange + string strXml = ImportResources.StandardMvc_Package; + var xml = XElement.Parse(strXml); + var dataTypeElement = xml.Descendants("DataTypes").First(); + var templateElement = xml.Descendants("Templates").First(); + var docTypeElement = xml.Descendants("DocumentTypes").First(); + var packagingService = ServiceContext.PackagingService; + + // Act + var dataTypeDefinitions = packagingService.ImportDataTypeDefinitions(dataTypeElement); + var templates = packagingService.ImportTemplates(templateElement); + var contentTypes = packagingService.ImportContentTypes(docTypeElement); + var numberOfDocTypes = (from doc in docTypeElement.Elements("DocumentType") select doc).Count(); + + // Assert + Assert.That(dataTypeDefinitions, Is.Not.Null); + Assert.That(dataTypeDefinitions.Any(), Is.True); + Assert.That(templates.Any(), Is.True); + Assert.That(contentTypes, Is.Not.Null); + Assert.That(contentTypes.Any(), Is.True); + Assert.That(contentTypes.Count(), Is.EqualTo(numberOfDocTypes)); + Assert.That(contentTypes.Count(x => x.ParentId == -1), Is.EqualTo(1)); + + var contentMaster = contentTypes.First(x => x.Alias == "ContentMaster"); + Assert.That(contentMaster.PropertyTypes.Count(), Is.EqualTo(3)); + Assert.That(contentMaster.PropertyGroups.Count(), Is.EqualTo(1)); + Assert.That(contentMaster.PropertyGroups["SEO"].PropertyTypes.Count(), Is.EqualTo(3)); + Assert.That(contentMaster.ContentTypeCompositionExists("Base"), Is.True); + + var propertyGroupId = contentMaster.PropertyGroups["SEO"].Id; + Assert.That(contentMaster.PropertyGroups["SEO"].PropertyTypes.Any(x => x.PropertyGroupId.Value != propertyGroupId), Is.False); + } + + [Test] + public void PackagingService_Can_Import_Content_Package_Xml() + { + // Arrange + string strXml = ImportResources.StandardMvc_Package; + var xml = XElement.Parse(strXml); + var dataTypeElement = xml.Descendants("DataTypes").First(); + var docTypesElement = xml.Descendants("DocumentTypes").First(); + var element = xml.Descendants("DocumentSet").First(); + var packagingService = ServiceContext.PackagingService; + + // Act + var dataTypeDefinitions = packagingService.ImportDataTypeDefinitions(dataTypeElement); + var contentTypes = packagingService.ImportContentTypes(docTypesElement); + var contents = packagingService.ImportContent(element); + var numberOfDocs = (from doc in element.Descendants() + where (string) doc.Attribute("isDoc") == "" + select doc).Count(); + + // Assert + Assert.That(contents, Is.Not.Null); + Assert.That(dataTypeDefinitions.Any(), Is.True); + Assert.That(contentTypes.Any(), Is.True); + Assert.That(contents.Any(), Is.True); + Assert.That(contents.Count(), Is.EqualTo(numberOfDocs)); + } + } +} \ No newline at end of file diff --git a/src/Umbraco.Tests/Services/Importing/StandardMvc-Package.xml b/src/Umbraco.Tests/Services/Importing/StandardMvc-Package.xml new file mode 100644 index 0000000000..ddf3d5e66f --- /dev/null +++ b/src/Umbraco.Tests/Services/Importing/StandardMvc-Package.xml @@ -0,0 +1,2278 @@ + + + + + Map.cshtml + /macroScripts + Map.cshtml + + + AccountController.cs + /App_Code + AccountController.cs + + + ContactController.cs + /App_Code + ContactController.cs + + + LuceneHighlightHelper.cs + /App_Code + LuceneHighlightHelper.cs + + + default.js + /scripts + default.js + + + jquery.timers.js + /scripts + jquery.timers.js + + + Creative_Founds_Square.jpg + /images + Creative_Founds_Square.jpg + + + header_bg.png + /images + header_bg.png + + + li_bg.gif + /images + li_bg.gif + + + li_white_bg.gif + /images + li_white_bg.gif + + + logo.png + /images + logo.png + + + nav_li_bg.png + /images + nav_li_bg.png + + + search_bg.png + /images + search_bg.png + + + search_btn_bg.png + /images + search_btn_bg.png + + + slider_bg.png + /images + slider_bg.png + + + twitter_square.png + /images + twitter_square.png + + + umbraco_Square.jpg + /images + umbraco_Square.jpg + + + web_applications.jpg + /images + web_applications.jpg + + + Lucene.Net.Contrib.Highlighter.dll + /bin + Lucene.Net.Contrib.Highlighter.dll + + + StandardWebsiteInstall.ascx.cs + /usercontrols + StandardWebsiteInstall.ascx.cs + + + Affiliations.cshtml + /Views/Partials + Affiliations.cshtml + + + ContactForm.cshtml + /Views/Partials + ContactForm.cshtml + + + ContentPanels.cshtml + /Views/Partials + ContentPanels.cshtml + + + LeftNavigation.cshtml + /Views/Partials + LeftNavigation.cshtml + + + LoginForm.cshtml + /Views/Partials + LoginForm.cshtml + + + dice.png + /media/1824 + dice.png + + + dice_thumb.jpg + /media/1824 + dice_thumb.jpg + + + cap.png + /media/1813 + cap.png + + + cap_thumb.jpg + /media/1813 + cap_thumb.jpg + + + chat.jpg + /media/2075 + chat.jpg + + + chat_thumb.jpg + /media/2075 + chat_thumb.jpg + + + umbraco_logo.png + /media/1477 + umbraco_logo.png + + + umbraco_logo_thumb.jpg + /media/1477 + umbraco_logo_thumb.jpg + + + StandardWebsiteInstall.ascx + /usercontrols + StandardWebsiteInstall.ascx + + + + + StandardWebsiteMVC + 2.0 + MIT license + http://our.umbraco.org/projects/starter-kits/standard-website-mvc + + 3 + 0 + 0 + + + + Chris Koiak + http://www.creativefounds.co.uk + + + + + + + + + + + Built by Creative Founds +

Web ApplicationsCreative Founds design and build first class software solutions that deliver big results. We provide ASP.NET web and mobile applications, Umbraco development service & technical consultancy.

+

www.creativefounds.co.uk

]]> +
+ + Umbraco Development +

UmbracoUmbraco the the leading ASP.NET open source CMS, under pinning over 150,000 websites. Our Certified Developers are experts in developing high performance and feature rich websites.

]]> +
+ + Contact Us +

Contact Us on TwitterWe'd love to hear how this package has helped you and how it can be improved. Get in touch on the project website or via twitter

]]> +
+ +
Standard Website MVC, Company Address, Glasgow, Postcode
+ Copyright &copy; 2012 Your Company + http://www.umbraco.org + /media/1477/umbraco_logo.png + + + + + + Standard Site for Umbraco by Koiak + + + 0 + + + About Us +

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur dictum, nisi non gravida blandit, odio nulla ultrices orci, quis blandit tortor libero vitae massa. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Nulla at velit lacus.

+

Vivamus dictum, lorem vitae bold text, libero link text elit, vitae tincidunt ante nibh vitae lectus. Praesent molestie justo non mi dapibus et venenatis ante facilisis. Morbi gravida molestie cursus.

+

Sub Section

+

Aliquam at est dui. Pellentesque tortor risus, congue eget pretium ut, elementum eu velit. Phasellus tempus leo sed elit tempus vestibulum. Integer mollis arcu porta leo vulputate dignissim.

+
    +
  • List Item 1
  • +
  • List Item 2
  • +
  • List Item 3
  • +
+
    +
  1. Numbered Item 1
  2. +
  3. Numbered Item 2
  4. +
  5. Numbered Item 3
  6. +
+

In suscipit lectus vitae nibh faucibus vel lobortis est ullamcorper. Morbi risus nisl, sodales egestas placerat nec, cursus vel tellus. Vivamus aliquet sagittis pellentesque. Nulla rutrum neque nec metus mattis volutpat.

+

Vivamus egestas enim sed augue eleifend id tristique magna tempus. Nunc ullamcorper scelerisque ante quis consectetur.

+

Curabitur vel dui a enim adipiscing malesuada non quis velit.

]]> +
+ + + <description><![CDATA[]]></description> + <keywords><![CDATA[]]></keywords> + <umbracoNaviHide>0</umbracoNaviHide> + <Standard id="1074" parentID="1073" level="3" creatorID="0" sortOrder="0" createDate="2013-02-17T09:04:41" updateDate="2013-02-17T09:04:46" nodeName="Sub Navigation 1" urlName="sub-navigation-1" path="-1,1072,1073,1074" isDoc="" nodeType="1058" creatorName="admin" writerName="admin" writerID="0" template="1053"> + <bodyText><![CDATA[]]></bodyText> + <contentPanels><![CDATA[]]></contentPanels> + <title /> + <description><![CDATA[]]></description> + <keywords><![CDATA[]]></keywords> + <umbracoNaviHide>0</umbracoNaviHide> + <Standard id="1075" parentID="1074" level="4" creatorID="0" sortOrder="0" createDate="2013-02-17T09:04:41" updateDate="2013-02-17T09:04:46" nodeName="3rd level nav 2" urlName="3rd-level-nav-2" path="-1,1072,1073,1074,1075" isDoc="" nodeType="1058" creatorName="admin" writerName="admin" writerID="0" template="1053"> + <bodyText><![CDATA[]]></bodyText> + <contentPanels><![CDATA[]]></contentPanels> + <title /> + <description><![CDATA[]]></description> + <keywords><![CDATA[]]></keywords> + <umbracoNaviHide>0</umbracoNaviHide> + </Standard> + </Standard> + <Standard id="1076" parentID="1073" level="3" creatorID="0" sortOrder="1" createDate="2013-02-17T09:04:41" updateDate="2013-02-17T09:04:46" nodeName="Sub Navigation 2" urlName="sub-navigation-2" path="-1,1072,1073,1076" isDoc="" nodeType="1058" creatorName="admin" writerName="admin" writerID="0" template="1053"> + <bodyText><![CDATA[]]></bodyText> + <contentPanels><![CDATA[]]></contentPanels> + <title /> + <description><![CDATA[]]></description> + <keywords><![CDATA[]]></keywords> + <umbracoNaviHide>0</umbracoNaviHide> + </Standard> + </Standard> + <Standard id="1077" parentID="1072" level="2" creatorID="0" sortOrder="1" createDate="2013-02-17T09:04:41" updateDate="2013-02-17T09:10:47" nodeName="News" urlName="news" path="-1,1072,1077" isDoc="" nodeType="1058" creatorName="admin" writerName="admin" writerID="0" template="1046"> + <bodyText><![CDATA[<h2>News</h2>]]></bodyText> + <contentPanels><![CDATA[]]></contentPanels> + <title /> + <description><![CDATA[]]></description> + <keywords><![CDATA[]]></keywords> + <umbracoNaviHide>0</umbracoNaviHide> + <NewsArticle id="1078" parentID="1077" level="3" creatorID="0" sortOrder="0" createDate="2013-02-17T09:04:42" updateDate="2013-02-17T09:11:22" nodeName="Article 1" urlName="article-1" path="-1,1072,1077,1078" isDoc="" nodeType="1063" creatorName="admin" writerName="admin" writerID="0" template="1053"> + <articleSummary><![CDATA[Here is an article summary, you can add as much of a description as you require.]]></articleSummary> + <articleDate>2012-11-08T00:00:00</articleDate> + <bodyText> + <![CDATA[<h2>Your first Article</h2> +<p><span><strong>Aliquam erat volutpat. Sed laoreet leo id nisi convallis sollicitudin sodales orci adipiscing. Sed a dolor ipsum. Quisque ut quam eu arcu placerat rhoncus vel et mi. Pellentesque sed est nisl.</strong> </span></p> +<p><span>Aliquam at orci justo, id pharetra augue. Aenean ut nunc ut nibh interdum scelerisque ut ac mi. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec vehicula dictum lectus in interdum. Fusce pellentesque elit nec metus convallis id porttitor felis laoreet. Nunc vitae enim quam.</span></p>]]> + </bodyText> + <contentPanels><![CDATA[]]></contentPanels> + <title /> + <description><![CDATA[]]></description> + <keywords><![CDATA[]]></keywords> + <umbracoNaviHide>0</umbracoNaviHide> + </NewsArticle> + </Standard> + <Standard id="1079" parentID="1072" level="2" creatorID="0" sortOrder="2" createDate="2013-02-17T09:04:42" updateDate="2013-02-17T09:10:55" nodeName="Clients" urlName="clients" path="-1,1072,1079" isDoc="" nodeType="1058" creatorName="admin" writerName="admin" writerID="0" template="1053"> + <bodyText> + <![CDATA[<h2>Clients</h2> +<p><strong>This is a standard content page.</strong></p> +<p><span>Vestibulum malesuada aliquet ante, vitae ullamcorper felis faucibus vel. Vestibulum condimentum faucibus tellus porta ultrices. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. </span></p> +<p><span>Cras at auctor orci. Praesent facilisis erat nec odio consequat at posuere ligula pretium. Nulla eget felis id nisl volutpat pellentesque. Ut id augue id ligula placerat rutrum a nec purus. Maecenas sed lectus ac mi pellentesque luctus quis sit amet turpis. Vestibulum adipiscing convallis vestibulum. </span></p> +<p><span>Duis condimentum lectus at orci placerat vitae imperdiet lorem cursus. Duis hendrerit porta lorem, non suscipit quam consectetur vitae. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean elit augue, tincidunt nec tincidunt id, elementum vel est.</span></p>]]> + </bodyText> + <contentPanels><![CDATA[]]></contentPanels> + <title /> + <description><![CDATA[]]></description> + <keywords><![CDATA[]]></keywords> + <umbracoNaviHide>0</umbracoNaviHide> + </Standard> + <ContactForm id="1080" parentID="1072" level="2" creatorID="0" sortOrder="3" createDate="2013-02-17T09:04:42" updateDate="2013-02-17T09:04:46" nodeName="Contact Us" urlName="contact-us" path="-1,1072,1080" isDoc="" nodeType="1059" creatorName="admin" writerName="admin" writerID="0" template="1048"> + <recipientEmailAddress>chriskoiak@gmail.com</recipientEmailAddress> + <emailSubject>Standard Website Contact Form</emailSubject> + <thankYouPage>1124</thankYouPage> + <senderEmailAddress>chriskoiak@gmail.com</senderEmailAddress> + <bodyText> + <![CDATA[<h2>Contact Us</h2> +<p>Please get in touch!</p> +<?UMBRACO_MACRO macroAlias="Map" />]]> + </bodyText> + <contentPanels><![CDATA[]]></contentPanels> + <title /> + <description><![CDATA[]]></description> + <keywords><![CDATA[]]></keywords> + <umbracoNaviHide>0</umbracoNaviHide> + <Standard id="1081" parentID="1080" level="3" creatorID="0" sortOrder="0" createDate="2013-02-17T09:04:42" updateDate="2013-02-17T09:04:46" nodeName="Thank You" urlName="thank-you" path="-1,1072,1080,1081" isDoc="" nodeType="1058" creatorName="admin" writerName="admin" writerID="0" template="1053"> + <bodyText><![CDATA[<p><strong>Email sent successfully</strong></p>]]></bodyText> + <contentPanels><![CDATA[]]></contentPanels> + <title /> + <description><![CDATA[]]></description> + <keywords><![CDATA[]]></keywords> + <umbracoNaviHide>1</umbracoNaviHide> + </Standard> + </ContactForm> + <Standard id="1082" parentID="1072" level="2" creatorID="0" sortOrder="4" createDate="2013-02-17T09:04:42" updateDate="2013-02-17T09:10:47" nodeName="Search" urlName="search" path="-1,1072,1082" isDoc="" nodeType="1058" creatorName="admin" writerName="admin" writerID="0" template="1051"> + <bodyText><![CDATA[<h2>Search</h2>]]></bodyText> + <contentPanels><![CDATA[]]></contentPanels> + <title /> + <description><![CDATA[]]></description> + <keywords><![CDATA[]]></keywords> + <umbracoNaviHide>0</umbracoNaviHide> + </Standard> + <Standard id="1083" parentID="1072" level="2" creatorID="0" sortOrder="5" createDate="2013-02-17T09:04:43" updateDate="2013-02-17T09:10:47" nodeName="Sitemap" urlName="sitemap" path="-1,1072,1083" isDoc="" nodeType="1058" creatorName="admin" writerName="admin" writerID="0" template="1052"> + <bodyText> + <![CDATA[<h2>Sitemap</h2> +<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur dictum, nisi non gravida blandit, odio nulla ultrices orci, quis blandit tortor libero vitae massa.<a href="/contact-us.aspx"><br /></a></p>]]> + </bodyText> + <contentPanels><![CDATA[]]></contentPanels> + <title /> + <description><![CDATA[]]></description> + <keywords><![CDATA[]]></keywords> + <umbracoNaviHide>0</umbracoNaviHide> + </Standard> + <ClientArea id="1084" parentID="1072" level="2" creatorID="0" sortOrder="6" createDate="2013-02-17T09:04:43" updateDate="2013-02-17T09:04:46" nodeName="Client Area" urlName="client-area" path="-1,1072,1084" isDoc="" nodeType="1056" creatorName="admin" writerName="admin" writerID="0" template="1047"> + <umbracoNaviHide>0</umbracoNaviHide> + <Standard id="1085" parentID="1084" level="3" creatorID="0" sortOrder="0" createDate="2013-02-17T09:04:43" updateDate="2013-02-17T09:04:46" nodeName="Client Area 1" urlName="client-area-1" path="-1,1072,1084,1085" isDoc="" nodeType="1058" creatorName="admin" writerName="admin" writerID="0" template="1053"> + <bodyText><![CDATA[]]></bodyText> + <contentPanels><![CDATA[]]></contentPanels> + <title /> + <description><![CDATA[]]></description> + <keywords><![CDATA[]]></keywords> + <umbracoNaviHide>0</umbracoNaviHide> + <Standard id="1086" parentID="1085" level="4" creatorID="0" sortOrder="0" createDate="2013-02-17T09:04:43" updateDate="2013-02-17T09:04:46" nodeName="Page 1" urlName="page-1" path="-1,1072,1084,1085,1086" isDoc="" nodeType="1058" creatorName="admin" writerName="admin" writerID="0" template="1053"> + <bodyText><![CDATA[]]></bodyText> + <contentPanels><![CDATA[]]></contentPanels> + <title /> + <description><![CDATA[]]></description> + <keywords><![CDATA[]]></keywords> + <umbracoNaviHide>0</umbracoNaviHide> + </Standard> + </Standard> + <Standard id="1087" parentID="1084" level="3" creatorID="0" sortOrder="1" createDate="2013-02-17T09:04:43" updateDate="2013-02-17T09:04:46" nodeName="Client Area 2" urlName="client-area-2" path="-1,1072,1084,1087" isDoc="" nodeType="1058" creatorName="admin" writerName="admin" writerID="0" template="1053"> + <bodyText><![CDATA[]]></bodyText> + <contentPanels><![CDATA[]]></contentPanels> + <title /> + <description><![CDATA[]]></description> + <keywords><![CDATA[]]></keywords> + <umbracoNaviHide>0</umbracoNaviHide> + </Standard> + </ClientArea> + <Standard id="1088" parentID="1072" level="2" creatorID="0" sortOrder="7" createDate="2013-02-17T09:04:44" updateDate="2013-02-17T09:04:46" nodeName="Insufficent Access" urlName="insufficent-access" path="-1,1072,1088" isDoc="" nodeType="1058" creatorName="admin" writerName="admin" writerID="0" template="1053"> + <bodyText> + <![CDATA[<h2>Insufficent Access</h2> +<p>You have tried to access a page you do not have access to.</p>]]> + </bodyText> + <contentPanels><![CDATA[]]></contentPanels> + <title /> + <description><![CDATA[]]></description> + <keywords><![CDATA[]]></keywords> + <umbracoNaviHide>1</umbracoNaviHide> + </Standard> + <Standard id="1089" parentID="1072" level="2" creatorID="0" sortOrder="8" createDate="2013-02-17T09:04:44" updateDate="2013-02-17T09:10:47" nodeName="Login" urlName="login" path="-1,1072,1089" isDoc="" nodeType="1058" creatorName="admin" writerName="admin" writerID="0" template="1050"> + <bodyText><![CDATA[<h2>Login</h2>]]></bodyText> + <contentPanels><![CDATA[]]></contentPanels> + <title /> + <description><![CDATA[]]></description> + <keywords><![CDATA[]]></keywords> + <umbracoNaviHide>1</umbracoNaviHide> + </Standard> + <Slideshow id="1090" parentID="1072" level="2" creatorID="0" sortOrder="9" createDate="2013-02-17T09:04:44" updateDate="2013-02-17T09:04:46" nodeName="Slideshow" urlName="slideshow" path="-1,1072,1090" isDoc="" nodeType="1065" creatorName="admin" writerName="admin" writerID="0" template="0"> + <umbracoNaviHide>0</umbracoNaviHide> + <Slide id="1091" parentID="1090" level="3" creatorID="0" sortOrder="0" createDate="2013-02-17T09:04:44" updateDate="2013-02-17T09:04:46" nodeName="Purple Hat" urlName="purple-hat" path="-1,1072,1090,1091" isDoc="" nodeType="1064" creatorName="admin" writerName="admin" writerID="0" template="0"> + <mainImage>/media/1813/cap.png</mainImage> + <bodyText> + <![CDATA[<h3>Standard Website MVC</h3> +<p>Well hello! This website package demonstrates all the standard functionality of Umbraco. It's a great starting point for <span>starting point for further development or as a prototype.</span></p> +<h3>Creative Founds</h3> +<p>This package was developed by <a href="http://www.twitter.com/chriskoiak" target="_blank">Chris Koiak</a> & <a href="http://www.creativefounds.co.uk" target="_blank">Creative Founds</a>. </p>]]> + </bodyText> + <umbracoNaviHide>1</umbracoNaviHide> + </Slide> + <Slide id="1092" parentID="1090" level="3" creatorID="0" sortOrder="1" createDate="2013-02-17T09:04:44" updateDate="2013-02-17T09:04:46" nodeName="Red Dice" urlName="red-dice" path="-1,1072,1090,1092" isDoc="" nodeType="1064" creatorName="admin" writerName="admin" writerID="0" template="0"> + <mainImage>/media/1824/dice.png</mainImage> + <bodyText> + <![CDATA[<h3>Secure Client Areas</h3> +<p>Make sure you check out the secure client areas and MVC login form,</p> +<h3>Multiple Areas</h3> +<p>You can create different areas for different clients or just the functionality to suit your project.</p>]]> + </bodyText> + <umbracoNaviHide>1</umbracoNaviHide> + </Slide> + <Slide id="1093" parentID="1090" level="3" creatorID="0" sortOrder="2" createDate="2013-02-17T09:04:44" updateDate="2013-02-17T09:04:46" nodeName="Umbraco Speechbubble" urlName="umbraco-speechbubble" path="-1,1072,1090,1093" isDoc="" nodeType="1064" creatorName="admin" writerName="admin" writerID="0" template="0"> + <mainImage>/media/2075/chat.jpg</mainImage> + <bodyText> + <![CDATA[<h3>News List</h3> +<p>The news page is an example of a list of content. Use this as a starting point for building any list of any type</p> +<h3>Contact Form</h3> +<p>The contact form is 100% MVC with strongly type view models.</p>]]> + </bodyText> + <umbracoNaviHide>1</umbracoNaviHide> + </Slide> + </Slideshow> + <ContentPanels id="1094" parentID="1072" level="2" creatorID="0" sortOrder="10" createDate="2013-02-17T09:04:45" updateDate="2013-02-17T09:04:46" nodeName="Content Panels" urlName="content-panels" path="-1,1072,1094" isDoc="" nodeType="1061" creatorName="admin" writerName="admin" writerID="0" template="0"> + <umbracoNaviHide>1</umbracoNaviHide> + <ContentPanel id="1095" parentID="1094" level="3" creatorID="0" sortOrder="0" createDate="2013-02-17T09:04:45" updateDate="2013-02-17T09:04:46" nodeName="Introductory Offers" urlName="introductory-offers" path="-1,1072,1094,1095" isDoc="" nodeType="1060" creatorName="admin" writerName="admin" writerID="0" template="0"> + <bodyText> + <![CDATA[ +<h3>Introductory Offers</h3> + +<p>asdjbasd askdja asio]ywer asduyiuy</p> + +<ul> +<li><a href="/rooms.aspx">related link 1</a></li> + +<li><a href="/rooms.aspx">related link 1</a></li> +</ul> +]]> + </bodyText> + <umbracoNaviHide>1</umbracoNaviHide> + </ContentPanel> + <ContentPanel id="1096" parentID="1094" level="3" creatorID="0" sortOrder="1" createDate="2013-02-17T09:04:45" updateDate="2013-02-17T09:04:46" nodeName="Sample Panel" urlName="sample-panel" path="-1,1072,1094,1096" isDoc="" nodeType="1060" creatorName="admin" writerName="admin" writerID="0" template="0"> + <bodyText> + <![CDATA[<p><strong>Sample Panel</strong></p> +<p>Don't you just love MVC?</p> +<ul> +<li><a href="/rooms.aspx">related link 1</a></li> +<li><a href="/rooms.aspx">related link 2</a></li> +</ul>]]> + </bodyText> + <umbracoNaviHide>0</umbracoNaviHide> + </ContentPanel> + </ContentPanels> + </Homepage> + </DocumentSet> + </Documents> + <DocumentTypes> + <DocumentType> + <Info> + <Name>Base</Name> + <Alias>Base</Alias> + <Icon>folder.gif</Icon> + <Thumbnail>folder.png</Thumbnail> + <Description> + </Description> + <AllowAtRoot>False</AllowAtRoot> + <AllowedTemplates /> + <DefaultTemplate> + </DefaultTemplate> + </Info> + <Structure /> + <GenericProperties> + <GenericProperty> + <Name>Hide From Navigation</Name> + <Alias>umbracoNaviHide</Alias> + <Type>38b352c1-e9f8-4fd8-9324-9a2eab06d97a</Type> + <Definition>92897bc6-a5f3-4ffe-ae27-f2e7e33dda49</Definition> + <Tab> + </Tab> + <Mandatory>False</Mandatory> + <Validation> + </Validation> + <Description><![CDATA[]]></Description> + </GenericProperty> + </GenericProperties> + <Tabs /> + </DocumentType> + <DocumentType> + <Info> + <Name>Client Area Folder</Name> + <Alias>ClientArea</Alias> + <Icon>.sprTreeFolder</Icon> + <Thumbnail>folder.png</Thumbnail> + <Description> + </Description> + <AllowAtRoot>False</AllowAtRoot> + <Master>Base</Master> + <AllowedTemplates> + <Template>ClientAreas</Template> + </AllowedTemplates> + <DefaultTemplate>ClientAreas</DefaultTemplate> + </Info> + <Structure> + <DocumentType>ClientArea</DocumentType> + <DocumentType>Standard</DocumentType> + </Structure> + <GenericProperties /> + <Tabs /> + </DocumentType> + <DocumentType> + <Info> + <Name>Content Master</Name> + <Alias>ContentMaster</Alias> + <Icon>folder.gif</Icon> + <Thumbnail>folder.png</Thumbnail> + <Description> + </Description> + <AllowAtRoot>False</AllowAtRoot> + <Master>Base</Master> + <AllowedTemplates /> + <DefaultTemplate> + </DefaultTemplate> + </Info> + <Structure /> + <GenericProperties> + <GenericProperty> + <Name>Title</Name> + <Alias>title</Alias> + <Type>ec15c1e5-9d90-422a-aa52-4f7622c63bea</Type> + <Definition>0cc0eba1-9960-42c9-bf9b-60e150b429ae</Definition> + <Tab>SEO</Tab> + <Mandatory>False</Mandatory> + <Validation> + </Validation> + <Description><![CDATA[]]></Description> + </GenericProperty> + <GenericProperty> + <Name>Description</Name> + <Alias>description</Alias> + <Type>67db8357-ef57-493e-91ac-936d305e0f2a</Type> + <Definition>c6bac0dd-4ab9-45b1-8e30-e4b619ee5da3</Definition> + <Tab>SEO</Tab> + <Mandatory>False</Mandatory> + <Validation> + </Validation> + <Description><![CDATA[]]></Description> + </GenericProperty> + <GenericProperty> + <Name>Keywords</Name> + <Alias>keywords</Alias> + <Type>67db8357-ef57-493e-91ac-936d305e0f2a</Type> + <Definition>c6bac0dd-4ab9-45b1-8e30-e4b619ee5da3</Definition> + <Tab>SEO</Tab> + <Mandatory>False</Mandatory> + <Validation> + </Validation> + <Description><![CDATA[]]></Description> + </GenericProperty> + </GenericProperties> + <Tabs> + <Tab> + <Id>6</Id> + <Caption>SEO</Caption> + </Tab> + </Tabs> + </DocumentType> + <DocumentType> + <Info> + <Name>Standard</Name> + <Alias>Standard</Alias> + <Icon>.sprTreeDoc</Icon> + <Thumbnail>doc.png</Thumbnail> + <Description> + </Description> + <AllowAtRoot>False</AllowAtRoot> + <Master>ContentMaster</Master> + <AllowedTemplates> + <Template>Articles</Template> + <Template>Login</Template> + <Template>Search</Template> + <Template>Sitemap</Template> + <Template>StandardPage</Template> + </AllowedTemplates> + <DefaultTemplate>StandardPage</DefaultTemplate> + </Info> + <Structure> + <DocumentType>Standard</DocumentType> + <DocumentType>NewsArticle</DocumentType> + </Structure> + <GenericProperties> + <GenericProperty> + <Name>Main Content</Name> + <Alias>bodyText</Alias> + <Type>5e9b75ae-face-41c8-b47e-5f4b0fd82f83</Type> + <Definition>ca90c950-0aff-4e72-b976-a30b1ac57dad</Definition> + <Tab>Content</Tab> + <Mandatory>False</Mandatory> + <Validation> + </Validation> + <Description><![CDATA[]]></Description> + </GenericProperty> + <GenericProperty> + <Name>Content Panels</Name> + <Alias>contentPanels</Alias> + <Type>7e062c13-7c41-4ad9-b389-41d88aeef87c</Type> + <Definition>d719387b-8261-48ac-b94b-00654896d114</Definition> + <Tab>Panels</Tab> + <Mandatory>False</Mandatory> + <Validation> + </Validation> + <Description><![CDATA[Select the panels to appear in the right column]]></Description> + </GenericProperty> + </GenericProperties> + <Tabs> + <Tab> + <Id>7</Id> + <Caption>Content</Caption> + </Tab> + <Tab> + <Id>8</Id> + <Caption>Panels</Caption> + </Tab> + </Tabs> + </DocumentType> + <DocumentType> + <Info> + <Name>ContactForm</Name> + <Alias>ContactForm</Alias> + <Icon>newsletter.gif</Icon> + <Thumbnail>doc.png</Thumbnail> + <Description> + </Description> + <AllowAtRoot>False</AllowAtRoot> + <Master>Standard</Master> + <AllowedTemplates> + <Template>Contact</Template> + </AllowedTemplates> + <DefaultTemplate>Contact</DefaultTemplate> + </Info> + <Structure> + <DocumentType>Standard</DocumentType> + </Structure> + <GenericProperties> + <GenericProperty> + <Name>Recipient Email Address</Name> + <Alias>recipientEmailAddress</Alias> + <Type>ec15c1e5-9d90-422a-aa52-4f7622c63bea</Type> + <Definition>0cc0eba1-9960-42c9-bf9b-60e150b429ae</Definition> + <Tab>Form</Tab> + <Mandatory>False</Mandatory> + <Validation> + </Validation> + <Description><![CDATA[]]></Description> + </GenericProperty> + <GenericProperty> + <Name>Email Subject</Name> + <Alias>emailSubject</Alias> + <Type>ec15c1e5-9d90-422a-aa52-4f7622c63bea</Type> + <Definition>0cc0eba1-9960-42c9-bf9b-60e150b429ae</Definition> + <Tab>Form</Tab> + <Mandatory>False</Mandatory> + <Validation> + </Validation> + <Description><![CDATA[]]></Description> + </GenericProperty> + <GenericProperty> + <Name>Thank You Page</Name> + <Alias>thankYouPage</Alias> + <Type>158aa029-24ed-4948-939e-c3da209e5fba</Type> + <Definition>a6857c73-d6e9-480c-b6e6-f15f6ad11125</Definition> + <Tab>Form</Tab> + <Mandatory>False</Mandatory> + <Validation> + </Validation> + <Description><![CDATA[]]></Description> + </GenericProperty> + <GenericProperty> + <Name>Sender Email Address</Name> + <Alias>senderEmailAddress</Alias> + <Type>ec15c1e5-9d90-422a-aa52-4f7622c63bea</Type> + <Definition>0cc0eba1-9960-42c9-bf9b-60e150b429ae</Definition> + <Tab>Form</Tab> + <Mandatory>False</Mandatory> + <Validation> + </Validation> + <Description><![CDATA[]]></Description> + </GenericProperty> + </GenericProperties> + <Tabs> + <Tab> + <Id>9</Id> + <Caption>Form</Caption> + </Tab> + </Tabs> + </DocumentType> + <DocumentType> + <Info> + <Name>ContentPanel</Name> + <Alias>ContentPanel</Alias> + <Icon>.sprTreeDoc</Icon> + <Thumbnail>doc.png</Thumbnail> + <Description> + </Description> + <AllowAtRoot>False</AllowAtRoot> + <Master>Base</Master> + <AllowedTemplates /> + <DefaultTemplate> + </DefaultTemplate> + </Info> + <Structure /> + <GenericProperties> + <GenericProperty> + <Name>Main Content</Name> + <Alias>bodyText</Alias> + <Type>5e9b75ae-face-41c8-b47e-5f4b0fd82f83</Type> + <Definition>ca90c950-0aff-4e72-b976-a30b1ac57dad</Definition> + <Tab>Content</Tab> + <Mandatory>False</Mandatory> + <Validation> + </Validation> + <Description><![CDATA[]]></Description> + </GenericProperty> + </GenericProperties> + <Tabs> + <Tab> + <Id>10</Id> + <Caption>Content</Caption> + </Tab> + </Tabs> + </DocumentType> + <DocumentType> + <Info> + <Name>ContentPanels</Name> + <Alias>ContentPanels</Alias> + <Icon>.sprTreeFolder</Icon> + <Thumbnail>folder.png</Thumbnail> + <Description> + </Description> + <AllowAtRoot>False</AllowAtRoot> + <Master>Base</Master> + <AllowedTemplates /> + <DefaultTemplate> + </DefaultTemplate> + </Info> + <Structure> + <DocumentType>ContentPanel</DocumentType> + </Structure> + <GenericProperties /> + <Tabs /> + </DocumentType> + <DocumentType> + <Info> + <Name>Homepage</Name> + <Alias>Homepage</Alias> + <Icon>.sprTreeSettingDomain</Icon> + <Thumbnail>folder.png</Thumbnail> + <Description> + </Description> + <AllowAtRoot>False</AllowAtRoot> + <Master>ContentMaster</Master> + <AllowedTemplates> + <Template>Home</Template> + </AllowedTemplates> + <DefaultTemplate>Home</DefaultTemplate> + </Info> + <Structure> + <DocumentType>ClientArea</DocumentType> + <DocumentType>Standard</DocumentType> + <DocumentType>ContactForm</DocumentType> + <DocumentType>ContentPanels</DocumentType> + <DocumentType>Slideshow</DocumentType> + </Structure> + <GenericProperties> + <GenericProperty> + <Name>Primary Navigation</Name> + <Alias>primaryNavigation</Alias> + <Type>7e062c13-7c41-4ad9-b389-41d88aeef87c</Type> + <Definition>d719387b-8261-48ac-b94b-00654896d114</Definition> + <Tab>Navigation</Tab> + <Mandatory>False</Mandatory> + <Validation> + </Validation> + <Description><![CDATA[]]></Description> + </GenericProperty> + <GenericProperty> + <Name>Panel Content 1</Name> + <Alias>panelContent1</Alias> + <Type>5e9b75ae-face-41c8-b47e-5f4b0fd82f83</Type> + <Definition>ca90c950-0aff-4e72-b976-a30b1ac57dad</Definition> + <Tab>Panel 1</Tab> + <Mandatory>False</Mandatory> + <Validation> + </Validation> + <Description><![CDATA[]]></Description> + </GenericProperty> + <GenericProperty> + <Name>Panel Content 2</Name> + <Alias>panelContent2</Alias> + <Type>5e9b75ae-face-41c8-b47e-5f4b0fd82f83</Type> + <Definition>ca90c950-0aff-4e72-b976-a30b1ac57dad</Definition> + <Tab>Panel 2</Tab> + <Mandatory>False</Mandatory> + <Validation> + </Validation> + <Description><![CDATA[]]></Description> + </GenericProperty> + <GenericProperty> + <Name>Panel Content 3</Name> + <Alias>panelContent3</Alias> + <Type>5e9b75ae-face-41c8-b47e-5f4b0fd82f83</Type> + <Definition>ca90c950-0aff-4e72-b976-a30b1ac57dad</Definition> + <Tab>Panel 3</Tab> + <Mandatory>False</Mandatory> + <Validation> + </Validation> + <Description><![CDATA[]]></Description> + </GenericProperty> + <GenericProperty> + <Name>Slideshow</Name> + <Alias>slideshow</Alias> + <Type>7e062c13-7c41-4ad9-b389-41d88aeef87c</Type> + <Definition>d719387b-8261-48ac-b94b-00654896d114</Definition> + <Tab>Slideshow</Tab> + <Mandatory>False</Mandatory> + <Validation> + </Validation> + <Description><![CDATA[]]></Description> + </GenericProperty> + <GenericProperty> + <Name>Header Navigation</Name> + <Alias>headerNavigation</Alias> + <Type>7e062c13-7c41-4ad9-b389-41d88aeef87c</Type> + <Definition>d719387b-8261-48ac-b94b-00654896d114</Definition> + <Tab>Header</Tab> + <Mandatory>False</Mandatory> + <Validation> + </Validation> + <Description><![CDATA[]]></Description> + </GenericProperty> + <GenericProperty> + <Name>Address</Name> + <Alias>address</Alias> + <Type>ec15c1e5-9d90-422a-aa52-4f7622c63bea</Type> + <Definition>0cc0eba1-9960-42c9-bf9b-60e150b429ae</Definition> + <Tab>Footer</Tab> + <Mandatory>False</Mandatory> + <Validation> + </Validation> + <Description><![CDATA[The address appears in the footer of all pages]]></Description> + </GenericProperty> + <GenericProperty> + <Name>Copyright</Name> + <Alias>copyright</Alias> + <Type>ec15c1e5-9d90-422a-aa52-4f7622c63bea</Type> + <Definition>0cc0eba1-9960-42c9-bf9b-60e150b429ae</Definition> + <Tab>Footer</Tab> + <Mandatory>False</Mandatory> + <Validation> + </Validation> + <Description><![CDATA[]]></Description> + </GenericProperty> + <GenericProperty> + <Name>Affiliation Link 1</Name> + <Alias>affiliationLink1</Alias> + <Type>ec15c1e5-9d90-422a-aa52-4f7622c63bea</Type> + <Definition>0cc0eba1-9960-42c9-bf9b-60e150b429ae</Definition> + <Tab>Footer</Tab> + <Mandatory>False</Mandatory> + <Validation> + </Validation> + <Description><![CDATA[]]></Description> + </GenericProperty> + <GenericProperty> + <Name>Affiliation Image 1</Name> + <Alias>affiliationImage1</Alias> + <Type>5032a6e6-69e3-491d-bb28-cd31cd11086c</Type> + <Definition>84c6b441-31df-4ffe-b67e-67d5bc3ae65a</Definition> + <Tab>Footer</Tab> + <Mandatory>False</Mandatory> + <Validation> + </Validation> + <Description><![CDATA[]]></Description> + </GenericProperty> + <GenericProperty> + <Name>Affiliation Link 2</Name> + <Alias>affiliationLink2</Alias> + <Type>ec15c1e5-9d90-422a-aa52-4f7622c63bea</Type> + <Definition>0cc0eba1-9960-42c9-bf9b-60e150b429ae</Definition> + <Tab>Footer</Tab> + <Mandatory>False</Mandatory> + <Validation> + </Validation> + <Description><![CDATA[]]></Description> + </GenericProperty> + <GenericProperty> + <Name>Affiliation Image 2</Name> + <Alias>affiliationImage2</Alias> + <Type>5032a6e6-69e3-491d-bb28-cd31cd11086c</Type> + <Definition>84c6b441-31df-4ffe-b67e-67d5bc3ae65a</Definition> + <Tab>Footer</Tab> + <Mandatory>False</Mandatory> + <Validation> + </Validation> + <Description><![CDATA[]]></Description> + </GenericProperty> + <GenericProperty> + <Name>Affiliation Link 3</Name> + <Alias>affiliationLink3</Alias> + <Type>ec15c1e5-9d90-422a-aa52-4f7622c63bea</Type> + <Definition>0cc0eba1-9960-42c9-bf9b-60e150b429ae</Definition> + <Tab>Footer</Tab> + <Mandatory>False</Mandatory> + <Validation> + </Validation> + <Description><![CDATA[]]></Description> + </GenericProperty> + <GenericProperty> + <Name>Affiliation Image 3</Name> + <Alias>affiliationImage3</Alias> + <Type>5032a6e6-69e3-491d-bb28-cd31cd11086c</Type> + <Definition>84c6b441-31df-4ffe-b67e-67d5bc3ae65a</Definition> + <Tab>Footer</Tab> + <Mandatory>False</Mandatory> + <Validation> + </Validation> + <Description><![CDATA[]]></Description> + </GenericProperty> + </GenericProperties> + <Tabs> + <Tab> + <Id>11</Id> + <Caption>Slideshow</Caption> + </Tab> + <Tab> + <Id>12</Id> + <Caption>Panel 1</Caption> + </Tab> + <Tab> + <Id>13</Id> + <Caption>Panel 2</Caption> + </Tab> + <Tab> + <Id>14</Id> + <Caption>Panel 3</Caption> + </Tab> + <Tab> + <Id>15</Id> + <Caption>Navigation</Caption> + </Tab> + <Tab> + <Id>16</Id> + <Caption>Footer</Caption> + </Tab> + <Tab> + <Id>17</Id> + <Caption>Header</Caption> + </Tab> + </Tabs> + </DocumentType> + <DocumentType> + <Info> + <Name>NewsArticle</Name> + <Alias>NewsArticle</Alias> + <Icon>doc.gif</Icon> + <Thumbnail>folder.png</Thumbnail> + <Description> + </Description> + <AllowAtRoot>False</AllowAtRoot> + <Master>Standard</Master> + <AllowedTemplates> + <Template>StandardPage</Template> + </AllowedTemplates> + <DefaultTemplate>StandardPage</DefaultTemplate> + </Info> + <Structure /> + <GenericProperties> + <GenericProperty> + <Name>Article Summary</Name> + <Alias>articleSummary</Alias> + <Type>67db8357-ef57-493e-91ac-936d305e0f2a</Type> + <Definition>c6bac0dd-4ab9-45b1-8e30-e4b619ee5da3</Definition> + <Tab>Article</Tab> + <Mandatory>False</Mandatory> + <Validation> + </Validation> + <Description><![CDATA[]]></Description> + </GenericProperty> + <GenericProperty> + <Name>Article Date</Name> + <Alias>articleDate</Alias> + <Type>23e93522-3200-44e2-9f29-e61a6fcbb79a</Type> + <Definition>5046194e-4237-453c-a547-15db3a07c4e1</Definition> + <Tab>Article</Tab> + <Mandatory>False</Mandatory> + <Validation> + </Validation> + <Description><![CDATA[]]></Description> + </GenericProperty> + </GenericProperties> + <Tabs> + <Tab> + <Id>18</Id> + <Caption>Article</Caption> + </Tab> + </Tabs> + </DocumentType> + <DocumentType> + <Info> + <Name>Slide</Name> + <Alias>Slide</Alias> + <Icon>.sprTreeMediaPhoto</Icon> + <Thumbnail>docWithImage.png</Thumbnail> + <Description> + </Description> + <AllowAtRoot>False</AllowAtRoot> + <Master>Base</Master> + <AllowedTemplates /> + <DefaultTemplate> + </DefaultTemplate> + </Info> + <Structure /> + <GenericProperties> + <GenericProperty> + <Name>Main Image</Name> + <Alias>mainImage</Alias> + <Type>5032a6e6-69e3-491d-bb28-cd31cd11086c</Type> + <Definition>84c6b441-31df-4ffe-b67e-67d5bc3ae65a</Definition> + <Tab>Content</Tab> + <Mandatory>False</Mandatory> + <Validation> + </Validation> + <Description><![CDATA[500px x 260px]]></Description> + </GenericProperty> + <GenericProperty> + <Name>Main Content</Name> + <Alias>bodyText</Alias> + <Type>5e9b75ae-face-41c8-b47e-5f4b0fd82f83</Type> + <Definition>ca90c950-0aff-4e72-b976-a30b1ac57dad</Definition> + <Tab>Content</Tab> + <Mandatory>False</Mandatory> + <Validation> + </Validation> + <Description><![CDATA[]]></Description> + </GenericProperty> + </GenericProperties> + <Tabs> + <Tab> + <Id>19</Id> + <Caption>Content</Caption> + </Tab> + </Tabs> + </DocumentType> + <DocumentType> + <Info> + <Name>Slideshow</Name> + <Alias>Slideshow</Alias> + <Icon>.sprTreeFolder</Icon> + <Thumbnail>folder.png</Thumbnail> + <Description> + </Description> + <AllowAtRoot>False</AllowAtRoot> + <Master>Base</Master> + <AllowedTemplates /> + <DefaultTemplate> + </DefaultTemplate> + </Info> + <Structure> + <DocumentType>Slide</DocumentType> + </Structure> + <GenericProperties /> + <Tabs /> + </DocumentType> + </DocumentTypes> + <Templates> + <Template> + <Name>Articles</Name> + <Alias>Articles</Alias> + <Master>SW_Master</Master> + <Design> + <![CDATA[@inherits Umbraco.Web.Mvc.UmbracoTemplatePage +@{ + Layout = "SW_Master.cshtml"; + int pageSize = 2; // How many items per page + int page; // The page we are viewing + + /* Set up parameters */ + + if (!int.TryParse(Request.QueryString["page"], out page)) + { + page = 1; + } + + /* This is your basic query to select the nodes you want */ + + var nodes = Model.Content.Children.Where(x => x.DocumentTypeAlias == "NewsArticle").OrderBy(x=>x.CreateDate); + + int totalNodes = nodes.Count(); + int totalPages = (int)Math.Ceiling((double)totalNodes / (double)pageSize); + + /* Bounds checking */ + + if (page > totalPages) + { + page = totalPages; + } + else if (page < 1) + { + page = 1; + } + + + + + + + + + + + + + + +} + + + + <div id="mainContent" class="fc"> + <div class="navigation"> + @Html.Partial("LeftNavigation",@Model.Content) +   + </div> + + <div id="content"> + + @Html.Raw(Model.Content.GetPropertyValue<string>("bodyText")) + + + <ul id="newsList"> + @foreach (var item in nodes.Skip((page - 1) * pageSize).Take(pageSize)) + { + <li> + <h3> + <a href="@item.NiceUrl()"> + @item.Name + </a> + </h3> + <p class="articleDate"> + @Convert.ToDateTime(item.GetPropertyValue("articleDate")).ToString("dd MMMM yyyy") + </p> + <p> + @item.GetPropertyValue("articleSummary") + + </p> + </li> + } +</ul> + +@if(totalPages > 1) +{ + + <p id="pager"> + @for (int p = 1; p < totalPages + 1; p++) + { + //string selected = (p == page) ? "selected" : String.Empty; + //<li class="@selected"><a href="?page=@p" title="Go to page @p of results">@p</a></li> + <a href="?page=@p" title="Go to page @p of results">@p</a> + if (p < totalPages) + { + <text>| </text> + } + } +</p> +} + + + </div> + + @Html.Partial("ContentPanels",@Model.Content) + </div>]]> + </Design> + </Template> + <Template> + <Name>ClientAreas</Name> + <Alias>ClientAreas</Alias> + <Master>SW_Master</Master> + <Design> + <![CDATA[@inherits Umbraco.Web.Mvc.UmbracoTemplatePage +@{ + Layout = "SW_Master.cshtml"; + var pages = Model.Content.Children.Where(x => x.IsVisible() && x.TemplateId > 0 && Umbraco.MemberHasAccess(x.Id, x.Path)); +} + <div id="mainContent" class="fc"> + + <div class="navigation"> + @Html.Partial("LeftNavigation",@Model.Content) +   + </div> + + <div id="content"> + @Html.Raw(Model.Content.GetPropertyValue<string>("bodyText")) + + @foreach (var page in pages) + { + <h3><a href="@page.NiceUrl()">@page.Name</a></h3> + } + + </div> + + + </div>]]> + </Design> + </Template> + <Template> + <Name>Contact</Name> + <Alias>Contact</Alias> + <Master>SW_Master</Master> + <Design> + <![CDATA[@inherits Umbraco.Web.Mvc.UmbracoTemplatePage +@{ + Layout = "SW_Master.cshtml"; +} + <div id="mainContent" class="fc"> + + <div class="navigation"> + @Html.Partial("LeftNavigation",@Model.Content) +   + </div> + + <div id="content"> + @Html.Raw(Model.Content.GetPropertyValue<string>("bodyText")) + + @Html.Partial("ContactForm",new Koiak.StandardWebsite.ContactFormModel()) + </div> +</div>]]> + </Design> + </Template> + <Template> + <Name>Home</Name> + <Alias>Home</Alias> + <Master>SW_Master</Master> + <Design> + <![CDATA[@inherits Umbraco.Web.Mvc.UmbracoTemplatePage +@{ + Layout = "SW_Master.cshtml"; +} + + <div id="slideshow"> + <ul> + @{ + var nodeIds = Model.Content.GetPropertyValue("slideshow").ToString().Split(','); + List<IPublishedContent> slides = new List<IPublishedContent>(); + + foreach (var nodeId in nodeIds) + { + if (!String.IsNullOrEmpty(nodeId)) + { + var publishedContent = Umbraco.NiceUrl(Convert.ToInt32(nodeId)); + if (!String.IsNullOrEmpty(publishedContent) && publishedContent != "#") + { + slides.Add(Umbraco.TypedContent(nodeId)); + } + } + } + } + + @foreach (var slide in slides) + { + if(slide != null) + { + string styleString = !slide.IsFirst() ? "display:none;" : ""; + <li class="rotating-panel fc" style="@styleString"> + <img class="fl" alt="@slide.Name" src="@slide.GetPropertyValue("mainImage")"/> + <div class=""> + @Html.Raw(slide.GetPropertyValue("bodyText")) + </div> + </li> + } + } + </ul> + <ul id="slidePager"> + @foreach (var slide in slides) + { + string classString = slide.IsFirst() ? "selected" : ""; + <li> + <a href="?position={position()}" class="@classString"> + @slide.Position() + </a> + </li> + } + </ul> + + </div> + + <div class="fc"> + <div class="feature fl"> + @Html.Raw(Model.Content.GetPropertyValue("panelContent1").ToString()) + </div> + + <div class="feature fl"> + @Html.Raw(Model.Content.GetPropertyValue("panelContent2").ToString()) + </div> + + <div class="feature fr"> + @Html.Raw(Model.Content.GetPropertyValue("panelContent3").ToString()) + </div> + </div>]]> + </Design> + </Template> + <Template> + <Name>Login</Name> + <Alias>Login</Alias> + <Master>SW_Master</Master> + <Design> + <![CDATA[ @inherits Umbraco.Web.Mvc.UmbracoTemplatePage +@{ + Layout = "SW_Master.cshtml"; + + if(!String.IsNullOrEmpty(Request.QueryString["signout"])) + { + FormsAuthentication.SignOut(); + Context.Response.Redirect(Model.Content.NiceUrl(), true); + } +} + <div id="mainContent" class="fc"> + + <div class="navigation"> + @Html.Partial("LeftNavigation",@Model.Content) +   + </div> + + <div id="content"> + @Html.Raw(Model.Content.GetPropertyValue<string>("bodyText")) + + @Html.Partial("LoginForm",new Koiak.StandardWebsite.LoginModel()) + </div> +</div>]]> + </Design> + </Template> + <Template> + <Name>Search</Name> + <Alias>Search</Alias> + <Master>SW_Master</Master> + <Design> + <![CDATA[@inherits Umbraco.Web.Mvc.UmbracoTemplatePage +@using Lucene.Net; +@using Examine; +@using Examine.LuceneEngine.SearchCriteria; + +@{ + Layout = "SW_Master.cshtml"; + + + int pageSize = 10; // How many items per page + int page; // The page we are viewing + string searchTerm = Context.Request.QueryString["search"]; + + /* Set up parameters */ + + if (!int.TryParse(Request.QueryString["page"], out page)) + { + page = 1; + } + + /* This is your basic query to select the nodes you want */ + + Examine.Providers.BaseSearchProvider baseSearchProvider = ExamineManager.Instance.DefaultSearchProvider; + IEnumerable<SearchResult> nodes = null; + //ISearchResults nodes = null; + Lucene.Net.Search.Searcher luceneSearcher = null; + int totalNodes = 0; + int totalPages = 0; + + if (!String.IsNullOrEmpty(searchTerm)) + { + //nodes = baseSearchProvider.Search(searchTerm, true); + var searchCriteria = Examine.ExamineManager.Instance.CreateSearchCriteria(Examine.SearchCriteria.BooleanOperation.And); + + var query = searchCriteria.GroupedOr( + new string[] { "nodeName", "bodyText", "panelContent1", "panelContent2", "panelContent3", "articleSummary"},searchTerm.Fuzzy(0.7f)) + .Compile(); + + var results = baseSearchProvider.Search(query); //.OrderByDescending(x => x.Score) + luceneSearcher = ((Examine.LuceneEngine.SearchResults)results).LuceneSearcher; + nodes = results.OrderByDescending(x => x.Score); + + totalNodes = nodes.Count(); + totalPages = (int)Math.Ceiling((double)totalNodes / (double)pageSize); + + /* Bounds checking */ + + if (page > totalPages) + { + page = totalPages; + } + else if (page < 1) + { + page = 1; + } + } + +} +<div id="mainContent" class="fc"> + <div class="navigation"> + @Html.Partial("LeftNavigation", @Model.Content) +   + + </div> + + <div id="content"> + @Html.Raw(Model.Content.GetPropertyValue<string>("bodyText")) + + @if (totalNodes == 0) + { + <p>No results match your search</p> + } + else + { + <ul id="newsList"> + @foreach (var item in nodes.Skip((page - 1) * pageSize).Take(pageSize)) + { + <li> + <h3> + <a href="@Umbraco.NiceUrl(Convert.ToInt32(@item.Fields["id"]))"> + @item.Fields["nodeName"] + </a> + </h3> + @{ + string fieldName = "bodyText"; + string searchHiglight = ""; + + if (item.Fields.ContainsKey(fieldName)) + { + string fieldValue = item.Fields[fieldName]; + searchHiglight = LuceneHighlightHelper.Instance.GetHighlight(fieldValue, fieldName, luceneSearcher, searchTerm); + + if (String.IsNullOrEmpty(searchHiglight)) + { + searchHiglight = Umbraco.Truncate(fieldValue, 200).ToString(); + } + else + { + searchHiglight = System.Text.RegularExpressions.Regex.Replace(searchHiglight, searchTerm, "<strong>" + searchTerm + "</strong>", System.Text.RegularExpressions.RegexOptions.IgnoreCase); + } + } + } + + <p>@Html.Raw(searchHiglight)</p> + + <!--<dl> + + @foreach (var field in item.Fields) + { + <dt>@field.Key</dt> + <dd>@field.Value</dd> + } + </dl>--> + </li> + } + </ul> + } + + @if (totalPages > 1) + { + + <p id="pager"> + @for (int p = 1; p < totalPages + 1; p++) + { + //string selected = (p == page) ? "selected" : String.Empty; + //<li class="@selected"><a href="?page=@p" title="Go to page @p of results">@p</a></li> + <a href="?search=@searchTerm&page=@p" title="Go to page @p of results">@p</a> + if (p < totalPages) + { + <text>| </text> + } + } + </p> + } + </div> + + @Html.Partial("ContentPanels", @Model.Content) +</div>]]> + </Design> + </Template> + <Template> + <Name>Sitemap</Name> + <Alias>Sitemap</Alias> + <Master>SW_Master</Master> + <Design> + <![CDATA[@inherits Umbraco.Web.Mvc.UmbracoTemplatePage +@{ + Layout = "SW_Master.cshtml"; +} + <div id="mainContent" class="fc"> + + <div class="navigation"> + @Html.Partial("LeftNavigation",@Model.Content) +   + </div> + + <div id="content"> + @Html.Raw(Model.Content.GetPropertyValue<string>("bodyText")) + + <div id="sitemap"> + @traverse(Model.Content.AncestorOrSelf(1)) + </div> + + </div> + + @Html.Partial("ContentPanels",@Model.Content) + </div> + +@helper traverse(IPublishedContent node) +{ + var cc = node.Children.Where(x=>x.IsVisible() && x.TemplateId > 0); + if (cc.Count()>0) + { + <ul> + @foreach (var c in cc) + { + <li> + <a href="@c.NiceUrl()">@c.Name</a> + @traverse(c) + </li> + } + </ul> + } +}]]> + </Design> + </Template> + <Template> + <Name>Standard Page</Name> + <Alias>StandardPage</Alias> + <Master>SW_Master</Master> + <Design> + <![CDATA[@inherits Umbraco.Web.Mvc.UmbracoTemplatePage +@{ + Layout = "SW_Master.cshtml"; +} + <div id="mainContent" class="fc"> + + <div class="navigation"> + @Html.Partial("LeftNavigation",@Model.Content) +   + </div> + + <div id="content"> + @Html.Raw(Model.Content.GetPropertyValue<string>("bodyText")) + </div> + + @Html.Partial("ContentPanels",@Model.Content) + </div>]]> + </Design> + </Template> + <Template> + <Name>SW_Master</Name> + <Alias>SW_Master</Alias> + <Design> + <![CDATA[@inherits Umbraco.Web.Mvc.UmbracoTemplatePage +@{ + Layout = null; + var homepage = Model.Content.AncestorOrSelf(1); +} +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> + <head> + <title>@Model.Content.GetPropertyValue("title") + + + + + + + + + + + + + + + + + + + +
+ @RenderBody() +
+ + + + + + + + +]]> + + + + + + admin + + + + + + + + Header 2 + h2 + + + + + Header 3 + h3 + + + + + Float Right + .fr + + + + + + + base-min + base-min + + + + + + default + default + + + + + + + + Map + Map + + + + + + + True + 0 + Map.cshtml + + + + + + + + + + + + + + + + + + + + + + + + + /usercontrols/StandardWebsiteInstall.ascx +
\ No newline at end of file diff --git a/src/Umbraco.Tests/Services/Importing/uBlogsy-Package.xml b/src/Umbraco.Tests/Services/Importing/uBlogsy-Package.xml new file mode 100644 index 0000000000..98e12465f5 --- /dev/null +++ b/src/Umbraco.Tests/Services/Importing/uBlogsy-Package.xml @@ -0,0 +1,2163 @@ + + + + + uBlogsy.BusinessLogic.dll + /bin + uBlogsy.BusinessLogic.dll + + + uBlogsy.BusinessLogic.pdb + /bin + uBlogsy.BusinessLogic.pdb + + + uBlogsy.Common.dll + /bin + uBlogsy.Common.dll + + + uBlogsy.Common.pdb + /bin + uBlogsy.Common.pdb + + + uBlogsy.Mvc.Parts.dll + /bin + uBlogsy.Mvc.Parts.dll + + + uBlogsy.Mvc.Parts.pdb + /bin + uBlogsy.Mvc.Parts.pdb + + + uBlogsy.Web.dll + /bin + uBlogsy.Web.dll + + + uBlogsy.Web.pdb + /bin + uBlogsy.Web.pdb + + + uDateFoldersy.dll + /bin + uDateFoldersy.dll + + + uDateFoldersy.pdb + /bin + uDateFoldersy.pdb + + + uLoremsy.dll + /bin + uLoremsy.dll + + + uLoremsy.pdb + /bin + uLoremsy.pdb + + + uHelpsy.dll + /bin + uHelpsy.dll + + + uHelpsy.pdb + /bin + uHelpsy.pdb + + + uTagsy.Web.dll + /bin + uTagsy.Web.dll + + + uTagsy.Web.pdb + /bin + uTagsy.Web.pdb + + + CreatePost.ascx + /usercontrols/uBlogsy/dashboard + CreatePost.ascx + + + RSSImport.ascx + /usercontrols/uBlogsy/dashboard + RSSImport.ascx + + + uTagsy.ascx + /usercontrols/uTagsy + uTagsy.ascx + + + uDateFoldersy.config + /config + uDateFoldersy.config + + + uTagsy.config + /config + uTagsy.config + + + uLoremsy.config + /config + uLoremsy.config + + + uBlogsy.css + /css + uBlogsy.css + + + uBlogsy_feed-icon-14x14.png + /Images + uBlogsy_feed-icon-14x14.png + + + calendar_view_day.png + /umbraco/images/umbraco + calendar_view_day.png + + + date.png + /umbraco/images/umbraco + date.png + + + feed.png + /umbraco/images/umbraco + feed.png + + + folder_table.png + /umbraco/images/umbraco + folder_table.png + + + folder_user.png + /umbraco/images/umbraco + folder_user.png + + + house.png + /umbraco/images/umbraco + house.png + + + page_green.png + /umbraco/images/umbraco + page_green.png + + + page_white_cup.png + /umbraco/images/umbraco + page_white_cup.png + + + rss.png + /umbraco/images/umbraco + rss.png + + + tag.png + /umbraco/images/umbraco + tag.png + + + tag_blue.png + /Umbraco/Images/Umbraco + tag_blue.png + + + tag_blue_add.png + /Umbraco/Images/Umbraco + tag_blue_add.png + + + user.png + /umbraco/images/umbraco + user.png + + + _uBlogsyBase.cshtml + /Views + _uBlogsyBase.cshtml + + + _uBlogsyBaseSite.cshtml + /Views + _uBlogsyBaseSite.cshtml + + + _uBlogsyBaseBlog.cshtml + /Views + _uBlogsyBaseBlog.cshtml + + + uBlogsyMacroShowSomeLove.cshtml + /Views/MacroPartials/uBlogsy + uBlogsyMacroShowSomeLove.cshtml + + + uBlogsyGlobalBrowserTitle.cshtml + /Views/Partials/uBlogsy/Global + uBlogsyGlobalBrowserTitle.cshtml + + + uBlogsyGlobalFooter.cshtml + /Views/Partials/uBlogsy/Global + uBlogsyGlobalFooter.cshtml + + + uBlogsyGlobalHeader.cshtml + /Views/Partials/uBlogsy/Global + uBlogsyGlobalHeader.cshtml + + + uBlogsyGlobalNavigation.cshtml + /Views/Partials/uBlogsy/Global + uBlogsyGlobalNavigation.cshtml + + + uBlogsyGlobalSeoMeta.cshtml + /Views/Partials/uBlogsy/Global + uBlogsyGlobalSeoMeta.cshtml + + + uBlogsyLandingListPosts.cshtml + /Views/Partials/uBlogsy/Landing + uBlogsyLandingListPosts.cshtml + + + uBlogsyLandingShowPost.cshtml + /Views/Partials/uBlogsy/Landing + uBlogsyLandingShowPost.cshtml + + + uBlogsyPostListAuthors.cshtml + /Views/Partials/uBlogsy/Post + uBlogsyPostListAuthors.cshtml + + + uBlogsyPostListLabels.cshtml + /Views/Partials/uBlogsy/Post + uBlogsyPostListLabels.cshtml + + + uBlogsyPostListRelatedPosts.cshtml + /Views/Partials/uBlogsy/Post + uBlogsyPostListRelatedPosts.cshtml + + + uBlogsyPostListTags.cshtml + /Views/Partials/uBlogsy/Post + uBlogsyPostListTags.cshtml + + + uBlogsyPostShowPost.cshtml + /Views/Partials/uBlogsy/Post + uBlogsyPostShowPost.cshtml + + + uBlogsyShowImage.cshtml + /Views/Partials/uBlogsy/Shared + uBlogsyShowImage.cshtml + + + uBlogsyWidgetListAuthors.cshtml + /Views/Partials/uBlogsy/Widgets + uBlogsyWidgetListAuthors.cshtml + + + uBlogsyWidgetListBlogRoll.cshtml + /Views/Partials/uBlogsy/Widgets + uBlogsyWidgetListBlogRoll.cshtml + + + uBlogsyWidgetListLabels.cshtml + /Views/Partials/uBlogsy/Widgets + uBlogsyWidgetListLabels.cshtml + + + uBlogsyWidgetListPostArchive.cshtml + /Views/Partials/uBlogsy/Widgets + uBlogsyWidgetListPostArchive.cshtml + + + uBlogsyWidgetListPosts.cshtml + /Views/Partials/uBlogsy/Widgets + uBlogsyWidgetListPosts.cshtml + + + uBlogsyWidgetListPostsForHome.cshtml + /Views/Partials/uBlogsy/Widgets + uBlogsyWidgetListPostsForHome.cshtml + + + uBlogsyWidgetListTags.cshtml + /Views/Partials/uBlogsy/Widgets + uBlogsyWidgetListTags.cshtml + + + uBlogsyWidgetSearch.cshtml + /Views/Partials/uBlogsy/Widgets + uBlogsyWidgetSearch.cshtml + + + uBlogsyWidgetShowRSSLink.cshtml + /Views/Partials/uBlogsy/Widgets + uBlogsyWidgetShowRSSLink.cshtml + + + uDateFoldersyFolderRedirect.cshtml + /Views/Partials/uDateFoldersy + uDateFoldersyFolderRedirect.cshtml + + + Installer.ascx + /usercontrols/uBlogsy/dashboard + Installer.ascx + + + + + uBlogsy + 3.0 + MIT license + http://our.umbraco.org/projects/starter-kits/ublogsy + + 3 + 0 + 0 + + + + Anthony Dang + http://anthonydotnet.blogspot.com + + + + + + + + + My Site + + + This is an example home page. 

+

From uBlogsy 3.0, the package is now a site (with basic pages) which has a blog (not a blog which has pages).

+

Below on this page you will see a widget (/Views/uBlogsy/Widgets/uBlogsyWidgetListPostsForHome.cshtml) which lists latest news. The purpose of the widget is to list news for the home page. Your home page will typically be the parent of the uBlogsyLanding node, or a sibling.

+

Take a look at /Views/uBlogsySiteHome.cshtml

+

 

+

 

]]> +
+ + + 0 + + + + + + + + + + 1 + 1 + 1 + + + + Blog + + + Show some love +

Did you know that uBlogsy (a completely free open-source package) has taken many 100's of hours to create and mainatain?

+

If you want to show some love, and support why not click the button below.

+]]> +
+ Keywords + + 0 + + + + + Blog + + 0 + + + + + + Author 1 + 0 + + + + + + + + + + Tag 1 + + + + 0 + + + + + + Category 1 + 0 + + + + + + + + 0 + + + + + My Blog + + Copyright @AnthonyDotNet + +
+ + About + + + Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut nibh massa, ornare ac tempor in, elementum ut sem. Fusce nisl urna, auctor eu varius vel, mattis eu sapien. Sed venenatis facilisis ligula, vitae adipiscing nulla scelerisque eget. Nulla facilisi. Aliquam rutrum sollicitudin erat, non consectetur nunc rutrum sit amet. Proin sit amet elit eget metus fermentum laoreet eu non ipsum. Vivamus non est nibh, non congue turpis. Pellentesque tempus vehicula diam ut tincidunt. Fusce sem diam, vestibulum quis faucibus sit amet, tincidunt id mi. Donec scelerisque blandit suscipit. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos.

+

Duis eget elementum libero. Donec in erat erat, vel convallis diam. Nulla facilisi. Vivamus adipiscing pellentesque facilisis. Nullam convallis nunc ac metus facilisis dapibus. Suspendisse potenti. Phasellus dictum arcu ac velit hendrerit non facilisis erat dignissim. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Sed vitae ante non magna mollis varius at at nisi. Suspendisse sagittis dignissim mi vel adipiscing. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed porttitor viverra congue. Ut sollicitudin enim quis orci scelerisque quis fringilla lorem fringilla. Integer urna leo, aliquam vel sollicitudin eget, facilisis id orci. Ut mollis libero nunc. Integer tortor nisi, aliquet non fermentum ac, bibendum in eros. Mauris aliquet arcu quis enim tincidunt venenatis. Vestibulum tincidunt ullamcorper nulla id blandit. Nam vitae quam id nisi aliquet malesuada malesuada sed eros. Aenean faucibus tempus enim sed pretium.

+

Cras malesuada magna ut elit condimentum mattis. Vestibulum eu risus ante, quis preti

]]> +
+ + + 0 + + + + + + About +
+ + Contact + + + Get your free embedable form from one of these:

+

 

+

http://www.formsite.com/landing/embed.html

+

 

+

http://www.jotformeu.com/

+

 

+

http://www.wufoo.com/

]]> +
+ + + 0 + + + + + + Contact +
+
+
+
+ + + + [uBlogsy] [Base] + uBlogsyBaseDocType + folder.gif + folder.png + This document type exists to allow sorting and categorisation of sub-document types. Do not create content nodes using this document type! + False + + + + + + + + Hide from navigation + umbracoNaviHide + 38b352c1-e9f8-4fd8-9324-9a2eab06d97a + 92897bc6-a5f3-4ffe-ae27-f2e7e33dda49 + + + False + + + + + + 302 Redirect + umbracoRedirect + 158aa029-24ed-4948-939e-c3da209e5fba + a6857c73-d6e9-480c-b6e6-f15f6ad11125 + + + False + + + + + + Invisible Redirect + umbracoInternalRedirectId + 158aa029-24ed-4948-939e-c3da209e5fba + a6857c73-d6e9-480c-b6e6-f15f6ad11125 + + + False + + + + + + Url Name Change + umbracoUrlName + ec15c1e5-9d90-422a-aa52-4f7622c63bea + 0cc0eba1-9960-42c9-bf9b-60e150b429ae + + + False + + + + + + Url Alias + umbracoUrlAlias + ec15c1e5-9d90-422a-aa52-4f7622c63bea + 0cc0eba1-9960-42c9-bf9b-60e150b429ae + + + False + + + + + + + + + + [uBlogsy] [Base] Container + uBlogsyBaseContainer + folder.gif + folder.png + + + False + uBlogsyBaseDocType + + + + + + + + + + + [uBlogsy] [Base] Page + uBlogsyBasePage + folder.gif + folder.png + This document type exists to allow sorting and categorisation of sub-document types. Do not create content nodes using this document type! + False + uBlogsyBaseDocType + + + + + + + + Title + uBlogsyContentTitle + ec15c1e5-9d90-422a-aa52-4f7622c63bea + 0cc0eba1-9960-42c9-bf9b-60e150b429ae + Content + False + + + + + + Summary + uBlogsyContentSummary + 67db8357-ef57-493e-91ac-936d305e0f2a + c6bac0dd-4ab9-45b1-8e30-e4b619ee5da3 + Content + False + + + + + + Body + uBlogsyContentBody + 5e9b75ae-face-41c8-b47e-5f4b0fd82f83 + ca90c950-0aff-4e72-b976-a30b1ac57dad + Content + False + + + + + + Seo Title + uBlogsySeoTitle + ec15c1e5-9d90-422a-aa52-4f7622c63bea + 0cc0eba1-9960-42c9-bf9b-60e150b429ae + SEO + False + + + + + + Navigation Title + uBlogsyNavigationTitle + ec15c1e5-9d90-422a-aa52-4f7622c63bea + 0cc0eba1-9960-42c9-bf9b-60e150b429ae + Navigation + False + + + + + + Keywords + uBlogsySeoKeywords + ec15c1e5-9d90-422a-aa52-4f7622c63bea + 0cc0eba1-9960-42c9-bf9b-60e150b429ae + SEO + False + + + + + + Description + uBlogsySeoDescription + 67db8357-ef57-493e-91ac-936d305e0f2a + c6bac0dd-4ab9-45b1-8e30-e4b619ee5da3 + SEO + False + + + + + + + + 6 + Content + + + 7 + SEO + + + 30 + Navigation + + + + + + [uBlogsy] Author + uBlogsyAuthor + user.png + folder.png + + + False + uBlogsyBaseDocType + + + + + + + + Author Name + uBlogsyAuthorName + ec15c1e5-9d90-422a-aa52-4f7622c63bea + 0cc0eba1-9960-42c9-bf9b-60e150b429ae + Author + False + + + + + + Gravatar Email + uBlogsyAuthorGravatarEmail + ec15c1e5-9d90-422a-aa52-4f7622c63bea + 0cc0eba1-9960-42c9-bf9b-60e150b429ae + Author + False + + + + + + + + 20 + Author + + + + + + [uBlogsy] Container - Author + uBlogsyContainerAuthor + folder_user.png + folder.png + + + False + uBlogsyBaseContainer + + + + + + uBlogsyAuthor + + + + + + + [uBlogsy] Container - Email Template + uBlogsyContainerEmailTemplate + folder_page_white.png + folder.png + + + False + uBlogsyBaseContainer + + + + + + + + + + + [uBlogsy] Container - Label + uBlogsyContainerLabel + folder_table.png + folder.png + + + False + uBlogsyBaseContainer + + + + + + uBlogsyLabel + + + + + + + [uBlogsy] Label + uBlogsyLabel + tag.png + folder.png + + + False + uBlogsyBaseDocType + + + + + + + + Label Name + uBlogsyLabelName + ec15c1e5-9d90-422a-aa52-4f7622c63bea + 0cc0eba1-9960-42c9-bf9b-60e150b429ae + Category + False + + + + + + + + 22 + Category + + + + + + [uBlogsy] Landing + uBlogsyLanding + feed.png + folder.png + This is the root of your blog. It is required. There can be multiple of these. But they cannot be nested under eachother. + False + uBlogsyBasePage + + + + uBlogsyLanding + + + uBlogsyPost + uBlogsyRSS + uTagsyTagContainer + uBlogsyContainerAuthor + uBlogsyContainerLabel + uBlogsyContainerEmailTemplate + uDateFoldersyFolderYear + + + + Blog Roll Links + uBlogsyBlogLinks + 67db8357-ef57-493e-91ac-936d305e0f2a + c6bac0dd-4ab9-45b1-8e30-e4b619ee5da3 + Blog Roll + False + + + + + + + + Default Author + uBlogsyGeneralDefaultAuthor + 7e062c13-7c41-4ad9-b389-41d88aeef87c + ec090322-7f08-4c1a-92cd-682bff7dbdcf + General Settings + False + + + + + + Use Summary On Landing + uBlogsyGeneralUseSummary + 38b352c1-e9f8-4fd8-9324-9a2eab06d97a + 92897bc6-a5f3-4ffe-ae27-f2e7e33dda49 + General Settings + False + + + + + + + + Show Social Media Links + uBlogsyGeneralShowSocialMedia + 38b352c1-e9f8-4fd8-9324-9a2eab06d97a + 92897bc6-a5f3-4ffe-ae27-f2e7e33dda49 + General Settings + False + + + + + + Use Title As Node Name + uBlogsyGeneralUseTitleAsNodeName + 38b352c1-e9f8-4fd8-9324-9a2eab06d97a + 92897bc6-a5f3-4ffe-ae27-f2e7e33dda49 + General Settings + False + + + + + + + + + + 14 + General Settings + + + 15 + Blog Roll + + + + + + [uBlogsy] Page + uBlogsyPage + page_white_cup.png + folder.png + This document type is for simple pages. + False + uBlogsyBasePage + + + + uBlogsyPage + + + + + + + + [uBlogsy] Post + uBlogsyPost + page_green.png + folder.png + This document type is for your blog posts. Put these posts directly under the year folder or under a month folder. + False + uBlogsyBasePage + + + + uBlogsyPost + + + + + Main Image + uBlogsyPostImage + ead69342-f06d-4253-83ac-28000225583b + 93929b9a-93a2-4e2a-b239-d99334440a59 + Post Info + False + + + + + + Author + uBlogsyPostAuthor + 7e062c13-7c41-4ad9-b389-41d88aeef87c + ec090322-7f08-4c1a-92cd-682bff7dbdcf + Post Info + False + + + + + + Post Date + uBlogsyPostDate + b6fb1622-afa5-4bbf-a3cc-d9672a442222 + e4d66c0f-b935-4200-81f0-025f7256b89a + Post Info + True + + + + + + Tags + uBlogsyPostTags + d15e1281-e456-4b24-aa86-1dda3e4299d5 + 1dcab42b-3ade-46d0-b13a-83e2f2944d20 + Post Info + False + + + + + + Categories + uBlogsyPostLabels + 7e062c13-7c41-4ad9-b389-41d88aeef87c + e9bc6389-9a8a-4f7b-b752-96e8b0e9fd51 + Post Info + False + + + + + + Disable Comments + uBlogsyPostDisableComments + 38b352c1-e9f8-4fd8-9324-9a2eab06d97a + 92897bc6-a5f3-4ffe-ae27-f2e7e33dda49 + Post Info + False + + + + + + + + 16 + Post Info + + + + + + [uBlogsy] RSS + uBlogsyRSS + rss.png + folder.png + This document type exists only for an RSS feed. There should only be one of these. + False + uBlogsyBaseDocType + + + + uBlogsyRss + + + + + Title + uBlogsyRssTitle + ec15c1e5-9d90-422a-aa52-4f7622c63bea + 0cc0eba1-9960-42c9-bf9b-60e150b429ae + RSS Feed + False + + + + + + Description + uBlogsyRssDescription + 67db8357-ef57-493e-91ac-936d305e0f2a + c6bac0dd-4ab9-45b1-8e30-e4b619ee5da3 + RSS Feed + False + + + + + + Copyright + uBlogsyRssCopyright + ec15c1e5-9d90-422a-aa52-4f7622c63bea + 0cc0eba1-9960-42c9-bf9b-60e150b429ae + RSS Feed + False + + + + + + + + + + 29 + RSS Feed + + + + + + [uBlogsy] Site Root + uBlogsySiteRoot + house.png + folder.png + + + True + uBlogsyBasePage + + + + uBlogsySiteHome + + + uBlogsyLanding + uBlogsyPage + + + + + + + [uDateFoldersy] [Base] + uDateFoldersyBase + folder.gif + folder.png + + + False + + + + + + + + + + + [uDateFoldersy] Folder - Day + uDateFoldersyFolderDay + calendar_view_day.png + folder.png + + + False + uDateFoldersyBase + + + + uDateFoldersyFolderRedirect + + + uBlogsyPost + + + + + + + [uDateFoldersy] Folder - Month + uDateFoldersyFolderMonth + date.png + folder.png + + + False + uDateFoldersyBase + + + + uDateFoldersyFolderRedirect + + + uBlogsyPost + + + + + + + [uDateFoldersy] Folder - Year + uDateFoldersyFolderYear + folder_table.png + folder.png + + + False + uDateFoldersyBase + + + + uDateFoldersyFolderRedirect + + + uBlogsyPost + + + + + + + [uTagsy] [Base] + uTagsyBaseDocType + folder.gif + folder.png + + + False + + + + + + + + + + + [uTagsy] Tag + uTagsyTag + tag_blue.png + folder.png + + + False + uTagsyBaseDocType + + + + + + + + Tag Name + uTagsyTagName + ec15c1e5-9d90-422a-aa52-4f7622c63bea + 0cc0eba1-9960-42c9-bf9b-60e150b429ae + Tag + False + + + + + + + + 21 + Tag + + + + + + [uTagsy] Tag Container + uTagsyTagContainer + tag_blue_add.png + folder.png + + + False + uTagsyBaseDocType + + + + + + uTagsyTag + + + + + + + + + + + + + + + + + + + uBlogsy + uBlogsy + + div { padding-bottom:20px;} + +/* right col - lists */ +#uBlogsy_right_col li{ clear: both; line-height:20px;} +#uBlogsy_right_col ul { list-style-type:none; margin:5px 0; padding-left:0px; overflow:hidden; } + +/* right col - post archive */ +#uBlogsy_post_archive ul { list-style-type:none; } +#uBlogsy_post_archive ul ul { padding-left:15px; } + +#uBlogsy_post_archive .uBlogsy_post_items {display:none; margin-top:0;} +#uBlogsy_post_archive .uBlogsy_months{display:none;} + +#uBlogsy_post_archive .uBlogsy_current{ font-weight: bold;} + + +/* right col - post archive - alternate layout */ +#uBlogsy_right_col .uBlogsy_post_archive_alt .uBlogsy_year_first .uBlogsy_year_name{display:none; } +#uBlogsy_right_col .uBlogsy_post_archive_alt .uBlogsy_year_first .uBlogsy_months{ padding-left:0px; margin-top: 0;} + + +/* right col - rss logo */ +#uBlogsy_right_col .uBlogsy_feed { margin-left: 3px; padding: 0 0 0 19px; background: url("../images/uBlogsy_feed-icon-14x14.png") no-repeat 0 50%; height: 15px; display: block; float: left; overflow: hidden;} + + +#uBlogsy_right_col .uBlogsy_post_list_image{ display: inline-block;float: left; padding: 0;margin: 0 5px 1px 0;overflow: hidden;height: 25px;width: 25px;border: 1px solid #555555;} + + +/********************************************** + pagination +***********************************************/ +/* pagination - landing */ +#uBlogsy_pagination { display:block; float:right; overflow:hidden;} +#uBlogsy_pagination li{ list-style-type:none; display:block; float:left; height: 20px; padding: 0 4px 0 0;} +#uBlogsy_pagination li a { display:block; padding :3px 0 0 6px; } +#uBlogsy_pagination li.uBlogsy_page_prev span, #uBlogsy_pagination li.uBlogsy_page_next span { display:block; padding :2px 0 0 5px; color:#CCC} +#uBlogsy_pagination .uBlogsy_page_next, #uBlogsy_pagination .uBlogsy_page_prev{ width:40px;} +#uBlogsy_pagination li.uBlogsy_current a{font-weight:bold;} +#uBlogsy_pagination li.uBlogsy_current span{padding:2px 0 0 6px; display:block;} + +/* pagination - post */ +.uBlogsy_next_prev{padding-top:20px;overflow: hidden;clear: both;} +#uBlogsy .uBlogsy_next_prev a { color:#505050; } +.uBlogsy_prev {float:left;} +.uBlogsy_next {float:right;} + + + + +/********************************************** + forms +***********************************************/ +/* forms */ +.uBlogsy_search input[type=submit] { border: 1px solid #cccccc; } + +.uBlogsy_row{ overflow:hidden; position: relative; } + +.uBlogsy_row.uBlogsy_Subscribe{padding-bottom:10px;} +.uBlogsy_row.uBlogsy_Subscribe input[type=checkbox] { float:left;} +.uBlogsy_row .field-validation-error{ position: absolute; top: 0px;} +.uBlogsy_row .field-validation-valid{ display: none;} + +/* forms - search */ +.uBlogsy_search input[type=text] { border:1px solid #ccc; height:20px; margin-bottom:10px; width:200px;} +#uBlogsyBtnSearch:hover{ color:#234B7B;} + + + + + +/********************************************** + misc +***********************************************/ +.uBlogsy_bottom_border { border-bottom-color: #CCC; border-bottom-style: dotted; border-bottom-width: 1px; } + +/*add this*/ +#uBlogsy .addthis_toolbox { float:left;clear: both;margin-top: 30px;height: 30px;} +#uBlogsy .addthis_toolbox a { display:block; float:right;} + + + + + + +/********************************************** + tag cloud +***********************************************/ +.uBlogsy_tag_cloud li { display:inline-block; padding-right:10px; } +.uBlogsy_tag_cloud li span {color:#505050} +.uBlogsy_tag_cloud1 { font-size: 10px;} +.uBlogsy_tag_cloud2 { font-size: 10px;} +.uBlogsy_tag_cloud3 { font-size: 11px;} +.uBlogsy_tag_cloud4 { font-size: 11px;} +.uBlogsy_tag_cloud5 { font-size: 12px;} +.uBlogsy_tag_cloud6 { font-size: 12px;} +.uBlogsy_tag_cloud7 { font-size: 13px;} +.uBlogsy_tag_cloud8 { font-size: 13px;} +.uBlogsy_tag_cloud9 { font-size: 14px;} +.uBlogsy_tag_cloud10 { font-size: 14px;} +.uBlogsy_tag_cloud11 { font-size: 15px;} +.uBlogsy_tag_cloud12 { font-size: 15px;} +.uBlogsy_tag_cloud13 { font-size: 16px;} +.uBlogsy_tag_cloud14 { font-size: 16px;} +.uBlogsy_tag_cloud15 { font-size: 17px;} +.uBlogsy_tag_cloud16 { font-size: 17px;} +.uBlogsy_tag_cloud17 { font-size: 18px;} +.uBlogsy_tag_cloud18 { font-size: 18px;} +.uBlogsy_tag_cloud19 { font-size: 19px;} +.uBlogsy_tag_cloud20 { font-size: 19px;} +.uBlogsy_tag_cloud21 { font-size: 20px;} +.uBlogsy_tag_cloud22 { font-size: 20px;} +.uBlogsy_tag_cloud23 { font-size: 21px;} +.uBlogsy_tag_cloud24 { font-size: 21px;} +.uBlogsy_tag_cloud25 { font-size: 22px;} +.uBlogsy_tag_cloud26 { font-size: 22px;} +.uBlogsy_tag_cloud27 { font-size: 23px;} +.uBlogsy_tag_cloud28 { font-size: 23px;} +.uBlogsy_tag_cloud29 { font-size: 24px;} +.uBlogsy_tag_cloud30 { font-size: 24px;} +.uBlogsy_tag_cloud31 { font-size: 25px;} +.uBlogsy_tag_cloud32 { font-size: 25px;} +.uBlogsy_tag_cloud33 { font-size: 26px;} +.uBlogsy_tag_cloud34 { font-size: 26px;} +.uBlogsy_tag_cloud35 { font-size: 27px;} +.uBlogsy_tag_cloud36 { font-size: 27px;} +.uBlogsy_tag_cloud37 { font-size: 28px;} +.uBlogsy_tag_cloud38 { font-size: 28px;} +.uBlogsy_tag_cloud39 { font-size: 29px;} +.uBlogsy_tag_cloud40 { font-size: 29px;} +.uBlogsy_tag_cloud40 { font-size: 30px;} +.uBlogsy_tag_cloud41 { font-size: 31px;} +.uBlogsy_tag_cloud42 { font-size: 31px;} +.uBlogsy_tag_cloud43 { font-size: 32px;} +.uBlogsy_tag_cloud44 { font-size: 32px;} +.uBlogsy_tag_cloud45 { font-size: 33px;} +.uBlogsy_tag_cloud46 { font-size: 33px;} +.uBlogsy_tag_cloud47 { font-size: 34px;} +.uBlogsy_tag_cloud48 { font-size: 34px;} +.uBlogsy_tag_cloud49 { font-size: 35px;} +.uBlogsy_tag_cloud50 { font-size: 35px;} +.uBlogsy_tag_cloud50 { font-size: 36px;} +.uBlogsy_tag_cloud51 { font-size: 36px;} +.uBlogsy_tag_cloud52 { font-size: 37px;} +.uBlogsy_tag_cloud53 { font-size: 37px;} +.uBlogsy_tag_cloud54 { font-size: 38px;} +.uBlogsy_tag_cloud55 { font-size: 38px;} +.uBlogsy_tag_cloud56 { font-size: 39px;} +.uBlogsy_tag_cloud57 { font-size: 39px;} +.uBlogsy_tag_cloud58 { font-size: 40px;} +.uBlogsy_tag_cloud59 { font-size: 40px;} +.uBlogsy_tag_cloud60 { font-size: 41px;} +.uBlogsy_tag_cloud71 { font-size: 41px;} +.uBlogsy_tag_cloud72 { font-size: 42px;} +.uBlogsy_tag_cloud73 { font-size: 42px;} +.uBlogsy_tag_cloud74 { font-size: 43px;} +.uBlogsy_tag_cloud75 { font-size: 43px;} +.uBlogsy_tag_cloud76 { font-size: 44px;} +.uBlogsy_tag_cloud77 { font-size: 44px;} +.uBlogsy_tag_cloud78 { font-size: 45px;} +.uBlogsy_tag_cloud79 { font-size: 45px;} +.uBlogsy_tag_cloud80 { font-size: 46px;} +.uBlogsy_tag_cloud81 { font-size: 46px;} +.uBlogsy_tag_cloud82 { font-size: 47px;} +.uBlogsy_tag_cloud83 { font-size: 47px;} +.uBlogsy_tag_cloud84 { font-size: 48px;} +.uBlogsy_tag_cloud85 { font-size: 48px;} +.uBlogsy_tag_cloud86 { font-size: 49px;} +.uBlogsy_tag_cloud87 { font-size: 49px;} +.uBlogsy_tag_cloud88 { font-size: 50px;} +.uBlogsy_tag_cloud89 { font-size: 50px;} +.uBlogsy_tag_cloud90 { font-size: 51px;} +.uBlogsy_tag_cloud91 { font-size: 51px;} +.uBlogsy_tag_cloud92 { font-size: 52px;} +.uBlogsy_tag_cloud93 { font-size: 52px;} +.uBlogsy_tag_cloud94 { font-size: 53px;} +.uBlogsy_tag_cloud95 { font-size: 53px;} +.uBlogsy_tag_cloud96 { font-size: 54px;} +.uBlogsy_tag_cloud97 { font-size: 54px;} +.uBlogsy_tag_cloud98 { font-size: 55px;} +.uBlogsy_tag_cloud99 { font-size: 55px;} +.uBlogsy_tag_cloud100 { font-size: 56px;} + + + +]]> + + + + + + [uBlogsy] Show Some Love + uBlogsyShowSomeLove + + + + + + + True + 0 + ~/Views/MacroPartials/uBlogsy/uBlogsyMacroShowSomeLove.cshtml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + /usercontrols/uBlogsy/dashboard/Installer.ascx + + +
+ + default + content + + + /usercontrols/uBlogsy/dashboard/CreatePost.ascx + + + /usercontrols/uBlogsy/dashboard/RSSImport.ascx + +
+
+
+
\ No newline at end of file diff --git a/src/Umbraco.Tests/Umbraco.Tests.csproj b/src/Umbraco.Tests/Umbraco.Tests.csproj index 934e56a5e0..149a962eaf 100644 --- a/src/Umbraco.Tests/Umbraco.Tests.csproj +++ b/src/Umbraco.Tests/Umbraco.Tests.csproj @@ -294,6 +294,12 @@ + + + True + True + ImportResources.resx + @@ -437,10 +443,15 @@ ResXFileCodeGenerator SqlResources.Designer.cs - + + ResXFileCodeGenerator + ImportResources.Designer.cs + + ResXFileCodeGenerator TestFiles.Designer.cs + @@ -475,6 +486,11 @@ + + + Designer + + 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 6e6cc43347..175e5b9852 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/controls/ContentTypeControlNew.ascx.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/controls/ContentTypeControlNew.ascx.cs @@ -648,40 +648,26 @@ jQuery(document).ready(function() {{ refreshDropDowns(); }}); propertyType.DataTypeDefinitionId = dataTypeDefinition.Id; propertyType.DataTypeId = dataTypeDefinition.ControlId; - if (propertyType.PropertyGroupId != gpw.GenricPropertyControl.Tab) + if (propertyType.PropertyGroupId.Value != gpw.GenricPropertyControl.Tab) { if (gpw.GenricPropertyControl.Tab == 0) { - propertyType.PropertyGroupId = 0; + propertyType.PropertyGroupId = new Lazy(() => 0); } else if (contentTypeItem.PropertyGroups.Any(x => x.Id == gpw.GenricPropertyControl.Tab)) { - propertyType.PropertyGroupId = gpw.GenricPropertyControl.Tab; + propertyType.PropertyGroupId = new Lazy(() => gpw.GenricPropertyControl.Tab); } else if (contentTypeItem.PropertyGroups.Any(x => x.ParentId == gpw.GenricPropertyControl.Tab)) { var propertyGroup = contentTypeItem.PropertyGroups.First(x => x.ParentId == gpw.GenricPropertyControl.Tab); - propertyType.PropertyGroupId = propertyGroup.Id; + propertyType.PropertyGroupId = new Lazy(() => propertyGroup.Id); } else { var propertyGroup = contentTypeItem.CompositionPropertyGroups.First(x => x.Id == gpw.GenricPropertyControl.Tab); contentTypeItem.AddPropertyGroup(propertyGroup.Name); contentTypeItem.MovePropertyType(propertyType.Alias, propertyGroup.Name); - - //if ( - // contentTypeItem.CompositionPropertyGroups.Any( - // x => x.ParentId == gpw.GenricPropertyControl.Tab)) - //{ - // var propertyGroups = contentTypeItem.CompositionPropertyGroups.Where(x => x.ParentId == gpw.GenricPropertyControl.Tab); - // var propertyGroup = propertyGroups.First(); - // propertyType.PropertyGroupId = propertyGroup.Id; - //} - //else - //{ - // var propertyGroup = contentTypeItem.CompositionPropertyGroups.First(x => x.Id == gpw.GenricPropertyControl.Tab); - // contentTypeItem.AddPropertyGroup(propertyGroup.Name); - //} } } } 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 bacb1354e9..18eccdaaf1 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/dialogs/importDocumenttype.aspx.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/dialogs/importDocumenttype.aspx.cs @@ -1,17 +1,10 @@ using System; -using System.Collections; -using System.ComponentModel; -using System.Data; -using System.Drawing; -using System.Web; -using System.Web.SessionState; -using System.Web.UI; +using System.Linq; using System.Web.UI.WebControls; using System.Web.UI.HtmlControls; - -using umbraco.cms.businesslogic.member; -using umbraco.cms.businesslogic.web; using System.Xml; +using System.Xml.Linq; +using Umbraco.Core; using umbraco.IO; namespace umbraco.presentation.umbraco.dialogs @@ -27,22 +20,22 @@ namespace umbraco.presentation.umbraco.dialogs CurrentApp = BusinessLogic.DefaultApps.settings.ToString(); } - protected System.Web.UI.WebControls.Literal FeedBackMessage; - protected System.Web.UI.WebControls.Literal jsShowWindow; - protected System.Web.UI.WebControls.Panel Wizard; - protected System.Web.UI.HtmlControls.HtmlTable Table1; - protected System.Web.UI.HtmlControls.HtmlInputHidden tempFile; - protected System.Web.UI.HtmlControls.HtmlInputFile documentTypeFile; - protected System.Web.UI.WebControls.Button submit; - protected System.Web.UI.WebControls.Panel Confirm; - protected System.Web.UI.WebControls.Literal dtName; - protected System.Web.UI.WebControls.Literal dtAlias; - protected System.Web.UI.WebControls.Button import; - protected System.Web.UI.WebControls.Literal dtNameConfirm; - protected System.Web.UI.WebControls.Panel done; + protected Literal FeedBackMessage; + protected Literal jsShowWindow; + protected Panel Wizard; + protected HtmlTable Table1; + protected HtmlInputHidden tempFile; + protected HtmlInputFile documentTypeFile; + protected Button submit; + protected Panel Confirm; + protected Literal dtName; + protected Literal dtAlias; + protected Button import; + protected Literal dtNameConfirm; + protected Panel done; private string tempFileName = ""; - private void Page_Load(object sender, System.EventArgs e) + private void Page_Load(object sender, EventArgs e) { if (!IsPostBack) { @@ -74,14 +67,20 @@ namespace umbraco.presentation.umbraco.dialogs } #endregion - private void import_Click(object sender, System.EventArgs e) + private void import_Click(object sender, EventArgs e) { - XmlDocument xd = new XmlDocument(); + /*XmlDocument xd = new XmlDocument(); xd.Load(tempFile.Value); cms.businesslogic.packager.Installer.ImportDocumentType(xd.DocumentElement, base.getUser(), true); - dtNameConfirm.Text = xd.DocumentElement.SelectSingleNode("/DocumentType/Info/Name").FirstChild.Value; + dtNameConfirm.Text = xd.DocumentElement.SelectSingleNode("/DocumentType/Info/Name").FirstChild.Value;*/ - Wizard.Visible = false; + var element = XElement.Parse(tempFile.Value); + var importContentTypes = ApplicationContext.Current.Services.PackagingService.ImportContentTypes(element); + var contentType = importContentTypes.FirstOrDefault(); + if (contentType != null) + dtNameConfirm.Text = contentType.Name; + + Wizard.Visible = false; Confirm.Visible = false; done.Visible = true; } diff --git a/src/umbraco.cms/businesslogic/Packager/Installer.cs b/src/umbraco.cms/businesslogic/Packager/Installer.cs index 08e85a4919..d5fae77bcc 100644 --- a/src/umbraco.cms/businesslogic/Packager/Installer.cs +++ b/src/umbraco.cms/businesslogic/Packager/Installer.cs @@ -1,18 +1,12 @@ using System; using System.Collections; using System.Collections.Generic; -using System.Data; +using System.Globalization; using System.IO; -using System.Web; using System.Xml; -using System.Xml.XPath; -using System.Reflection; using System.Runtime.CompilerServices; using System.Linq; -using ICSharpCode.SharpZipLib; using ICSharpCode.SharpZipLib.Zip; -using ICSharpCode.SharpZipLib.Zip.Compression; -using ICSharpCode.SharpZipLib.Zip.Compression.Streams; using Umbraco.Core; using Umbraco.Core.Logging; using umbraco.cms.businesslogic.web; @@ -137,17 +131,18 @@ namespace umbraco.cms.businesslogic.packager _control = Control; } + #region Public Methods + /// /// Adds the macro to the package /// /// Macro to add - public void AddMacro(businesslogic.macro.Macro MacroToAdd) + [Obsolete("This method does nothing but add the macro to an ArrayList that is never used, so don't call this method.")] + public void AddMacro(Macro MacroToAdd) { _macros.Add(MacroToAdd); } - - - + /// /// Imports the specified package /// @@ -168,7 +163,7 @@ namespace umbraco.cms.businesslogic.packager { try { - tempDir = unPack(fi.FullName); + tempDir = UnPack(fi.FullName); LoadConfig(tempDir); } catch (Exception unpackE) @@ -184,8 +179,7 @@ namespace umbraco.cms.businesslogic.packager return tempDir; } } - - + public int CreateManifest(string tempDir, string guid, string repoGuid) { //This is the new improved install rutine, which chops up the process into 3 steps, creating the manifest, moving files, and finally handling umb objects @@ -245,9 +239,9 @@ namespace umbraco.cms.businesslogic.packager //we enclose the whole file-moving to ensure that the entire installer doesn't crash try { - String destPath = getFileName(basePath, xmlHelper.GetNodeValue(n.SelectSingleNode("orgPath"))); - String sourceFile = getFileName(tempDir, xmlHelper.GetNodeValue(n.SelectSingleNode("guid"))); - String destFile = getFileName(destPath, xmlHelper.GetNodeValue(n.SelectSingleNode("orgName"))); + String destPath = GetFileName(basePath, xmlHelper.GetNodeValue(n.SelectSingleNode("orgPath"))); + String sourceFile = GetFileName(tempDir, xmlHelper.GetNodeValue(n.SelectSingleNode("guid"))); + String destFile = GetFileName(destPath, xmlHelper.GetNodeValue(n.SelectSingleNode("orgName"))); // Create the destination directory if it doesn't exist if (!Directory.Exists(destPath)) @@ -271,21 +265,40 @@ namespace umbraco.cms.businesslogic.packager insPack.Save(); } } - - + public void InstallBusinessLogic(int packageId, string tempDir) { - using (DisposableTimer.DebugDuration( () => "Installing business logic for package id " + packageId + " into temp folder " + tempDir, () => "Package business logic installation complete for package id " + packageId)) { //retrieve the manifest to continue installation - packager.InstalledPackage insPack = packager.InstalledPackage.GetById(packageId); - bool saveNeeded = false; + var insPack = InstalledPackage.GetById(packageId); + //bool saveNeeded = false; - //Install DataTypes - foreach (XmlNode n in _packageConfig.DocumentElement.SelectNodes("//DataType")) + // Get current user, with a fallback + var currentUser = new User(0); + if (string.IsNullOrEmpty(BasePages.UmbracoEnsuredPage.umbracoUserContextID) == false) + { + if (BasePages.UmbracoEnsuredPage.ValidateUserContextID(BasePages.UmbracoEnsuredPage.umbracoUserContextID)) + { + currentUser = User.GetCurrent(); + } + } + + //Xml as XElement which is used with the new PackagingService + var rootElement = _packageConfig.DocumentElement.GetXElement(); + var packagingService = ApplicationContext.Current.Services.PackagingService; + + #region DataTypes + var dataTypeElement = rootElement.Descendants("DataTypes").First(); + var dataTypeDefinitions = packagingService.ImportDataTypeDefinitions(dataTypeElement, currentUser.Id); + foreach (var dataTypeDefinition in dataTypeDefinitions) + { + insPack.Data.DataTypes.Add(dataTypeDefinition.Id.ToString(CultureInfo.InvariantCulture)); + //saveNeeded = true; + } + /*foreach (XmlNode n in _packageConfig.DocumentElement.SelectNodes("//DataType")) { cms.businesslogic.datatype.DataTypeDefinition newDtd = cms.businesslogic.datatype.DataTypeDefinition.Import(n); @@ -294,25 +307,27 @@ namespace umbraco.cms.businesslogic.packager insPack.Data.DataTypes.Add(newDtd.Id.ToString()); saveNeeded = true; } - } + }*/ - if (saveNeeded) { insPack.Save(); saveNeeded = false; } + //if (saveNeeded) { insPack.Save(); saveNeeded = false; } + #endregion - //Install languages + #region Languages foreach (XmlNode n in _packageConfig.DocumentElement.SelectNodes("//Language")) { language.Language newLang = language.Language.Import(n); if (newLang != null) { - insPack.Data.Languages.Add(newLang.id.ToString()); - saveNeeded = true; + insPack.Data.Languages.Add(newLang.id.ToString(CultureInfo.InvariantCulture)); + //saveNeeded = true; } } - if (saveNeeded) { insPack.Save(); saveNeeded = false; } + //if (saveNeeded) { insPack.Save(); saveNeeded = false; } + #endregion - //Install dictionary items + #region Dictionary items foreach (XmlNode n in _packageConfig.DocumentElement.SelectNodes("./DictionaryItems/DictionaryItem")) { Dictionary.DictionaryItem newDi = Dictionary.DictionaryItem.Import(n); @@ -320,41 +335,42 @@ namespace umbraco.cms.businesslogic.packager if (newDi != null) { insPack.Data.DictionaryItems.Add(newDi.id.ToString()); - saveNeeded = true; + //saveNeeded = true; } } - if (saveNeeded) { insPack.Save(); saveNeeded = false; } + //if (saveNeeded) { insPack.Save(); saveNeeded = false; } + #endregion - // Install macros + #region Macros foreach (XmlNode n in _packageConfig.DocumentElement.SelectNodes("//macro")) { - cms.businesslogic.macro.Macro m = cms.businesslogic.macro.Macro.Import(n); + Macro m = Macro.Import(n); if (m != null) { - insPack.Data.Macros.Add(m.Id.ToString()); - saveNeeded = true; + insPack.Data.Macros.Add(m.Id.ToString(CultureInfo.InvariantCulture)); + //saveNeeded = true; } } - if (saveNeeded) { insPack.Save(); saveNeeded = false; } - - // Get current user, with a fallback - User u = new User(0); - if (!string.IsNullOrEmpty(BasePages.UmbracoEnsuredPage.umbracoUserContextID)) + //if (saveNeeded) { insPack.Save(); saveNeeded = false; } + #endregion + + #region Templates + var templateElement = rootElement.Descendants("Templates").First(); + var templates = packagingService.ImportTemplates(templateElement, currentUser.Id); + foreach (var template in templates) { - if (BasePages.UmbracoEnsuredPage.ValidateUserContextID(BasePages.UmbracoEnsuredPage.umbracoUserContextID)) - { - u = User.GetCurrent(); - } + insPack.Data.Templates.Add(template.Id.ToString(CultureInfo.InvariantCulture)); + //saveNeeded = true; } + //if (saveNeeded) { insPack.Save(); saveNeeded = false; } - // Add Templates - foreach (XmlNode n in _packageConfig.DocumentElement.SelectNodes("Templates/Template")) + /*foreach (XmlNode n in _packageConfig.DocumentElement.SelectNodes("Templates/Template")) { - var t = Template.Import(n, u); + var t = Template.Import(n, currentUser); insPack.Data.Templates.Add(t.Id.ToString()); @@ -371,13 +387,13 @@ namespace umbraco.cms.businesslogic.packager foreach (XmlNode n in _packageConfig.DocumentElement.SelectNodes("Templates/Template")) { string master = xmlHelper.GetNodeValue(n.SelectSingleNode("Master")); - template.Template t = template.Template.GetByAlias(xmlHelper.GetNodeValue(n.SelectSingleNode("Alias"))); + Template t = Template.GetByAlias(xmlHelper.GetNodeValue(n.SelectSingleNode("Alias"))); if (master.Trim() != "") { - template.Template masterTemplate = template.Template.GetByAlias(master); + var masterTemplate = Template.GetByAlias(master); if (masterTemplate != null) { - t.MasterTemplate = template.Template.GetByAlias(master).Id; + t.MasterTemplate = Template.GetByAlias(master).Id; //SD: This appears to always just save an empty template because the design isn't set yet // this fixes an issue now that we have MVC because if there is an empty template and MVC is // the default, it will create a View not a master page and then the system will try to route via @@ -395,12 +411,23 @@ namespace umbraco.cms.businesslogic.packager t.ImportDesign(xmlHelper.GetNodeValue(n.SelectSingleNode("Design"))); t.SaveMasterPageFile(t.Design); } + }*/ + #endregion + + #region DocumentTypes + var docTypeElement = rootElement.Descendants("DocumentTypes").First(); + var contentTypes = packagingService.ImportContentTypes(docTypeElement, currentUser.Id); + foreach (var contentType in contentTypes) + { + insPack.Data.Documenttypes.Add(contentType.Id.ToString(CultureInfo.InvariantCulture)); + //saveNeeded = true; } - // Add documenttypes - foreach (XmlNode n in _packageConfig.DocumentElement.SelectNodes("DocumentTypes/DocumentType")) + //if (saveNeeded) { insPack.Save(); saveNeeded = false; } + + /*foreach (XmlNode n in _packageConfig.DocumentElement.SelectNodes("DocumentTypes/DocumentType")) { - ImportDocumentType(n, u, false); + ImportDocumentType(n, currentUser, false); saveNeeded = true; } @@ -432,29 +459,36 @@ namespace umbraco.cms.businesslogic.packager } } - if (saveNeeded) { insPack.Save(); saveNeeded = false; } + if (saveNeeded) { insPack.Save(); saveNeeded = false; }*/ + #endregion - // Stylesheets + #region Stylesheets foreach (XmlNode n in _packageConfig.DocumentElement.SelectNodes("Stylesheets/Stylesheet")) { - StyleSheet s = StyleSheet.Import(n, u); + StyleSheet s = StyleSheet.Import(n, currentUser); insPack.Data.Stylesheets.Add(s.Id.ToString()); - saveNeeded = true; + //saveNeeded = true; } - if (saveNeeded) { insPack.Save(); saveNeeded = false; } + //if (saveNeeded) { insPack.Save(); saveNeeded = false; } + #endregion - // Documents - foreach (XmlElement n in _packageConfig.DocumentElement.SelectNodes("Documents/DocumentSet [@importMode = 'root']/*")) + #region Documents + var documentElement = rootElement.Descendants("DocumentSet").First(); + var content = packagingService.ImportContent(documentElement, -1, currentUser.Id); + var firstContentItem = content.First(); + insPack.Data.ContentNodeId = firstContentItem.Id.ToString(CultureInfo.InvariantCulture); + + /*foreach (XmlElement n in _packageConfig.DocumentElement.SelectNodes("Documents/DocumentSet [@importMode = 'root']/*")) { - insPack.Data.ContentNodeId = cms.businesslogic.web.Document.Import(-1, u, n).ToString(); - } + insPack.Data.ContentNodeId = cms.businesslogic.web.Document.Import(-1, currentUser, n).ToString(); + }*/ + #endregion - //Package Actions + #region Package Actions foreach (XmlNode n in _packageConfig.DocumentElement.SelectNodes("Actions/Action")) { - if (n.Attributes["undo"] == null || n.Attributes["undo"].Value == "true") { insPack.Data.Actions += n.OuterXml; @@ -464,7 +498,7 @@ namespace umbraco.cms.businesslogic.packager { try { - packager.PackageAction.RunPackageAction(insPack.Data.Name, n.Attributes["alias"].Value, n); + PackageAction.RunPackageAction(insPack.Data.Name, n.Attributes["alias"].Value, n); } catch { @@ -472,6 +506,7 @@ namespace umbraco.cms.businesslogic.packager } } } + #endregion // Trigger update of Apps / Trees config. // (These are ApplicationStartupHandlers so just instantiating them will trigger them) @@ -499,30 +534,54 @@ namespace umbraco.cms.businesslogic.packager /// Invoking this method installs the entire current package ///
/// Temporary folder where the package's content are extracted to + /// + /// public void Install(string tempDir, string guid, string repoGuid) { //PPH added logging of installs, this adds all install info in the installedPackages config file. - string _packName = xmlHelper.GetNodeValue(_packageConfig.DocumentElement.SelectSingleNode("/umbPackage/info/package/name")); - string _packAuthor = xmlHelper.GetNodeValue(_packageConfig.DocumentElement.SelectSingleNode("/umbPackage/info/author/name")); - string _packAuthorUrl = xmlHelper.GetNodeValue(_packageConfig.DocumentElement.SelectSingleNode("/umbPackage/info/author/website")); - string _packVersion = xmlHelper.GetNodeValue(_packageConfig.DocumentElement.SelectSingleNode("/umbPackage/info/package/version")); - string _packReadme = xmlHelper.GetNodeValue(_packageConfig.DocumentElement.SelectSingleNode("/umbPackage/info/readme")); - string _packLicense = xmlHelper.GetNodeValue(_packageConfig.DocumentElement.SelectSingleNode("/umbPackage/info/package/license ")); + string packName = xmlHelper.GetNodeValue(_packageConfig.DocumentElement.SelectSingleNode("/umbPackage/info/package/name")); + string packAuthor = xmlHelper.GetNodeValue(_packageConfig.DocumentElement.SelectSingleNode("/umbPackage/info/author/name")); + string packAuthorUrl = xmlHelper.GetNodeValue(_packageConfig.DocumentElement.SelectSingleNode("/umbPackage/info/author/website")); + string packVersion = xmlHelper.GetNodeValue(_packageConfig.DocumentElement.SelectSingleNode("/umbPackage/info/package/version")); + string packReadme = xmlHelper.GetNodeValue(_packageConfig.DocumentElement.SelectSingleNode("/umbPackage/info/readme")); + string packLicense = xmlHelper.GetNodeValue(_packageConfig.DocumentElement.SelectSingleNode("/umbPackage/info/package/license ")); //Create a new package instance to record all the installed package adds - this is the same format as the created packages has. //save the package meta data - packager.InstalledPackage insPack = packager.InstalledPackage.MakeNew(_packName); - insPack.Data.Author = _packAuthor; - insPack.Data.AuthorUrl = _packAuthorUrl; - insPack.Data.Version = _packVersion; - insPack.Data.Readme = _packReadme; - insPack.Data.License = _packLicense; + var insPack = InstalledPackage.MakeNew(packName); + insPack.Data.Author = packAuthor; + insPack.Data.AuthorUrl = packAuthorUrl; + insPack.Data.Version = packVersion; + insPack.Data.Readme = packReadme; + insPack.Data.License = packLicense; insPack.Data.PackageGuid = guid; //the package unique key. insPack.Data.RepositoryGuid = repoGuid; //the repository unique key, if the package is a file install, the repository will not get logged. + // Get current user, with a fallback + var currentUser = new User(0); + if (string.IsNullOrEmpty(BasePages.UmbracoEnsuredPage.umbracoUserContextID) == false) + { + if (BasePages.UmbracoEnsuredPage.ValidateUserContextID(BasePages.UmbracoEnsuredPage.umbracoUserContextID)) + { + currentUser = User.GetCurrent(); + } + } - //Install languages + //Xml as XElement which is used with the new PackagingService + var rootElement = _packageConfig.DocumentElement.GetXElement(); + var packagingService = ApplicationContext.Current.Services.PackagingService; + + #region DataTypes + var dataTypeElement = rootElement.Descendants("DataTypes").First(); + var dataTypeDefinitions = packagingService.ImportDataTypeDefinitions(dataTypeElement, currentUser.Id); + foreach (var dataTypeDefinition in dataTypeDefinitions) + { + insPack.Data.DataTypes.Add(dataTypeDefinition.Id.ToString(CultureInfo.InvariantCulture)); + } + #endregion + + #region Install Languages foreach (XmlNode n in _packageConfig.DocumentElement.SelectNodes("//Language")) { language.Language newLang = language.Language.Import(n); @@ -530,8 +589,9 @@ namespace umbraco.cms.businesslogic.packager if (newLang != null) insPack.Data.Languages.Add(newLang.id.ToString()); } + #endregion - //Install dictionary items + #region Install Dictionary Items foreach (XmlNode n in _packageConfig.DocumentElement.SelectNodes("./DictionaryItems/DictionaryItem")) { Dictionary.DictionaryItem newDi = Dictionary.DictionaryItem.Import(n); @@ -539,23 +599,25 @@ namespace umbraco.cms.businesslogic.packager if (newDi != null) insPack.Data.DictionaryItems.Add(newDi.id.ToString()); } + #endregion - // Install macros + #region Install Macros foreach (XmlNode n in _packageConfig.DocumentElement.SelectNodes("//macro")) { - cms.businesslogic.macro.Macro m = cms.businesslogic.macro.Macro.Import(n); + Macro m = Macro.Import(n); if (m != null) insPack.Data.Macros.Add(m.Id.ToString()); } + #endregion - // Move files + #region Move files string basePath = System.Web.Hosting.HostingEnvironment.ApplicationPhysicalPath; foreach (XmlNode n in _packageConfig.DocumentElement.SelectNodes("//file")) { - String destPath = getFileName(basePath, xmlHelper.GetNodeValue(n.SelectSingleNode("orgPath"))); - String sourceFile = getFileName(tempDir, xmlHelper.GetNodeValue(n.SelectSingleNode("guid"))); - String destFile = getFileName(destPath, xmlHelper.GetNodeValue(n.SelectSingleNode("orgName"))); + String destPath = GetFileName(basePath, xmlHelper.GetNodeValue(n.SelectSingleNode("orgPath"))); + String sourceFile = GetFileName(tempDir, xmlHelper.GetNodeValue(n.SelectSingleNode("guid"))); + String destFile = GetFileName(destPath, xmlHelper.GetNodeValue(n.SelectSingleNode("orgName"))); // Create the destination directory if it doesn't exist if (!Directory.Exists(destPath)) @@ -569,33 +631,36 @@ namespace umbraco.cms.businesslogic.packager //PPH log file install insPack.Data.Files.Add(xmlHelper.GetNodeValue(n.SelectSingleNode("orgPath")) + "/" + xmlHelper.GetNodeValue(n.SelectSingleNode("orgName"))); } + #endregion - - // Get current user - BusinessLogic.User u = User.GetCurrent(); - - // Add Templates - foreach (XmlNode n in _packageConfig.DocumentElement.SelectNodes("Templates/Template")) + #region Install Templates + var templateElement = rootElement.Descendants("Templates").First(); + var templates = packagingService.ImportTemplates(templateElement, currentUser.Id); + foreach (var template in templates) { - template.Template t = template.Template.MakeNew(xmlHelper.GetNodeValue(n.SelectSingleNode("Name")), u); + insPack.Data.Templates.Add(template.Id.ToString(CultureInfo.InvariantCulture)); + } + /*foreach (XmlNode n in _packageConfig.DocumentElement.SelectNodes("Templates/Template")) + { + Template t = Template.MakeNew(xmlHelper.GetNodeValue(n.SelectSingleNode("Name")), currentUser); t.Alias = xmlHelper.GetNodeValue(n.SelectSingleNode("Alias")); t.ImportDesign(xmlHelper.GetNodeValue(n.SelectSingleNode("Design"))); insPack.Data.Templates.Add(t.Id.ToString()); } - + // Add master templates foreach (XmlNode n in _packageConfig.DocumentElement.SelectNodes("Templates/Template")) { string master = xmlHelper.GetNodeValue(n.SelectSingleNode("Master")); - template.Template t = template.Template.GetByAlias(xmlHelper.GetNodeValue(n.SelectSingleNode("Alias"))); + Template t = Template.GetByAlias(xmlHelper.GetNodeValue(n.SelectSingleNode("Alias"))); if (master.Trim() != "") { - template.Template masterTemplate = template.Template.GetByAlias(master); + Template masterTemplate = Template.GetByAlias(master); if (masterTemplate != null) { - t.MasterTemplate = template.Template.GetByAlias(master).Id; + t.MasterTemplate = Template.GetByAlias(master).Id; if (UmbracoSettings.UseAspNetMasterPages) t.SaveMasterPageFile(t.Design); } @@ -606,12 +671,19 @@ namespace umbraco.cms.businesslogic.packager t.ImportDesign(xmlHelper.GetNodeValue(n.SelectSingleNode("Design"))); t.SaveMasterPageFile(t.Design); } - } + }*/ + #endregion - // Add documenttypes - foreach (XmlNode n in _packageConfig.DocumentElement.SelectNodes("DocumentTypes/DocumentType")) + #region Install DocumentTypes + var docTypeElement = rootElement.Descendants("DocumentTypes").First(); + var contentTypes = packagingService.ImportContentTypes(docTypeElement, currentUser.Id); + foreach (var contentType in contentTypes) { - ImportDocumentType(n, u, false); + insPack.Data.Documenttypes.Add(contentType.Id.ToString(CultureInfo.InvariantCulture)); + } + /*foreach (XmlNode n in _packageConfig.DocumentElement.SelectNodes("DocumentTypes/DocumentType")) + { + ImportDocumentType(n, currentUser, false); } // Add documenttype structure @@ -634,13 +706,14 @@ namespace umbraco.cms.businesslogic.packager //PPH we log the document type install here. insPack.Data.Documenttypes.Add(dt.Id.ToString()); } - } + }*/ + #endregion - // Stylesheets + #region Install Stylesheets foreach (XmlNode n in _packageConfig.DocumentElement.SelectNodes("Stylesheets/Stylesheet")) { StyleSheet s = StyleSheet.MakeNew( - u, + currentUser, xmlHelper.GetNodeValue(n.SelectSingleNode("Name")), xmlHelper.GetNodeValue(n.SelectSingleNode("FileName")), xmlHelper.GetNodeValue(n.SelectSingleNode("Content"))); @@ -650,7 +723,7 @@ namespace umbraco.cms.businesslogic.packager StylesheetProperty sp = StylesheetProperty.MakeNew( xmlHelper.GetNodeValue(prop.SelectSingleNode("Name")), s, - u); + currentUser); sp.Alias = xmlHelper.GetNodeValue(prop.SelectSingleNode("Alias")); sp.value = xmlHelper.GetNodeValue(prop.SelectSingleNode("Value")); } @@ -659,20 +732,29 @@ namespace umbraco.cms.businesslogic.packager insPack.Data.Stylesheets.Add(s.Id.ToString()); } + #endregion - // Documents - foreach (XmlElement n in _packageConfig.DocumentElement.SelectNodes("Documents/DocumentSet [@importMode = 'root']/*")) + #region Install Documents + var documentElement = rootElement.Descendants("DocumentSet").First(); + var content = packagingService.ImportContent(documentElement, -1, currentUser.Id); + + var firstContentItem = content.First(); + insPack.Data.ContentNodeId = firstContentItem.Id.ToString(CultureInfo.InvariantCulture); + + /*foreach (XmlElement n in _packageConfig.DocumentElement.SelectNodes("Documents/DocumentSet [@importMode = 'root']/*")) { - cms.businesslogic.web.Document.Import(-1, u, n); + Document.Import(-1, currentUser, n); //PPH todo log document install... - } + }*/ + #endregion + #region Install Actions foreach (XmlNode n in _packageConfig.DocumentElement.SelectNodes("Actions/Action [@runat != 'uninstall']")) { try { - packager.PackageAction.RunPackageAction(_packName, n.Attributes["alias"].Value, n); + PackageAction.RunPackageAction(packName, n.Attributes["alias"].Value, n); } catch { } } @@ -682,268 +764,11 @@ namespace umbraco.cms.businesslogic.packager { insPack.Data.Actions += n.OuterXml; } - + #endregion insPack.Save(); - - } - - public static void ImportDocumentType(XmlNode n, BusinessLogic.User u, bool ImportStructure) - { - DocumentType dt = DocumentType.GetByAlias(xmlHelper.GetNodeValue(n.SelectSingleNode("Info/Alias"))); - if (dt == null) - { - dt = DocumentType.MakeNew(u, xmlHelper.GetNodeValue(n.SelectSingleNode("Info/Name"))); - dt.Alias = xmlHelper.GetNodeValue(n.SelectSingleNode("Info/Alias")); - - - //Master content type - DocumentType mdt = DocumentType.GetByAlias(xmlHelper.GetNodeValue(n.SelectSingleNode("Info/Master"))); - if (mdt != null) - dt.MasterContentType = mdt.Id; - } - else - { - dt.Text = xmlHelper.GetNodeValue(n.SelectSingleNode("Info/Name")); - } - - - // Info - dt.IconUrl = xmlHelper.GetNodeValue(n.SelectSingleNode("Info/Icon")); - dt.Thumbnail = xmlHelper.GetNodeValue(n.SelectSingleNode("Info/Thumbnail")); - dt.Description = xmlHelper.GetNodeValue(n.SelectSingleNode("Info/Description")); - - // Allow at root (check for node due to legacy) - bool allowAtRoot = false; - string allowAtRootNode = xmlHelper.GetNodeValue(n.SelectSingleNode("Info/AllowAtRoot")); - if (!String.IsNullOrEmpty(allowAtRootNode)) - { - bool.TryParse(allowAtRootNode, out allowAtRoot); - } - dt.AllowAtRoot = allowAtRoot; - - // Templates - ArrayList templates = new ArrayList(); - foreach (XmlNode tem in n.SelectNodes("Info/AllowedTemplates/Template")) - { - template.Template t = template.Template.GetByAlias(xmlHelper.GetNodeValue(tem)); - if (t != null) - templates.Add(t); - } - - try - { - template.Template[] at = new template.Template[templates.Count]; - for (int i = 0; i < templates.Count; i++) - at[i] = (template.Template)templates[i]; - dt.allowedTemplates = at; - } - catch (Exception ee) - { - LogHelper.Error("Packager: Error handling allowed templates", ee); - } - - // Default template - try - { - if (xmlHelper.GetNodeValue(n.SelectSingleNode("Info/DefaultTemplate")) != "") - dt.DefaultTemplate = template.Template.GetByAlias(xmlHelper.GetNodeValue(n.SelectSingleNode("Info/DefaultTemplate"))).Id; - } - catch (Exception ee) - { - LogHelper.Error("Packager: Error assigning default template", ee); - } - - // Tabs - cms.businesslogic.ContentType.TabI[] tabs = dt.getVirtualTabs; - string tabNames = ";"; - for (int t = 0; t < tabs.Length; t++) - tabNames += tabs[t].Caption + ";"; - - - - Hashtable ht = new Hashtable(); - foreach (XmlNode t in n.SelectNodes("Tabs/Tab")) - { - if (tabNames.IndexOf(";" + xmlHelper.GetNodeValue(t.SelectSingleNode("Caption")) + ";") == -1) - { - ht.Add(int.Parse(xmlHelper.GetNodeValue(t.SelectSingleNode("Id"))), - dt.AddVirtualTab(xmlHelper.GetNodeValue(t.SelectSingleNode("Caption")))); - } - } - - dt.ClearVirtualTabs(); - // Get all tabs in hashtable - Hashtable tabList = new Hashtable(); - foreach (cms.businesslogic.ContentType.TabI t in dt.getVirtualTabs.ToList()) - { - if (!tabList.ContainsKey(t.Caption)) - tabList.Add(t.Caption, t.Id); - } - - // Generic Properties - datatype.controls.Factory f = new datatype.controls.Factory(); - foreach (XmlNode gp in n.SelectNodes("GenericProperties/GenericProperty")) - { - int dfId = 0; - Guid dtId = new Guid(xmlHelper.GetNodeValue(gp.SelectSingleNode("Type"))); - - if (gp.SelectSingleNode("Definition") != null && !string.IsNullOrEmpty(xmlHelper.GetNodeValue(gp.SelectSingleNode("Definition")))) - { - Guid dtdId = new Guid(xmlHelper.GetNodeValue(gp.SelectSingleNode("Definition"))); - if (CMSNode.IsNode(dtdId)) - dfId = new CMSNode(dtdId).Id; - } - if (dfId == 0) - { - try - { - dfId = findDataTypeDefinitionFromType(ref dtId); - } - catch - { - throw new Exception(String.Format("Could not find datatype with id {0}.", dtId)); - } - } - - // Fix for rich text editor backwards compatibility - if (dfId == 0 && dtId == new Guid("a3776494-0574-4d93-b7de-efdfdec6f2d1")) - { - dtId = new Guid(Constants.PropertyEditors.TinyMCE); - dfId = findDataTypeDefinitionFromType(ref dtId); - } - - if (dfId != 0) - { - PropertyType pt = dt.getPropertyType(xmlHelper.GetNodeValue(gp.SelectSingleNode("Alias"))); - if (pt == null) - { - dt.AddPropertyType( - datatype.DataTypeDefinition.GetDataTypeDefinition(dfId), - xmlHelper.GetNodeValue(gp.SelectSingleNode("Alias")), - xmlHelper.GetNodeValue(gp.SelectSingleNode("Name")) - ); - pt = dt.getPropertyType(xmlHelper.GetNodeValue(gp.SelectSingleNode("Alias"))); - } - else - { - pt.DataTypeDefinition = datatype.DataTypeDefinition.GetDataTypeDefinition(dfId); - pt.Name = xmlHelper.GetNodeValue(gp.SelectSingleNode("Name")); - } - - pt.Mandatory = bool.Parse(xmlHelper.GetNodeValue(gp.SelectSingleNode("Mandatory"))); - pt.ValidationRegExp = xmlHelper.GetNodeValue(gp.SelectSingleNode("Validation")); - pt.Description = xmlHelper.GetNodeValue(gp.SelectSingleNode("Description")); - - // tab - try - { - if (tabList.ContainsKey(xmlHelper.GetNodeValue(gp.SelectSingleNode("Tab")))) - pt.TabId = (int)tabList[xmlHelper.GetNodeValue(gp.SelectSingleNode("Tab"))]; - } - catch (Exception ee) - { - LogHelper.Error("Packager: Error assigning property to tab", ee); - } - } - } - - if (ImportStructure) - { - if (dt != null) - { - ArrayList allowed = new ArrayList(); - foreach (XmlNode structure in n.SelectNodes("Structure/DocumentType")) - { - DocumentType dtt = DocumentType.GetByAlias(xmlHelper.GetNodeValue(structure)); - if (dtt != null) - allowed.Add(dtt.Id); - } - int[] adt = new int[allowed.Count]; - for (int i = 0; i < allowed.Count; i++) - adt[i] = (int)allowed[i]; - dt.AllowedChildContentTypeIDs = adt; - } - } - - // clear caching (NOTE: SD: there is no tab caching so this really doesn't do anything) - foreach (DocumentType.TabI t in dt.getVirtualTabs.ToList()) - DocumentType.FlushTabCache(t.Id, dt.Id); - - dt.Save(); - } - - /// - /// Gets the name of the file in the specified path. - /// Corrects possible problems with slashes that would result from a simple concatenation. - /// Can also be used to concatenate paths. - /// - /// The path. - /// Name of the file. - /// The name of the file in the specified path. - private static String getFileName(String path, string fileName) - { - // virtual dir support - fileName = IOHelper.FindFile(fileName); - - if (path.Contains("[$")) - { - //this is experimental and undocumented... - path = path.Replace("[$UMBRACO]", IO.SystemDirectories.Umbraco); - path = path.Replace("[$UMBRACOCLIENT]", IO.SystemDirectories.Umbraco_client); - path = path.Replace("[$CONFIG]", IO.SystemDirectories.Config); - path = path.Replace("[$DATA]", IO.SystemDirectories.Data); - } - - //to support virtual dirs we try to lookup the file... - path = IOHelper.FindFile(path); - - - - Debug.Assert(path != null && path.Length >= 1); - Debug.Assert(fileName != null && fileName.Length >= 1); - - path = path.Replace('/', '\\'); - fileName = fileName.Replace('/', '\\'); - - // Does filename start with a slash? Does path end with one? - bool fileNameStartsWithSlash = (fileName[0] == Path.DirectorySeparatorChar); - bool pathEndsWithSlash = (path[path.Length - 1] == Path.DirectorySeparatorChar); - - // Path ends with a slash - if (pathEndsWithSlash) - { - if (!fileNameStartsWithSlash) - // No double slash, just concatenate - return path + fileName; - else - // Double slash, exclude that of the file - return path + fileName.Substring(1); - } - else - { - if (fileNameStartsWithSlash) - // Required slash specified, just concatenate - return path + fileName; - else - // Required slash missing, add it - return path + Path.DirectorySeparatorChar + fileName; - } - } - - private static int findDataTypeDefinitionFromType(ref Guid dtId) - { - int dfId = 0; - foreach (datatype.DataTypeDefinition df in datatype.DataTypeDefinition.GetAll()) - if (df.DataType.Id == dtId) - { - dfId = df.Id; - break; - } - return dfId; - } - + /// /// Reads the configuration of the package from the configuration xmldocument /// @@ -969,8 +794,8 @@ namespace umbraco.cms.businesslogic.packager foreach (XmlNode n in _packageConfig.DocumentElement.SelectNodes("//file")) { bool badFile = false; - string destPath = getFileName(basePath, xmlHelper.GetNodeValue(n.SelectSingleNode("orgPath"))); - string destFile = getFileName(destPath, xmlHelper.GetNodeValue(n.SelectSingleNode("orgName"))); + string destPath = GetFileName(basePath, xmlHelper.GetNodeValue(n.SelectSingleNode("orgPath"))); + string destFile = GetFileName(destPath, xmlHelper.GetNodeValue(n.SelectSingleNode("orgName"))); if (destPath.ToLower().Contains(IOHelper.DirSepChar + "app_code")) badFile = true; @@ -1038,25 +863,317 @@ namespace umbraco.cms.businesslogic.packager _readme = xmlHelper.GetNodeValue(_packageConfig.DocumentElement.SelectSingleNode("/umbPackage/info/readme")); } catch { } + try { _control = xmlHelper.GetNodeValue(_packageConfig.DocumentElement.SelectSingleNode("/umbPackage/control")); } catch { } } + + /// + /// This uses the old method of fetching and only supports the packages.umbraco.org repository. + /// + /// + /// + public string Fetch(Guid Package) + { + // Check for package directory + if (!Directory.Exists(IOHelper.MapPath(SystemDirectories.Packages))) + Directory.CreateDirectory(IOHelper.MapPath(SystemDirectories.Packages)); - private string unPack(string ZipName) + var wc = new System.Net.WebClient(); + + wc.DownloadFile( + "http://" + UmbracoSettings.PackageServer + "/fetch?package=" + Package.ToString(), + IOHelper.MapPath(SystemDirectories.Packages + "/" + Package.ToString() + ".umb")); + + return "packages\\" + Package.ToString() + ".umb"; + } + + #endregion + + #region Public Static Methods + + [Obsolete("This method is empty, so calling it will have no effect whatsoever.")] + public static void updatePackageInfo(Guid Package, int VersionMajor, int VersionMinor, int VersionPatch, User User) + { + //Why does this even exist? + } + + [Obsolete("Use ApplicationContext.Current.Services.PackagingService.ImportContentTypes instead")] + public static void ImportDocumentType(XmlNode n, User u, bool ImportStructure) + { + var element = n.GetXElement(); + var contentTypes = ApplicationContext.Current.Services.PackagingService.ImportContentTypes(element, u.Id); + /*DocumentType dt = DocumentType.GetByAlias(xmlHelper.GetNodeValue(n.SelectSingleNode("Info/Alias"))); + if (dt == null) + { + dt = DocumentType.MakeNew(u, xmlHelper.GetNodeValue(n.SelectSingleNode("Info/Name"))); + dt.Alias = xmlHelper.GetNodeValue(n.SelectSingleNode("Info/Alias")); + + + //Master content type + DocumentType mdt = DocumentType.GetByAlias(xmlHelper.GetNodeValue(n.SelectSingleNode("Info/Master"))); + if (mdt != null) + dt.MasterContentType = mdt.Id; + } + else + { + dt.Text = xmlHelper.GetNodeValue(n.SelectSingleNode("Info/Name")); + } + + + // Info + dt.IconUrl = xmlHelper.GetNodeValue(n.SelectSingleNode("Info/Icon")); + dt.Thumbnail = xmlHelper.GetNodeValue(n.SelectSingleNode("Info/Thumbnail")); + dt.Description = xmlHelper.GetNodeValue(n.SelectSingleNode("Info/Description")); + + // Allow at root (check for node due to legacy) + bool allowAtRoot = false; + string allowAtRootNode = xmlHelper.GetNodeValue(n.SelectSingleNode("Info/AllowAtRoot")); + if (!String.IsNullOrEmpty(allowAtRootNode)) + { + bool.TryParse(allowAtRootNode, out allowAtRoot); + } + dt.AllowAtRoot = allowAtRoot; + + // Templates + ArrayList templates = new ArrayList(); + foreach (XmlNode tem in n.SelectNodes("Info/AllowedTemplates/Template")) + { + template.Template t = template.Template.GetByAlias(xmlHelper.GetNodeValue(tem)); + if (t != null) + templates.Add(t); + } + + try + { + template.Template[] at = new template.Template[templates.Count]; + for (int i = 0; i < templates.Count; i++) + at[i] = (template.Template)templates[i]; + dt.allowedTemplates = at; + } + catch (Exception ee) + { + LogHelper.Error("Packager: Error handling allowed templates", ee); + } + + // Default template + try + { + if (xmlHelper.GetNodeValue(n.SelectSingleNode("Info/DefaultTemplate")) != "") + dt.DefaultTemplate = template.Template.GetByAlias(xmlHelper.GetNodeValue(n.SelectSingleNode("Info/DefaultTemplate"))).Id; + } + catch (Exception ee) + { + LogHelper.Error("Packager: Error assigning default template", ee); + } + + // Tabs + cms.businesslogic.ContentType.TabI[] tabs = dt.getVirtualTabs; + string tabNames = ";"; + for (int t = 0; t < tabs.Length; t++) + tabNames += tabs[t].Caption + ";"; + + + //So the Tab is added to the DocumentType and then to this Hashtable, but its never used anywhere - WHY? + Hashtable ht = new Hashtable(); + foreach (XmlNode t in n.SelectNodes("Tabs/Tab")) + { + if (tabNames.IndexOf(";" + xmlHelper.GetNodeValue(t.SelectSingleNode("Caption")) + ";") == -1) + { + ht.Add(int.Parse(xmlHelper.GetNodeValue(t.SelectSingleNode("Id"))), + dt.AddVirtualTab(xmlHelper.GetNodeValue(t.SelectSingleNode("Caption")))); + } + } + + dt.ClearVirtualTabs(); + // Get all tabs in hashtable + Hashtable tabList = new Hashtable(); + foreach (cms.businesslogic.ContentType.TabI t in dt.getVirtualTabs.ToList()) + { + if (!tabList.ContainsKey(t.Caption)) + tabList.Add(t.Caption, t.Id); + } + + // Generic Properties + datatype.controls.Factory f = new datatype.controls.Factory(); + foreach (XmlNode gp in n.SelectNodes("GenericProperties/GenericProperty")) + { + int dfId = 0; + Guid dtId = new Guid(xmlHelper.GetNodeValue(gp.SelectSingleNode("Type"))); + + if (gp.SelectSingleNode("Definition") != null && !string.IsNullOrEmpty(xmlHelper.GetNodeValue(gp.SelectSingleNode("Definition")))) + { + Guid dtdId = new Guid(xmlHelper.GetNodeValue(gp.SelectSingleNode("Definition"))); + if (CMSNode.IsNode(dtdId)) + dfId = new CMSNode(dtdId).Id; + } + if (dfId == 0) + { + try + { + dfId = FindDataTypeDefinitionFromType(ref dtId); + } + catch + { + throw new Exception(String.Format("Could not find datatype with id {0}.", dtId)); + } + } + + // Fix for rich text editor backwards compatibility + if (dfId == 0 && dtId == new Guid("a3776494-0574-4d93-b7de-efdfdec6f2d1")) + { + dtId = new Guid(Constants.PropertyEditors.TinyMCE); + dfId = FindDataTypeDefinitionFromType(ref dtId); + } + + if (dfId != 0) + { + PropertyType pt = dt.getPropertyType(xmlHelper.GetNodeValue(gp.SelectSingleNode("Alias"))); + if (pt == null) + { + dt.AddPropertyType( + datatype.DataTypeDefinition.GetDataTypeDefinition(dfId), + xmlHelper.GetNodeValue(gp.SelectSingleNode("Alias")), + xmlHelper.GetNodeValue(gp.SelectSingleNode("Name")) + ); + pt = dt.getPropertyType(xmlHelper.GetNodeValue(gp.SelectSingleNode("Alias"))); + } + else + { + pt.DataTypeDefinition = datatype.DataTypeDefinition.GetDataTypeDefinition(dfId); + pt.Name = xmlHelper.GetNodeValue(gp.SelectSingleNode("Name")); + } + + pt.Mandatory = bool.Parse(xmlHelper.GetNodeValue(gp.SelectSingleNode("Mandatory"))); + pt.ValidationRegExp = xmlHelper.GetNodeValue(gp.SelectSingleNode("Validation")); + pt.Description = xmlHelper.GetNodeValue(gp.SelectSingleNode("Description")); + + // tab + try + { + if (tabList.ContainsKey(xmlHelper.GetNodeValue(gp.SelectSingleNode("Tab")))) + pt.TabId = (int)tabList[xmlHelper.GetNodeValue(gp.SelectSingleNode("Tab"))]; + } + catch (Exception ee) + { + LogHelper.Error("Packager: Error assigning property to tab", ee); + } + } + } + + if (ImportStructure) + { + if (dt != null) + { + ArrayList allowed = new ArrayList(); + foreach (XmlNode structure in n.SelectNodes("Structure/DocumentType")) + { + DocumentType dtt = DocumentType.GetByAlias(xmlHelper.GetNodeValue(structure)); + if (dtt != null) + allowed.Add(dtt.Id); + } + int[] adt = new int[allowed.Count]; + for (int i = 0; i < allowed.Count; i++) + adt[i] = (int)allowed[i]; + dt.AllowedChildContentTypeIDs = adt; + } + } + + // clear caching (NOTE: SD: there is no tab caching so this really doesn't do anything) + foreach (DocumentType.TabI t in dt.getVirtualTabs.ToList()) + DocumentType.FlushTabCache(t.Id, dt.Id); + + dt.Save();*/ + } + + #endregion + + #region Private Methods + + /// + /// Gets the name of the file in the specified path. + /// Corrects possible problems with slashes that would result from a simple concatenation. + /// Can also be used to concatenate paths. + /// + /// The path. + /// Name of the file. + /// The name of the file in the specified path. + private static String GetFileName(String path, string fileName) + { + // virtual dir support + fileName = IOHelper.FindFile(fileName); + + if (path.Contains("[$")) + { + //this is experimental and undocumented... + path = path.Replace("[$UMBRACO]", IO.SystemDirectories.Umbraco); + path = path.Replace("[$UMBRACOCLIENT]", IO.SystemDirectories.Umbraco_client); + path = path.Replace("[$CONFIG]", IO.SystemDirectories.Config); + path = path.Replace("[$DATA]", IO.SystemDirectories.Data); + } + + //to support virtual dirs we try to lookup the file... + path = IOHelper.FindFile(path); + + + + Debug.Assert(path != null && path.Length >= 1); + Debug.Assert(fileName != null && fileName.Length >= 1); + + path = path.Replace('/', '\\'); + fileName = fileName.Replace('/', '\\'); + + // Does filename start with a slash? Does path end with one? + bool fileNameStartsWithSlash = (fileName[0] == Path.DirectorySeparatorChar); + bool pathEndsWithSlash = (path[path.Length - 1] == Path.DirectorySeparatorChar); + + // Path ends with a slash + if (pathEndsWithSlash) + { + if (!fileNameStartsWithSlash) + // No double slash, just concatenate + return path + fileName; + else + // Double slash, exclude that of the file + return path + fileName.Substring(1); + } + else + { + if (fileNameStartsWithSlash) + // Required slash specified, just concatenate + return path + fileName; + else + // Required slash missing, add it + return path + Path.DirectorySeparatorChar + fileName; + } + } + + private static int FindDataTypeDefinitionFromType(ref Guid dtId) + { + int dfId = 0; + foreach (datatype.DataTypeDefinition df in datatype.DataTypeDefinition.GetAll()) + if (df.DataType.Id == dtId) + { + dfId = df.Id; + break; + } + return dfId; + } + + private static string UnPack(string zipName) { // Unzip string tempDir = IOHelper.MapPath(SystemDirectories.Data) + Path.DirectorySeparatorChar + Guid.NewGuid().ToString(); Directory.CreateDirectory(tempDir); - ZipInputStream s = new ZipInputStream(File.OpenRead(ZipName)); + var s = new ZipInputStream(File.OpenRead(zipName)); ZipEntry theEntry; while ((theEntry = s.GetNextEntry()) != null) { - string directoryName = Path.GetDirectoryName(theEntry.Name); string fileName = Path.GetFileName(theEntry.Name); if (fileName != String.Empty) @@ -1085,34 +1202,13 @@ namespace umbraco.cms.businesslogic.packager // Clean up s.Close(); - File.Delete(ZipName); + File.Delete(zipName); return tempDir; } - //this uses the old method of fetching and only supports the packages.umbraco.org repository. - public string Fetch(Guid Package) - { - - // Check for package directory - if (!System.IO.Directory.Exists(IOHelper.MapPath(SystemDirectories.Packages))) - System.IO.Directory.CreateDirectory(IOHelper.MapPath(SystemDirectories.Packages)); - - System.Net.WebClient wc = new System.Net.WebClient(); - - wc.DownloadFile( - "http://" + UmbracoSettings.PackageServer + "/fetch?package=" + Package.ToString(), - IOHelper.MapPath(SystemDirectories.Packages + "/" + Package.ToString() + ".umb")); - - return "packages\\" + Package.ToString() + ".umb"; - } - - - public static void updatePackageInfo(Guid Package, int VersionMajor, int VersionMinor, int VersionPatch, User User) - { - - } + #endregion } public class Package diff --git a/src/umbraco.cms/businesslogic/Packager/PackageInstance/InstalledPackage.cs b/src/umbraco.cms/businesslogic/Packager/PackageInstance/InstalledPackage.cs index 7a3ab5bf29..94c523aeab 100644 --- a/src/umbraco.cms/businesslogic/Packager/PackageInstance/InstalledPackage.cs +++ b/src/umbraco.cms/businesslogic/Packager/PackageInstance/InstalledPackage.cs @@ -1,12 +1,13 @@ using System; using System.Collections.Generic; -using System.Text; -using System.Web; using Umbraco.Core.Logging; using umbraco.IO; namespace umbraco.cms.businesslogic.packager { - public class InstalledPackage { + public class InstalledPackage + { + + private int _saveHitCount = 0; public static InstalledPackage GetById(int id) { InstalledPackage pack = new InstalledPackage(); @@ -27,7 +28,12 @@ namespace umbraco.cms.businesslogic.packager { return pack; } - public void Save() { + public void Save() + { +#if DEBUG + _saveHitCount++; + LogHelper.Info("The InstalledPackage class save method has been hit " + _saveHitCount + " times."); +#endif this.FireBeforeSave(EventArgs.Empty); data.Save(this.Data, IOHelper.MapPath(Settings.InstalledPackagesSettings)); this.FireAfterSave(EventArgs.Empty); diff --git a/src/umbraco.cms/umbraco.cms.csproj b/src/umbraco.cms/umbraco.cms.csproj index a8cb396ac6..29e453ebac 100644 --- a/src/umbraco.cms/umbraco.cms.csproj +++ b/src/umbraco.cms/umbraco.cms.csproj @@ -158,6 +158,7 @@ {511F6D8D-7717-440A-9A57-A507E9A8B27F} {FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + False ..\packages\Tidy.Net.1.0.0\lib\TidyNet.dll diff --git a/src/umbraco.webservices/media/mediaService.cs b/src/umbraco.webservices/media/mediaService.cs index b0f3e96d1a..47058cb04e 100644 --- a/src/umbraco.webservices/media/mediaService.cs +++ b/src/umbraco.webservices/media/mediaService.cs @@ -137,6 +137,7 @@ namespace umbraco.webservices.media Media m = new Media(id); + //TODO Fix this as the Id of the umbracoFile-property is no longer used var path = _fs.GetRelativePath(m.getProperty(Constants.Conventions.Media.File).Id, filename); var stream = new MemoryStream();