diff --git a/src/Umbraco.Core/Configuration/GlobalSettings.cs b/src/Umbraco.Core/Configuration/GlobalSettings.cs index 06083bee3f..0ca0189527 100644 --- a/src/Umbraco.Core/Configuration/GlobalSettings.cs +++ b/src/Umbraco.Core/Configuration/GlobalSettings.cs @@ -179,7 +179,10 @@ namespace Umbraco.Core.Configuration { throw new InvalidOperationException("Cannot create an MVC Area path without the umbracoPath specified"); } - return Path.TrimStart(SystemDirectories.Root).TrimStart('~').TrimStart('/').Replace('/', '-').Trim().ToLower(); + var path = Path; + if (path.StartsWith(SystemDirectories.Root)) // beware of TrimStart, see U4-2518 + path = path.Substring(SystemDirectories.Root.Length); + return path.TrimStart('~').TrimStart('/').Replace('/', '-').Trim().ToLower(); } } diff --git a/src/Umbraco.Core/ObjectExtensions.cs b/src/Umbraco.Core/ObjectExtensions.cs index 2b55a2276d..603c508e0f 100644 --- a/src/Umbraco.Core/ObjectExtensions.cs +++ b/src/Umbraco.Core/ObjectExtensions.cs @@ -97,8 +97,17 @@ namespace Umbraco.Core // if we've got a nullable of something, we try to convert directly to that thing. if (destinationType.IsGenericType && destinationType.GetGenericTypeDefinition() == typeof(Nullable<>)) { + var underlyingType = Nullable.GetUnderlyingType(destinationType); + + //special case for empty strings for bools/dates which should return null if an empty string + var asString = input as string; + if (asString != null && string.IsNullOrEmpty(asString) && (underlyingType == typeof(DateTime) || underlyingType == typeof(bool))) + { + return Attempt.Succeed(null); + } + // recursively call into myself with the inner (not-nullable) type and handle the outcome - var nonNullable = input.TryConvertTo(Nullable.GetUnderlyingType(destinationType)); + var nonNullable = input.TryConvertTo(underlyingType); // and if sucessful, fall on through to rewrap in a nullable; if failed, pass on the exception if (nonNullable.Success) @@ -202,78 +211,78 @@ namespace Umbraco.Core if (destinationType == typeof(string)) return Attempt.Succeed(input); - if (input == null || input.Length == 0) + if (string.IsNullOrEmpty(input)) { if (destinationType == typeof(Boolean)) return Attempt.Succeed(false); // special case for booleans, null/empty == false - else if (destinationType == typeof(DateTime)) - return Attempt.Succeed(false); + if (destinationType == typeof(DateTime)) + return Attempt.Succeed(DateTime.MinValue); } // we have a non-empty string, look for type conversions in the expected order of frequency of use... if (destinationType.IsPrimitive) { - if (destinationType == typeof(Int32)) + if (destinationType == typeof(Int32)) { Int32 value; return Int32.TryParse(input, out value) ? Attempt.Succeed(value) : Attempt.Fail(); } - else if (destinationType == typeof(Int64)) - { - Int64 value; - return Int64.TryParse(input, out value) ? Attempt.Succeed(value) : Attempt.Fail(); - } - else if (destinationType == typeof(Boolean)) - { - Boolean value; - if (Boolean.TryParse(input, out value)) - return Attempt.Succeed(value); // don't declare failure so the CustomBooleanTypeConverter can try - } - else if (destinationType == typeof(Int16)) - { - Int16 value; - return Int16.TryParse(input, out value) ? Attempt.Succeed(value) : Attempt.Fail(); - } - else if (destinationType == typeof(Double)) - { - Double value; - return Double.TryParse(input, out value) ? Attempt.Succeed(value) : Attempt.Fail(); - } - else if (destinationType == typeof(Single)) - { - Single value; - return Single.TryParse(input, out value) ? Attempt.Succeed(value) : Attempt.Fail(); - } - else if (destinationType == typeof(Char)) - { - Char value; - return Char.TryParse(input, out value) ? Attempt.Succeed(value) : Attempt.Fail(); - } - else if (destinationType == typeof(Byte)) - { - Byte value; - return Byte.TryParse(input, out value) ? Attempt.Succeed(value) : Attempt.Fail(); - } - else if (destinationType == typeof(SByte)) - { - SByte value; - return SByte.TryParse(input, out value) ? Attempt.Succeed(value) : Attempt.Fail(); - } - else if (destinationType == typeof(UInt32)) - { - UInt32 value; - return UInt32.TryParse(input, out value) ? Attempt.Succeed(value) : Attempt.Fail(); - } - else if (destinationType == typeof(UInt16)) - { - UInt16 value; - return UInt16.TryParse(input, out value) ? Attempt.Succeed(value) : Attempt.Fail(); - } - else if (destinationType == typeof(UInt64)) - { - UInt64 value; - return UInt64.TryParse(input, out value) ? Attempt.Succeed(value) : Attempt.Fail(); - } + if (destinationType == typeof(Int64)) + { + Int64 value; + return Int64.TryParse(input, out value) ? Attempt.Succeed(value) : Attempt.Fail(); + } + if (destinationType == typeof(Boolean)) + { + Boolean value; + if (Boolean.TryParse(input, out value)) + return Attempt.Succeed(value); // don't declare failure so the CustomBooleanTypeConverter can try + } + else if (destinationType == typeof(Int16)) + { + Int16 value; + return Int16.TryParse(input, out value) ? Attempt.Succeed(value) : Attempt.Fail(); + } + else if (destinationType == typeof(Double)) + { + Double value; + return Double.TryParse(input, out value) ? Attempt.Succeed(value) : Attempt.Fail(); + } + else if (destinationType == typeof(Single)) + { + Single value; + return Single.TryParse(input, out value) ? Attempt.Succeed(value) : Attempt.Fail(); + } + else if (destinationType == typeof(Char)) + { + Char value; + return Char.TryParse(input, out value) ? Attempt.Succeed(value) : Attempt.Fail(); + } + else if (destinationType == typeof(Byte)) + { + Byte value; + return Byte.TryParse(input, out value) ? Attempt.Succeed(value) : Attempt.Fail(); + } + else if (destinationType == typeof(SByte)) + { + SByte value; + return SByte.TryParse(input, out value) ? Attempt.Succeed(value) : Attempt.Fail(); + } + else if (destinationType == typeof(UInt32)) + { + UInt32 value; + return UInt32.TryParse(input, out value) ? Attempt.Succeed(value) : Attempt.Fail(); + } + else if (destinationType == typeof(UInt16)) + { + UInt16 value; + return UInt16.TryParse(input, out value) ? Attempt.Succeed(value) : Attempt.Fail(); + } + else if (destinationType == typeof(UInt64)) + { + UInt64 value; + return UInt64.TryParse(input, out value) ? Attempt.Succeed(value) : Attempt.Fail(); + } } else if (destinationType == typeof(Guid)) { diff --git a/src/Umbraco.Core/Services/PackagingService.cs b/src/Umbraco.Core/Services/PackagingService.cs index 873145166b..1671d3ae89 100644 --- a/src/Umbraco.Core/Services/PackagingService.cs +++ b/src/Umbraco.Core/Services/PackagingService.cs @@ -1,4 +1,5 @@ using System; +using System.Collections; using System.Collections.Generic; using System.Globalization; using System.Linq; @@ -32,15 +33,15 @@ namespace Umbraco.Core.Services private readonly RepositoryFactory _repositoryFactory; private readonly IDatabaseUnitOfWorkProvider _uowProvider; private Dictionary _importedContentTypes; - - - public PackagingService(IContentService contentService, - IContentTypeService contentTypeService, - IMediaService mediaService, - IDataTypeService dataTypeService, - IFileService fileService, + + + public PackagingService(IContentService contentService, + IContentTypeService contentTypeService, + IMediaService mediaService, + IDataTypeService dataTypeService, + IFileService fileService, ILocalizationService localizationService, - RepositoryFactory repositoryFactory, + RepositoryFactory repositoryFactory, IDatabaseUnitOfWorkProvider uowProvider) { _contentService = contentService; @@ -56,7 +57,7 @@ namespace Umbraco.Core.Services } #region Generic export methods - + internal void ExportToFile(string absoluteFilePath, string nodeType, int id) { XElement xml = null; @@ -91,7 +92,7 @@ namespace Umbraco.Core.Services xml = Export(dataType); } - if(xml != null) + if (xml != null) xml.Save(absoluteFilePath); } @@ -293,7 +294,7 @@ namespace Umbraco.Core.Services var properties = from property in element.Elements() where property.Attribute("isDoc") == null select property; - + IContent content = parent == null ? new Content(nodeName, parentId, contentType) { @@ -324,7 +325,7 @@ namespace Umbraco.Core.Services { propertyValueList.Add(dtos.Single(x => x.Value == preValue).Id.ToString(CultureInfo.InvariantCulture)); } - + propertyValue = string.Join(",", propertyValueList.ToArray()); } @@ -355,7 +356,7 @@ namespace Umbraco.Core.Services new XElement("AllowAtRoot", contentType.AllowedAsRoot.ToString())); var masterContentType = contentType.CompositionAliases().FirstOrDefault(); - if(masterContentType != null) + if (masterContentType != null) info.Add(new XElement("Master", masterContentType)); var allowedTemplates = new XElement("AllowedTemplates"); @@ -364,7 +365,7 @@ namespace Umbraco.Core.Services allowedTemplates.Add(new XElement("Template", template.Alias)); } info.Add(allowedTemplates); - if(contentType.DefaultTemplate != null && contentType.DefaultTemplate.Id != 0) + if (contentType.DefaultTemplate != null && contentType.DefaultTemplate.Id != 0) info.Add(new XElement("DefaultTemplate", contentType.DefaultTemplate.Alias)); else info.Add(new XElement("DefaultTemplate", "")); @@ -391,7 +392,7 @@ namespace Umbraco.Core.Services new XElement("Description", new XCData(propertyType.Description))); genericProperties.Add(genericProperty); } - + var tabs = new XElement("Tabs"); foreach (var propertyGroup in contentType.PropertyGroups) { @@ -541,7 +542,7 @@ namespace Umbraco.Core.Services var template = _fileService.GetTemplate(alias.ToSafeAlias()); if (template != null) { - if(allowedTemplates.Any(x => x.Id == template.Id)) continue; + if (allowedTemplates.Any(x => x.Id == template.Id)) continue; allowedTemplates.Add(template); } else @@ -598,40 +599,46 @@ namespace Umbraco.Core.Services 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 + + //we'll check if it is a GUID (legacy id for a property editor) + var legacyPropertyEditorId = Guid.Empty; + Guid.TryParse(property.Element("Type").Value, out legacyPropertyEditorId); + //get the alias as a string for use below + var propertyEditorAlias = property.Element("Type").Value.Trim(); + + //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) { - //we'll check if it is a GUID (legacy id for a property editor) - Guid legacyPropertyEditorId; - if (Guid.TryParse(property.Element("Type").Value, out legacyPropertyEditorId)) + var dataTypeDefinitions = legacyPropertyEditorId != Guid.Empty + ? _dataTypeService.GetDataTypeDefinitionByControlId(legacyPropertyEditorId) + : _dataTypeService.GetDataTypeDefinitionByPropertyEditorAlias(propertyEditorAlias); + if (dataTypeDefinitions != null && dataTypeDefinitions.Any()) { - if (dataTypeDefinition.ControlId != legacyPropertyEditorId) - { - var dataTypeDefinitions = _dataTypeService.GetDataTypeDefinitionByControlId(legacyPropertyEditorId); - if (dataTypeDefinitions != null && dataTypeDefinitions.Any()) - { - dataTypeDefinition = dataTypeDefinitions.First(); - } - } + dataTypeDefinition = dataTypeDefinitions.First(); } - else + } + else if (legacyPropertyEditorId != Guid.Empty && dataTypeDefinition.ControlId != legacyPropertyEditorId) + { + var dataTypeDefinitions = _dataTypeService.GetDataTypeDefinitionByControlId(legacyPropertyEditorId); + if (dataTypeDefinitions != null && dataTypeDefinitions.Any()) { - //check against the property editor string alias - var propertyEditorAlias = property.Element("Type").Value.Trim(); - if (dataTypeDefinition.PropertyEditorAlias != propertyEditorAlias) - { - var dataTypeDefinitions = _dataTypeService.GetDataTypeDefinitionByPropertyEditorAlias(propertyEditorAlias); - if (dataTypeDefinitions != null && dataTypeDefinitions.Any()) - { - dataTypeDefinition = dataTypeDefinitions.First(); - } - } + dataTypeDefinition = dataTypeDefinitions.First(); + } + } + else if (dataTypeDefinition.PropertyEditorAlias != propertyEditorAlias) + { + var dataTypeDefinitions = _dataTypeService.GetDataTypeDefinitionByPropertyEditorAlias(propertyEditorAlias); + if (dataTypeDefinitions != null && dataTypeDefinitions.Any()) + { + dataTypeDefinition = dataTypeDefinitions.First(); } } - // For backwards compatibility, if no datatype with that ID can be found, we're letting this fail silently. // This means that the property will not be created. if (dataTypeDefinition == null) @@ -790,7 +797,7 @@ namespace Umbraco.Core.Services var databaseType = databaseTypeAttribute != null ? databaseTypeAttribute.Value.EnumParse(true) : DataTypeDatabaseType.Ntext; - + //check if the Id was a GUID, that means it is referenced using the legacy property editor GUID id if (legacyPropertyEditorId != Guid.Empty) { @@ -813,7 +820,7 @@ namespace Umbraco.Core.Services }; dataTypes.Add(dataTypeDefinitionName, dataTypeDefinition); } - + } } diff --git a/src/Umbraco.Tests/Configurations/UmbracoSettings/umbracoSettings.config b/src/Umbraco.Tests/Configurations/UmbracoSettings/umbracoSettings.config index c245b29154..363d0dd50a 100644 --- a/src/Umbraco.Tests/Configurations/UmbracoSettings/umbracoSettings.config +++ b/src/Umbraco.Tests/Configurations/UmbracoSettings/umbracoSettings.config @@ -96,20 +96,6 @@ error handler is defined then you'll see the Yellow Screen Of Death (YSOD) error page. Note the error can also be handled by the umbraco.macro.Error event, where you can log/alarm with your own code and change the behaviour per event. --> inline - - - HideFileDuplicates ashx,aspx,ascx,config,cshtml,vbhtml,asmx,air,axd diff --git a/src/Umbraco.Tests/ObjectExtensionsTests.cs b/src/Umbraco.Tests/ObjectExtensionsTests.cs index f42f2445c2..b98e7607bb 100644 --- a/src/Umbraco.Tests/ObjectExtensionsTests.cs +++ b/src/Umbraco.Tests/ObjectExtensionsTests.cs @@ -114,6 +114,23 @@ namespace Umbraco.Tests Assert.AreEqual(DateTime.Equals(dateTime.Date, result.Result.Date), testCase.Value, testCase.Key); } } + + [Test] + public virtual void CanConvertBlankStringToNullDateTime() + { + var result = "".TryConvertTo(); + Assert.IsTrue(result.Success); + Assert.IsNull(result.Result); + } + + [Test] + public virtual void CanConvertBlankStringToNullBool() + { + var result = "".TryConvertTo(); + Assert.IsTrue(result.Success); + Assert.IsNull(result.Result); + } + [Test] public virtual void CanConvertBlankStringToDateTime() { diff --git a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj index 5291f937a8..09ba05f489 100644 --- a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj +++ b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj @@ -183,7 +183,9 @@ - + + True + ..\packages\Microsoft.Net.Http.2.2.15\lib\net45\System.Net.Http.Extensions.dll @@ -193,7 +195,9 @@ ..\packages\Microsoft.Net.Http.2.2.15\lib\net45\System.Net.Http.Primitives.dll - + + True + diff --git a/src/Umbraco.Web/PublishedQueryContext.cs b/src/Umbraco.Web/PublishedContentQuery.cs similarity index 99% rename from src/Umbraco.Web/PublishedQueryContext.cs rename to src/Umbraco.Web/PublishedContentQuery.cs index 6b69faad6b..f759d42e16 100644 --- a/src/Umbraco.Web/PublishedQueryContext.cs +++ b/src/Umbraco.Web/PublishedContentQuery.cs @@ -13,12 +13,12 @@ namespace Umbraco.Web /// /// A class used to query for published content, media items /// - public class PublishedQueryContext + public class PublishedContentQuery { private readonly ContextualPublishedContentCache _contentCache; private readonly ContextualPublishedMediaCache _mediaCache; - public PublishedQueryContext(ContextualPublishedContentCache contentCache, ContextualPublishedMediaCache mediaCache) + public PublishedContentQuery(ContextualPublishedContentCache contentCache, ContextualPublishedMediaCache mediaCache) { _contentCache = contentCache; _mediaCache = mediaCache; diff --git a/src/Umbraco.Web/TagQueryContext.cs b/src/Umbraco.Web/TagQuery.cs similarity index 97% rename from src/Umbraco.Web/TagQueryContext.cs rename to src/Umbraco.Web/TagQuery.cs index fac291a77b..8d4a857464 100644 --- a/src/Umbraco.Web/TagQueryContext.cs +++ b/src/Umbraco.Web/TagQuery.cs @@ -9,11 +9,11 @@ namespace Umbraco.Web /// /// A class that exposes methods used to query tag data in views /// - public class TagQueryContext + public class TagQuery { private readonly ITagService _tagService; - public TagQueryContext(ITagService tagService) + public TagQuery(ITagService tagService) { if (tagService == null) throw new ArgumentNullException("tagService"); _tagService = tagService; diff --git a/src/Umbraco.Web/UI/LegacyDialogTask.cs b/src/Umbraco.Web/UI/LegacyDialogTask.cs index 824d753ebe..537141e30a 100644 --- a/src/Umbraco.Web/UI/LegacyDialogTask.cs +++ b/src/Umbraco.Web/UI/LegacyDialogTask.cs @@ -22,6 +22,7 @@ namespace Umbraco.Web.UI /// specific app, they'd still be able to execute code to create/delete for any ITask regardless of what app /// they have access to. /// + [Obsolete("ITask is used for legacy webforms back office editors, change to using the v7 angular approach")] public abstract class LegacyDialogTask : ITaskReturnUrl, IAssignedApp { public virtual int ParentID { get; set; } diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index 0539fc5f61..f9d62c1aa7 100644 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -401,9 +401,9 @@ - + - + diff --git a/src/Umbraco.Web/UmbracoHelper.cs b/src/Umbraco.Web/UmbracoHelper.cs index a9ccba55f4..0275ba2ce5 100644 --- a/src/Umbraco.Web/UmbracoHelper.cs +++ b/src/Umbraco.Web/UmbracoHelper.cs @@ -32,23 +32,23 @@ namespace Umbraco.Web { private readonly UmbracoContext _umbracoContext; private readonly IPublishedContent _currentPage; - private PublishedQueryContext _queryContext; - private TagQueryContext _tagContext; + private PublishedContentQuery _query; + private TagQuery _tag; /// /// Lazy instantiates the tag context /// - public TagQueryContext Tags + public TagQuery TagQuery { - get { return _tagContext ?? (_tagContext = new TagQueryContext(UmbracoContext.Application.Services.TagService)); } + get { return _tag ?? (_tag = new TagQuery(UmbracoContext.Application.Services.TagService)); } } /// /// Lazy instantiates the query context /// - public PublishedQueryContext QueryContext + public PublishedContentQuery ContentQuery { - get { return _queryContext ?? (_queryContext = new PublishedQueryContext(UmbracoContext.ContentCache, UmbracoContext.MediaCache)); } + get { return _query ?? (_query = new PublishedContentQuery(UmbracoContext.ContentCache, UmbracoContext.MediaCache)); } } /// @@ -73,13 +73,13 @@ namespace Umbraco.Web { } - public UmbracoHelper(UmbracoContext umbracoContext, IPublishedContent content, PublishedQueryContext queryContext) + public UmbracoHelper(UmbracoContext umbracoContext, IPublishedContent content, PublishedContentQuery query) : this(umbracoContext) { if (content == null) throw new ArgumentNullException("content"); - if (queryContext == null) throw new ArgumentNullException("queryContext"); + if (query == null) throw new ArgumentNullException("query"); _currentPage = content; - _queryContext = queryContext; + _query = query; } /// @@ -109,11 +109,11 @@ namespace Umbraco.Web } } - public UmbracoHelper(UmbracoContext umbracoContext, PublishedQueryContext queryContext) + public UmbracoHelper(UmbracoContext umbracoContext, PublishedContentQuery query) : this(umbracoContext) { - if (queryContext == null) throw new ArgumentNullException("queryContext"); - _queryContext = queryContext; + if (query == null) throw new ArgumentNullException("query"); + _query = query; } /// @@ -576,140 +576,140 @@ namespace Umbraco.Web public IPublishedContent TypedContent(object id) { int intId; - return ConvertIdObjectToInt(id, out intId) ? QueryContext.TypedContent(intId) : null; + return ConvertIdObjectToInt(id, out intId) ? ContentQuery.TypedContent(intId) : null; } public IPublishedContent TypedContent(int id) { - return QueryContext.TypedContent(id); + return ContentQuery.TypedContent(id); } public IPublishedContent TypedContent(string id) { int intId; - return ConvertIdObjectToInt(id, out intId) ? QueryContext.TypedContent(intId) : null; + return ConvertIdObjectToInt(id, out intId) ? ContentQuery.TypedContent(intId) : null; } public IPublishedContent TypedContentSingleAtXPath(string xpath, params XPathVariable[] vars) { - return QueryContext.TypedContentSingleAtXPath(xpath, vars); + return ContentQuery.TypedContentSingleAtXPath(xpath, vars); } public IEnumerable TypedContent(params object[] ids) { - return QueryContext.TypedContent(ConvertIdsObjectToInts(ids)); + return ContentQuery.TypedContent(ConvertIdsObjectToInts(ids)); } public IEnumerable TypedContent(params int[] ids) { - return QueryContext.TypedContent(ids); + return ContentQuery.TypedContent(ids); } public IEnumerable TypedContent(params string[] ids) { - return QueryContext.TypedContent(ConvertIdsObjectToInts(ids)); + return ContentQuery.TypedContent(ConvertIdsObjectToInts(ids)); } public IEnumerable TypedContent(IEnumerable ids) { - return QueryContext.TypedContent(ConvertIdsObjectToInts(ids)); + return ContentQuery.TypedContent(ConvertIdsObjectToInts(ids)); } public IEnumerable TypedContent(IEnumerable ids) { - return QueryContext.TypedContent(ConvertIdsObjectToInts(ids)); + return ContentQuery.TypedContent(ConvertIdsObjectToInts(ids)); } public IEnumerable TypedContent(IEnumerable ids) { - return QueryContext.TypedContent(ids); + return ContentQuery.TypedContent(ids); } public IEnumerable TypedContentAtXPath(string xpath, params XPathVariable[] vars) { - return QueryContext.TypedContentAtXPath(xpath, vars); + return ContentQuery.TypedContentAtXPath(xpath, vars); } public IEnumerable TypedContentAtXPath(XPathExpression xpath, params XPathVariable[] vars) { - return QueryContext.TypedContentAtXPath(xpath, vars); + return ContentQuery.TypedContentAtXPath(xpath, vars); } public IEnumerable TypedContentAtRoot() { - return QueryContext.TypedContentAtRoot(); + return ContentQuery.TypedContentAtRoot(); } public dynamic Content(object id) { int intId; - return ConvertIdObjectToInt(id, out intId) ? QueryContext.Content(intId) : DynamicNull.Null; + return ConvertIdObjectToInt(id, out intId) ? ContentQuery.Content(intId) : DynamicNull.Null; } public dynamic Content(int id) { - return QueryContext.Content(id); + return ContentQuery.Content(id); } public dynamic Content(string id) { int intId; - return ConvertIdObjectToInt(id, out intId) ? QueryContext.Content(intId) : DynamicNull.Null; + return ConvertIdObjectToInt(id, out intId) ? ContentQuery.Content(intId) : DynamicNull.Null; } public dynamic ContentSingleAtXPath(string xpath, params XPathVariable[] vars) { - return QueryContext.ContentSingleAtXPath(xpath, vars); + return ContentQuery.ContentSingleAtXPath(xpath, vars); } public dynamic ContentSingleAtXPath(XPathExpression xpath, params XPathVariable[] vars) { - return QueryContext.ContentSingleAtXPath(xpath, vars); + return ContentQuery.ContentSingleAtXPath(xpath, vars); } public dynamic Content(params object[] ids) { - return QueryContext.Content(ConvertIdsObjectToInts(ids)); + return ContentQuery.Content(ConvertIdsObjectToInts(ids)); } public dynamic Content(params int[] ids) { - return QueryContext.Content(ids); + return ContentQuery.Content(ids); } public dynamic Content(params string[] ids) { - return QueryContext.Content(ConvertIdsObjectToInts(ids)); + return ContentQuery.Content(ConvertIdsObjectToInts(ids)); } public dynamic Content(IEnumerable ids) { - return QueryContext.Content(ConvertIdsObjectToInts(ids)); + return ContentQuery.Content(ConvertIdsObjectToInts(ids)); } public dynamic Content(IEnumerable ids) { - return QueryContext.Content(ids); + return ContentQuery.Content(ids); } public dynamic Content(IEnumerable ids) { - return QueryContext.Content(ConvertIdsObjectToInts(ids)); + return ContentQuery.Content(ConvertIdsObjectToInts(ids)); } public dynamic ContentAtXPath(string xpath, params XPathVariable[] vars) { - return QueryContext.ContentAtXPath(xpath, vars); + return ContentQuery.ContentAtXPath(xpath, vars); } public dynamic ContentAtXPath(XPathExpression xpath, params XPathVariable[] vars) { - return QueryContext.ContentAtXPath(xpath, vars); + return ContentQuery.ContentAtXPath(xpath, vars); } public dynamic ContentAtRoot() { - return QueryContext.ContentAtRoot(); + return ContentQuery.ContentAtRoot(); } private bool ConvertIdObjectToInt(object id, out int intId) @@ -760,105 +760,105 @@ namespace Umbraco.Web public IPublishedContent TypedMedia(object id) { int intId; - return ConvertIdObjectToInt(id, out intId) ? QueryContext.TypedMedia(intId) : null; + return ConvertIdObjectToInt(id, out intId) ? ContentQuery.TypedMedia(intId) : null; } public IPublishedContent TypedMedia(int id) { - return QueryContext.TypedMedia(id); + return ContentQuery.TypedMedia(id); } public IPublishedContent TypedMedia(string id) { int intId; - return ConvertIdObjectToInt(id, out intId) ? QueryContext.TypedMedia(intId) : null; + return ConvertIdObjectToInt(id, out intId) ? ContentQuery.TypedMedia(intId) : null; } public IEnumerable TypedMedia(params object[] ids) { - return QueryContext.TypedMedia(ConvertIdsObjectToInts(ids)); + return ContentQuery.TypedMedia(ConvertIdsObjectToInts(ids)); } public IEnumerable TypedMedia(params int[] ids) { - return QueryContext.TypedMedia(ids); + return ContentQuery.TypedMedia(ids); } public IEnumerable TypedMedia(params string[] ids) { - return QueryContext.TypedMedia(ConvertIdsObjectToInts(ids)); + return ContentQuery.TypedMedia(ConvertIdsObjectToInts(ids)); } public IEnumerable TypedMedia(IEnumerable ids) { - return QueryContext.TypedMedia(ConvertIdsObjectToInts(ids)); + return ContentQuery.TypedMedia(ConvertIdsObjectToInts(ids)); } public IEnumerable TypedMedia(IEnumerable ids) { - return QueryContext.TypedMedia(ids); + return ContentQuery.TypedMedia(ids); } public IEnumerable TypedMedia(IEnumerable ids) { - return QueryContext.TypedMedia(ConvertIdsObjectToInts(ids)); + return ContentQuery.TypedMedia(ConvertIdsObjectToInts(ids)); } public IEnumerable TypedMediaAtRoot() { - return QueryContext.TypedMediaAtRoot(); + return ContentQuery.TypedMediaAtRoot(); } public dynamic Media(object id) { int intId; - return ConvertIdObjectToInt(id, out intId) ? QueryContext.Media(intId) : DynamicNull.Null; + return ConvertIdObjectToInt(id, out intId) ? ContentQuery.Media(intId) : DynamicNull.Null; } public dynamic Media(int id) { - return QueryContext.Media(id); + return ContentQuery.Media(id); } public dynamic Media(string id) { int intId; - return ConvertIdObjectToInt(id, out intId) ? QueryContext.Media(intId) : DynamicNull.Null; + return ConvertIdObjectToInt(id, out intId) ? ContentQuery.Media(intId) : DynamicNull.Null; } public dynamic Media(params object[] ids) { - return QueryContext.Media(ConvertIdsObjectToInts(ids)); + return ContentQuery.Media(ConvertIdsObjectToInts(ids)); } public dynamic Media(params int[] ids) { - return QueryContext.Media(ids); + return ContentQuery.Media(ids); } public dynamic Media(params string[] ids) { - return QueryContext.Media(ConvertIdsObjectToInts(ids)); + return ContentQuery.Media(ConvertIdsObjectToInts(ids)); } public dynamic Media(IEnumerable ids) { - return QueryContext.Media(ConvertIdsObjectToInts(ids)); + return ContentQuery.Media(ConvertIdsObjectToInts(ids)); } public dynamic Media(IEnumerable ids) { - return QueryContext.Media(ids); + return ContentQuery.Media(ids); } public dynamic Media(IEnumerable ids) { - return QueryContext.Media(ConvertIdsObjectToInts(ids)); + return ContentQuery.Media(ConvertIdsObjectToInts(ids)); } public dynamic MediaAtRoot() { - return QueryContext.MediaAtRoot(); + return ContentQuery.MediaAtRoot(); } #endregion @@ -874,7 +874,7 @@ namespace Umbraco.Web /// public dynamic Search(string term, bool useWildCards = true, string searchProvider = null) { - return QueryContext.Search(term, useWildCards, searchProvider); + return ContentQuery.Search(term, useWildCards, searchProvider); } /// @@ -885,7 +885,7 @@ namespace Umbraco.Web /// public dynamic Search(Examine.SearchCriteria.ISearchCriteria criteria, Examine.Providers.BaseSearchProvider searchProvider = null) { - return QueryContext.Search(criteria, searchProvider); + return ContentQuery.Search(criteria, searchProvider); } /// @@ -897,7 +897,7 @@ namespace Umbraco.Web /// public IEnumerable TypedSearch(string term, bool useWildCards = true, string searchProvider = null) { - return QueryContext.Search(term, useWildCards, searchProvider); + return ContentQuery.Search(term, useWildCards, searchProvider); } /// @@ -908,7 +908,7 @@ namespace Umbraco.Web /// public IEnumerable TypedSearch(Examine.SearchCriteria.ISearchCriteria criteria, Examine.Providers.BaseSearchProvider searchProvider = null) { - return QueryContext.Search(criteria, searchProvider); + return ContentQuery.Search(criteria, searchProvider); } #endregion diff --git a/src/Umbraco.Web/WebServices/TagsController.cs b/src/Umbraco.Web/WebServices/TagsController.cs index b9a4cca105..6d22a54f17 100644 --- a/src/Umbraco.Web/WebServices/TagsController.cs +++ b/src/Umbraco.Web/WebServices/TagsController.cs @@ -23,7 +23,7 @@ namespace Umbraco.Web.WebServices /// public IEnumerable GetAllTags(string group = null) { - return Umbraco.Tags.GetAllTags(group); + return Umbraco.TagQuery.GetAllTags(group); } /// @@ -33,7 +33,7 @@ namespace Umbraco.Web.WebServices /// public IEnumerable GetAllContentTags(string group = null) { - return Umbraco.Tags.GetAllContentTags(group); + return Umbraco.TagQuery.GetAllContentTags(group); } /// @@ -43,7 +43,7 @@ namespace Umbraco.Web.WebServices /// public IEnumerable GetAllMediaTags(string group = null) { - return Umbraco.Tags.GetAllMediaTags(group); + return Umbraco.TagQuery.GetAllMediaTags(group); } /// @@ -53,7 +53,7 @@ namespace Umbraco.Web.WebServices /// public IEnumerable GetAllMemberTags(string group = null) { - return Umbraco.Tags.GetAllMemberTags(group); + return Umbraco.TagQuery.GetAllMemberTags(group); } /// @@ -65,7 +65,7 @@ namespace Umbraco.Web.WebServices /// public IEnumerable GetTagsForProperty(int contentId, string propertyTypeAlias, string tagGroup = null) { - return Umbraco.Tags.GetTagsForProperty(contentId, propertyTypeAlias, tagGroup); + return Umbraco.TagQuery.GetTagsForProperty(contentId, propertyTypeAlias, tagGroup); } /// @@ -76,7 +76,7 @@ namespace Umbraco.Web.WebServices /// public IEnumerable GetTagsForEntity(int contentId, string tagGroup = null) { - return Umbraco.Tags.GetTagsForEntity(contentId, tagGroup); + return Umbraco.TagQuery.GetTagsForEntity(contentId, tagGroup); } } diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/create/PartialViewMacrosTasks.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/create/PartialViewMacrosTasks.cs index f939ba51a9..216bcd15e9 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/create/PartialViewMacrosTasks.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/create/PartialViewMacrosTasks.cs @@ -4,8 +4,10 @@ using Umbraco.Core.CodeAnnotations; using Umbraco.Core.IO; using Umbraco.Core.Logging; using Umbraco.Web.Mvc; +using Umbraco.Web.UI; using umbraco.BasePages; using Umbraco.Core; +using umbraco.BusinessLogic; namespace umbraco { @@ -13,13 +15,10 @@ namespace umbraco /// The UI 'tasks' for the create dialog and delete processes /// [UmbracoWillObsolete("http://issues.umbraco.org/issue/U4-1373", "This will one day be removed when we overhaul the create process")] - public class PartialViewMacroTasks : interfaces.ITaskReturnUrl + public class PartialViewMacroTasks : LegacyDialogTask { - private string _alias; - private int _parentId; - private int _typeId; - private int _userId; - + private string _returnUrl = ""; + protected virtual string EditViewFile { get { return "Settings/Views/EditView.aspx"; } @@ -35,34 +34,11 @@ namespace umbraco get { return "MacroPartials"; } } - public int UserId + public override bool PerformSave() { - set { _userId = value; } - } - public int TypeID - { - set { _typeId = value; } - get { return _typeId; } - } - - - public string Alias - { - set { _alias = value; } - get { return _alias; } - } - - public int ParentID - { - set { _parentId = value; } - get { return _parentId; } - } - - public bool Save() - { - var pipesIndex = _alias.IndexOf("|||", System.StringComparison.Ordinal); - var template = _alias.Substring(0, pipesIndex).Trim(); - var fileName = _alias.Substring(pipesIndex + 3, _alias.Length - pipesIndex - 3) + ".cshtml"; + var pipesIndex = Alias.IndexOf("|||", System.StringComparison.Ordinal); + var template = Alias.Substring(0, pipesIndex).Trim(); + var fileName = Alias.Substring(pipesIndex + 3, Alias.Length - pipesIndex - 3) + ".cshtml"; var fullFilePath = IOHelper.MapPath(BasePath + fileName); @@ -97,27 +73,29 @@ namespace umbraco return true; } - public bool Delete() + public override string ReturnUrl { - var path = IOHelper.MapPath(BasePath + _alias.TrimStart('/')); + get { return _returnUrl; } + } + + public override string AssignedApp + { + get { return DefaultApps.developer.ToString(); } + } + + public override bool PerformDelete() + { + var path = IOHelper.MapPath(BasePath + Alias.TrimStart('/')); if (File.Exists(path)) File.Delete(path); else if (Directory.Exists(path)) Directory.Delete(path, true); - LogHelper.Info(string.Format("{0} Deleted by user {1}", _alias, UmbracoEnsuredPage.CurrentUser.Id)); + LogHelper.Info(string.Format("{0} Deleted by user {1}", Alias, User.Id)); return true; } - #region ITaskReturnUrl Members - private string _returnUrl = ""; - public string ReturnUrl - { - get { return _returnUrl; } - } - - #endregion } } \ No newline at end of file diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/create/PartialViewTasks.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/create/PartialViewTasks.cs index 37983a5343..87e5abd1e8 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/create/PartialViewTasks.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/create/PartialViewTasks.cs @@ -107,4 +107,4 @@ namespace umbraco } } -} +} diff --git a/src/umbraco.cms/businesslogic/Packager/Installer.cs b/src/umbraco.cms/businesslogic/Packager/Installer.cs index 43729b0f25..49247e49ce 100644 --- a/src/umbraco.cms/businesslogic/Packager/Installer.cs +++ b/src/umbraco.cms/businesslogic/Packager/Installer.cs @@ -1,812 +1,807 @@ -using System; -using System.Collections.Generic; -using System.Globalization; -using System.IO; -using System.Xml; -using System.Linq; -using ICSharpCode.SharpZipLib.Zip; -using Umbraco.Core; -using Umbraco.Core.IO; -using Umbraco.Core.Logging; -using Umbraco.Core.Packaging; -using umbraco.cms.businesslogic.web; -using umbraco.cms.businesslogic.propertytype; -using umbraco.BusinessLogic; -using System.Diagnostics; -using umbraco.cms.businesslogic.macro; -using umbraco.cms.businesslogic.template; -using umbraco.interfaces; - -namespace umbraco.cms.businesslogic.packager -{ - /// - /// The packager is a component which enables sharing of both data and functionality components between different umbraco installations. - /// - /// The output is a .umb (a zip compressed file) which contains the exported documents/medias/macroes/documenttypes (etc.) - /// in a Xml document, along with the physical files used (images/usercontrols/xsl documents etc.) - /// - /// Partly implemented, import of packages is done, the export is *under construction*. - /// - /// - /// Ruben Verborgh 31/12/2007: I had to change some code, I marked my changes with "DATALAYER". - /// Reason: @@IDENTITY can't be used with the new datalayer. - /// I wasn't able to test the code, since I'm not aware how the code functions. - /// - public class Installer - { - private const string PackageServer = "packages.umbraco.org"; - - private readonly List _unsecureFiles = new List(); - private readonly Dictionary _conflictingMacroAliases = new Dictionary(); - private readonly Dictionary _conflictingTemplateAliases = new Dictionary(); - private readonly Dictionary _conflictingStyleSheetNames = new Dictionary(); - - private readonly List _binaryFileErrors = new List(); - - public string Name { get; private set; } - public string Version { get; private set; } - public string Url { get; private set; } - public string License { get; private set; } - public string LicenseUrl { get; private set; } - public string Author { get; private set; } - public string AuthorUrl { get; private set; } - public string ReadMe { get; private set; } - public string Control { get; private set; } - - public bool ContainsMacroConflict { get; private set; } - public IDictionary ConflictingMacroAliases { get { return _conflictingMacroAliases; } } - - public bool ContainsUnsecureFiles { get; private set; } - public List UnsecureFiles { get { return _unsecureFiles; } } - - public bool ContainsTemplateConflicts { get; private set; } - public IDictionary ConflictingTemplateAliases { get { return _conflictingTemplateAliases; } } - - /// - /// Indicates that the package contains assembly reference errors - /// - public bool ContainsBinaryFileErrors { get; private set; } - - /// - /// List each assembly reference error - /// - public List BinaryFileErrors { get { return _binaryFileErrors; } } - - /// - /// Indicates that the package contains legacy property editors - /// - public bool ContainsLegacyPropertyEditors { get; private set; } - - public bool ContainsStyleSheeConflicts { get; private set; } - public IDictionary ConflictingStyleSheetNames { get { return _conflictingStyleSheetNames; } } - - public int RequirementsMajor { get; private set; } - public int RequirementsMinor { get; private set; } - public int RequirementsPatch { get; private set; } - - /// - /// The xmldocument, describing the contents of a package. - /// - public XmlDocument Config { get; private set; } - - /// - /// Constructor - /// - public Installer() - { - ContainsBinaryFileErrors = false; - ContainsTemplateConflicts = false; - ContainsUnsecureFiles = false; - ContainsMacroConflict = false; - ContainsStyleSheeConflicts = false; - } - - /// - /// Constructor - /// - /// The name of the package - /// The version of the package - /// The url to a descriptionpage - /// The license under which the package is released (preferably GPL ;)) - /// The url to a licensedescription - /// The original author of the package - /// The url to the Authors website - /// Umbraco version major - /// Umbraco version minor - /// Umbraco version patch - /// The readme text - /// The name of the usercontrol used to configure the package after install - public Installer(string Name, string Version, string Url, string License, string LicenseUrl, string Author, string AuthorUrl, int RequirementsMajor, int RequirementsMinor, int RequirementsPatch, string Readme, string Control) - { - ContainsBinaryFileErrors = false; - ContainsTemplateConflicts = false; - ContainsUnsecureFiles = false; - ContainsMacroConflict = false; - ContainsStyleSheeConflicts = false; - this.Name = Name; - this.Version = Version; - this.Url = Url; - this.License = License; - this.LicenseUrl = LicenseUrl; - this.RequirementsMajor = RequirementsMajor; - this.RequirementsMinor = RequirementsMinor; - this.RequirementsPatch = RequirementsPatch; - this.Author = Author; - this.AuthorUrl = AuthorUrl; - ReadMe = Readme; - this.Control = Control; - } - - #region Public Methods - - /// - /// Imports the specified package - /// - /// Filename of the umbracopackage - /// - public string Import(string InputFile) - { - using (DisposableTimer.DebugDuration( - () => "Importing package file " + InputFile, - () => "Package file " + InputFile + "imported")) - { - var tempDir = ""; - if (File.Exists(IOHelper.MapPath(SystemDirectories.Data + Path.DirectorySeparatorChar + InputFile))) - { - var fi = new FileInfo(IOHelper.MapPath(SystemDirectories.Data + Path.DirectorySeparatorChar + InputFile)); - // Check if the file is a valid package - if (fi.Extension.ToLower() == ".umb") - { - try - { - tempDir = UnPack(fi.FullName); - LoadConfig(tempDir); - } - catch (Exception unpackE) - { - throw new Exception("Error unpacking extension...", unpackE); - } - } - else - throw new Exception("Error - file isn't a package (doesn't have a .umb extension). Check if the file automatically got named '.zip' upon download."); - } - else - throw new Exception("Error - file not found. Could find file named '" + IOHelper.MapPath(SystemDirectories.Data + Path.DirectorySeparatorChar + InputFile) + "'"); - 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 - var packName = XmlHelper.GetNodeValue(Config.DocumentElement.SelectSingleNode("/umbPackage/info/package/name")); - var packAuthor = XmlHelper.GetNodeValue(Config.DocumentElement.SelectSingleNode("/umbPackage/info/author/name")); - var packAuthorUrl = XmlHelper.GetNodeValue(Config.DocumentElement.SelectSingleNode("/umbPackage/info/author/website")); - var packVersion = XmlHelper.GetNodeValue(Config.DocumentElement.SelectSingleNode("/umbPackage/info/package/version")); - var packReadme = XmlHelper.GetNodeValue(Config.DocumentElement.SelectSingleNode("/umbPackage/info/readme")); - var packLicense = XmlHelper.GetNodeValue(Config.DocumentElement.SelectSingleNode("/umbPackage/info/package/license ")); - var packUrl = XmlHelper.GetNodeValue(Config.DocumentElement.SelectSingleNode("/umbPackage/info/package/url ")); - - var enableSkins = false; - var skinRepoGuid = ""; - - if (Config.DocumentElement.SelectSingleNode("/umbPackage/enableSkins") != null) - { - var skinNode = Config.DocumentElement.SelectSingleNode("/umbPackage/enableSkins"); - enableSkins = bool.Parse(XmlHelper.GetNodeValue(skinNode)); - if (skinNode.Attributes["repository"] != null && string.IsNullOrEmpty(skinNode.Attributes["repository"].Value) == false) - skinRepoGuid = skinNode.Attributes["repository"].Value; - } - - //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 - 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.Url = packUrl; - - //skinning - insPack.Data.EnableSkins = enableSkins; - insPack.Data.SkinRepoGuid = string.IsNullOrEmpty(skinRepoGuid) ? Guid.Empty : new Guid(skinRepoGuid); - - 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. - insPack.Save(); - - return insPack.Data.Id; - } - - public void InstallFiles(int packageId, string tempDir) - { - using (DisposableTimer.DebugDuration( - () => "Installing package files for package id " + packageId + " into temp folder " + tempDir, - () => "Package file installation complete for package id " + packageId)) - { - //retrieve the manifest to continue installation - var insPack = InstalledPackage.GetById(packageId); - - // Move files - //string virtualBasePath = System.Web.HttpContext.Current.Request.ApplicationPath; - string basePath = System.Web.Hosting.HostingEnvironment.ApplicationPhysicalPath; - - foreach (XmlNode n in Config.DocumentElement.SelectNodes("//file")) - { - //we enclose the whole file-moving to ensure that the entire installer doesn't crash - try - { - var destPath = GetFileName(basePath, XmlHelper.GetNodeValue(n.SelectSingleNode("orgPath"))); - var sourceFile = GetFileName(tempDir, XmlHelper.GetNodeValue(n.SelectSingleNode("guid"))); - var destFile = GetFileName(destPath, XmlHelper.GetNodeValue(n.SelectSingleNode("orgName"))); - - // Create the destination directory if it doesn't exist - if (Directory.Exists(destPath) == false) - Directory.CreateDirectory(destPath); - //If a file with this name exists, delete it - else if (File.Exists(destFile)) - File.Delete(destFile); - - // Move the file - File.Move(sourceFile, destFile); - - //PPH log file install - insPack.Data.Files.Add(XmlHelper.GetNodeValue(n.SelectSingleNode("orgPath")) + "/" + XmlHelper.GetNodeValue(n.SelectSingleNode("orgName"))); - } - catch (Exception ex) - { - LogHelper.Error("Package install error", ex); - } - } - - 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 - var insPack = InstalledPackage.GetById(packageId); - //bool saveNeeded = false; - - // 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 = Config.DocumentElement.GetXElement(); - var packagingService = ApplicationContext.Current.Services.PackagingService; - - //Perhaps it would have been a good idea to put the following into methods eh?!? - - #region DataTypes - var dataTypeElement = rootElement.Descendants("DataTypes").FirstOrDefault(); - if(dataTypeElement != null) - { - 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); - - if (newDtd != null) - { - insPack.Data.DataTypes.Add(newDtd.Id.ToString()); - saveNeeded = true; - } - }*/ - - //if (saveNeeded) { insPack.Save(); saveNeeded = false; } - #endregion - - #region Languages - foreach (XmlNode n in Config.DocumentElement.SelectNodes("//Language")) - { - language.Language newLang = language.Language.Import(n); - - if (newLang != null) - { - insPack.Data.Languages.Add(newLang.id.ToString(CultureInfo.InvariantCulture)); - //saveNeeded = true; - } - } - - //if (saveNeeded) { insPack.Save(); saveNeeded = false; } - #endregion - - #region Dictionary items - foreach (XmlNode n in Config.DocumentElement.SelectNodes("./DictionaryItems/DictionaryItem")) - { - Dictionary.DictionaryItem newDi = Dictionary.DictionaryItem.Import(n); - - if (newDi != null) - { - insPack.Data.DictionaryItems.Add(newDi.id.ToString()); - //saveNeeded = true; - } - } - - //if (saveNeeded) { insPack.Save(); saveNeeded = false; } - #endregion - - #region Macros - foreach (XmlNode n in Config.DocumentElement.SelectNodes("//macro")) - { - Macro m = Macro.Import(n); - - if (m != null) - { - insPack.Data.Macros.Add(m.Id.ToString(CultureInfo.InvariantCulture)); - //saveNeeded = true; - } - } - - //if (saveNeeded) { insPack.Save(); saveNeeded = false; } - #endregion - - #region Templates - var templateElement = rootElement.Descendants("Templates").FirstOrDefault(); - if (templateElement != null) - { - var templates = packagingService.ImportTemplates(templateElement, currentUser.Id); - foreach (var template in templates) - { - insPack.Data.Templates.Add(template.Id.ToString(CultureInfo.InvariantCulture)); - //saveNeeded = true; - } - } - - //if (saveNeeded) { insPack.Save(); saveNeeded = false; } - - /*foreach (XmlNode n in _packageConfig.DocumentElement.SelectNodes("Templates/Template")) - { - var t = Template.Import(n, currentUser); - - insPack.Data.Templates.Add(t.Id.ToString()); - - saveNeeded = true; - } - - if (saveNeeded) { insPack.Save(); saveNeeded = false; } - - - //NOTE: SD: I'm pretty sure the only thing the below script does is ensure that the Master template Id is set - // in the database, but this is also duplicating the saving of the design content since the above Template.Import - // already does this. I've left this for now because I'm not sure the reprocussions of removing it but seems there - // is a lot of excess database calls happening here. - foreach (XmlNode n in _packageConfig.DocumentElement.SelectNodes("Templates/Template")) - { - string master = XmlHelper.GetNodeValue(n.SelectSingleNode("Master")); - Template t = Template.GetByAlias(XmlHelper.GetNodeValue(n.SelectSingleNode("Alias"))); - if (master.Trim() != "") - { - var masterTemplate = Template.GetByAlias(master); - if (masterTemplate != null) - { - 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 - // MVC which means that the package will not work anymore. - // The code below that imports the templates should suffice because it's actually importing - // template data not just blank data. - - //if (UmbracoConfiguration.Current.UmbracoSettings.Templates.UseAspNetMasterPages) - // t.SaveMasterPageFile(t.Design); - } - } - // Master templates can only be generated when their master is known - if (UmbracoConfiguration.Current.UmbracoSettings.Templates.UseAspNetMasterPages) - { - t.ImportDesign(XmlHelper.GetNodeValue(n.SelectSingleNode("Design"))); - t.SaveMasterPageFile(t.Design); - } - }*/ - #endregion - - #region DocumentTypes - //Check whether the root element is a doc type rather then a complete package - var docTypeElement = rootElement.Name.LocalName.Equals("DocumentType") || - rootElement.Name.LocalName.Equals("DocumentTypes") - ? rootElement - : rootElement.Descendants("DocumentTypes").FirstOrDefault(); - - if (docTypeElement != null) - { - var contentTypes = packagingService.ImportContentTypes(docTypeElement, currentUser.Id); - foreach (var contentType in contentTypes) - { - insPack.Data.Documenttypes.Add(contentType.Id.ToString(CultureInfo.InvariantCulture)); - //saveNeeded = true; - } - } - - //if (saveNeeded) { insPack.Save(); saveNeeded = false; } - - /*foreach (XmlNode n in _packageConfig.DocumentElement.SelectNodes("DocumentTypes/DocumentType")) - { - ImportDocumentType(n, currentUser, false); - saveNeeded = true; - } - - if (saveNeeded) { insPack.Save(); saveNeeded = false; } - - - // Add documenttype structure - foreach (XmlNode n in _packageConfig.DocumentElement.SelectNodes("DocumentTypes/DocumentType")) - { - DocumentType dt = DocumentType.GetByAlias(XmlHelper.GetNodeValue(n.SelectSingleNode("Info/Alias"))); - 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; - dt.Save(); - //PPH we log the document type install here. - insPack.Data.Documenttypes.Add(dt.Id.ToString()); - saveNeeded = true; - } - } - - if (saveNeeded) { insPack.Save(); saveNeeded = false; }*/ - #endregion - - #region Stylesheets - foreach (XmlNode n in Config.DocumentElement.SelectNodes("Stylesheets/Stylesheet")) - { - StyleSheet s = StyleSheet.Import(n, currentUser); - - insPack.Data.Stylesheets.Add(s.Id.ToString()); - //saveNeeded = true; - } - - //if (saveNeeded) { insPack.Save(); saveNeeded = false; } - #endregion - - #region Documents - var documentElement = rootElement.Descendants("DocumentSet").FirstOrDefault(); - if (documentElement != null) - { - 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, currentUser, n).ToString(); - }*/ - #endregion - - #region Package Actions - foreach (XmlNode n in Config.DocumentElement.SelectNodes("Actions/Action")) - { - if (n.Attributes["undo"] == null || n.Attributes["undo"].Value == "true") - { - insPack.Data.Actions += n.OuterXml; - } - - if (n.Attributes["runat"] != null && n.Attributes["runat"].Value == "install") - { - try - { - PackageAction.RunPackageAction(insPack.Data.Name, n.Attributes["alias"].Value, n); - } - catch - { - - } - } - } - #endregion - - // Trigger update of Apps / Trees config. - // (These are ApplicationStartupHandlers so just instantiating them will trigger them) - new ApplicationRegistrar(); - new ApplicationTreeRegistrar(); - - insPack.Save(); - } - } - - /// - /// Remove the temp installation folder - /// - /// - /// - public void InstallCleanUp(int packageId, string tempDir) - { - if (Directory.Exists(tempDir)) - { - Directory.Delete(tempDir, true); - } - } - - /// - /// Reads the configuration of the package from the configuration xmldocument - /// - /// The folder to which the contents of the package is extracted - public void LoadConfig(string tempDir) - { - Config = new XmlDocument(); - Config.Load(tempDir + Path.DirectorySeparatorChar + "package.xml"); - - Name = Config.DocumentElement.SelectSingleNode("/umbPackage/info/package/name").FirstChild.Value; - Version = Config.DocumentElement.SelectSingleNode("/umbPackage/info/package/version").FirstChild.Value; - Url = Config.DocumentElement.SelectSingleNode("/umbPackage/info/package/url").FirstChild.Value; - License = Config.DocumentElement.SelectSingleNode("/umbPackage/info/package/license").FirstChild.Value; - LicenseUrl = Config.DocumentElement.SelectSingleNode("/umbPackage/info/package/license").Attributes.GetNamedItem("url").Value; - RequirementsMajor = int.Parse(Config.DocumentElement.SelectSingleNode("/umbPackage/info/package/requirements/major").FirstChild.Value); - RequirementsMinor = int.Parse(Config.DocumentElement.SelectSingleNode("/umbPackage/info/package/requirements/minor").FirstChild.Value); - RequirementsPatch = int.Parse(Config.DocumentElement.SelectSingleNode("/umbPackage/info/package/requirements/patch").FirstChild.Value); - Author = Config.DocumentElement.SelectSingleNode("/umbPackage/info/author/name").FirstChild.Value; - AuthorUrl = Config.DocumentElement.SelectSingleNode("/umbPackage/info/author/website").FirstChild.Value; - - var basePath = System.Web.Hosting.HostingEnvironment.ApplicationPhysicalPath; - var dllBinFiles = new List(); - - foreach (XmlNode n in Config.DocumentElement.SelectNodes("//file")) - { - var badFile = false; - var destPath = GetFileName(basePath, XmlHelper.GetNodeValue(n.SelectSingleNode("orgPath"))); - var orgName = XmlHelper.GetNodeValue(n.SelectSingleNode("orgName")); - var destFile = GetFileName(destPath, orgName); - - if (destPath.ToLower().Contains(IOHelper.DirSepChar + "app_code")) - { - badFile = true; - } - - if (destPath.ToLower().Contains(IOHelper.DirSepChar + "bin")) - { - badFile = true; - } - - if (destFile.ToLower().EndsWith(".dll")) - { - badFile = true; - dllBinFiles.Add(Path.Combine(tempDir, orgName)); - } - - if (badFile) - { - ContainsUnsecureFiles = true; - _unsecureFiles.Add(XmlHelper.GetNodeValue(n.SelectSingleNode("orgName"))); - } - } - - if (ContainsUnsecureFiles) - { - //Now we want to see if the DLLs contain any legacy data types since we want to warn people about that - string[] assemblyErrors; - var assembliesWithReferences = PackageBinaryInspector.ScanAssembliesForTypeReference(tempDir, out assemblyErrors).ToArray(); - if (assemblyErrors.Any()) - { - ContainsBinaryFileErrors = true; - BinaryFileErrors.AddRange(assemblyErrors); - } - if (assembliesWithReferences.Any()) - { - ContainsLegacyPropertyEditors = true; - } - } - - //this will check for existing macros with the same alias - //since we will not overwrite on import it's a good idea to inform the user what will be overwritten - foreach (XmlNode n in Config.DocumentElement.SelectNodes("//macro")) - { - var alias = n.SelectSingleNode("alias").InnerText; - if (!string.IsNullOrEmpty(alias)) - { - try - { - var m = Macro.GetByAlias(alias); - - if (m != null) - { - this.ContainsMacroConflict = true; - this._conflictingMacroAliases.Add(m.Name, alias); - } - } - catch (IndexOutOfRangeException) { } //thrown when the alias doesn't exist in the DB, ie - macro not there - } - } - - foreach (XmlNode n in Config.DocumentElement.SelectNodes("Templates/Template")) - { - var alias = n.SelectSingleNode("Alias").InnerText; - if (!string.IsNullOrEmpty(alias)) - { - var t = Template.GetByAlias(alias); - if (t != null) - { - this.ContainsTemplateConflicts = true; - this._conflictingTemplateAliases.Add(t.Text, alias); - } - } - } - - foreach (XmlNode n in Config.DocumentElement.SelectNodes("Stylesheets/Stylesheet")) - { - var alias = n.SelectSingleNode("Name").InnerText; - if (!string.IsNullOrEmpty(alias)) - { - var s = StyleSheet.GetByName(alias); - if (s != null) - { - this.ContainsStyleSheeConflicts = true; - this._conflictingStyleSheetNames.Add(s.Text, alias); - } - } - } - - try - { - ReadMe = XmlHelper.GetNodeValue(Config.DocumentElement.SelectSingleNode("/umbPackage/info/readme")); - } - catch { } - - try - { - Control = XmlHelper.GetNodeValue(Config.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)) == false) - Directory.CreateDirectory(IOHelper.MapPath(SystemDirectories.Packages)); - - var wc = new System.Net.WebClient(); - - wc.DownloadFile( - "http://" + PackageServer + "/fetch?package=" + Package.ToString(), - IOHelper.MapPath(SystemDirectories.Packages + "/" + Package.ToString() + ".umb")); - - return "packages\\" + Package.ToString() + ".umb"; - } - - #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]", SystemDirectories.Umbraco); - path = path.Replace("[$UMBRACOCLIENT]", SystemDirectories.UmbracoClient); - path = path.Replace("[$CONFIG]", SystemDirectories.Config); - path = path.Replace("[$DATA]", 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; - return path + fileName.Substring(1); - } - if (fileNameStartsWithSlash) - // Required slash specified, just concatenate - return path + fileName; - return path + Path.DirectorySeparatorChar + fileName; - } - - private static string UnPack(string zipName) - { - // Unzip - - //the temp directory will be the package GUID - this keeps it consistent! - //the zipName is always the package Guid.umb - - var packageFileName = Path.GetFileNameWithoutExtension(zipName); - var packageId = Guid.NewGuid(); - Guid.TryParse(packageFileName, out packageId); - - string tempDir = IOHelper.MapPath(SystemDirectories.Data) + Path.DirectorySeparatorChar + packageId.ToString(); - //clear the directory if it exists - if (Directory.Exists(tempDir)) Directory.Delete(tempDir, true); - Directory.CreateDirectory(tempDir); - - var s = new ZipInputStream(File.OpenRead(zipName)); - - ZipEntry theEntry; - while ((theEntry = s.GetNextEntry()) != null) - { - string fileName = Path.GetFileName(theEntry.Name); - - if (fileName != String.Empty) - { - FileStream streamWriter = File.Create(tempDir + Path.DirectorySeparatorChar + fileName); - - int size = 2048; - byte[] data = new byte[2048]; - while (true) - { - size = s.Read(data, 0, data.Length); - if (size > 0) - { - streamWriter.Write(data, 0, size); - } - else - { - break; - } - } - - streamWriter.Close(); - - } - } - - // Clean up - s.Close(); - File.Delete(zipName); - - return tempDir; - - } - - #endregion - } -} +using System; +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Xml; +using System.Linq; +using ICSharpCode.SharpZipLib.Zip; +using Umbraco.Core; +using Umbraco.Core.IO; +using Umbraco.Core.Logging; +using Umbraco.Core.Packaging; +using umbraco.cms.businesslogic.web; +using umbraco.cms.businesslogic.propertytype; +using umbraco.BusinessLogic; +using System.Diagnostics; +using umbraco.cms.businesslogic.macro; +using umbraco.cms.businesslogic.template; +using umbraco.interfaces; + +namespace umbraco.cms.businesslogic.packager +{ + /// + /// The packager is a component which enables sharing of both data and functionality components between different umbraco installations. + /// + /// The output is a .umb (a zip compressed file) which contains the exported documents/medias/macroes/documenttypes (etc.) + /// in a Xml document, along with the physical files used (images/usercontrols/xsl documents etc.) + /// + /// Partly implemented, import of packages is done, the export is *under construction*. + /// + /// + /// Ruben Verborgh 31/12/2007: I had to change some code, I marked my changes with "DATALAYER". + /// Reason: @@IDENTITY can't be used with the new datalayer. + /// I wasn't able to test the code, since I'm not aware how the code functions. + /// + public class Installer + { + private const string PackageServer = "packages.umbraco.org"; + + private readonly List _unsecureFiles = new List(); + private readonly Dictionary _conflictingMacroAliases = new Dictionary(); + private readonly Dictionary _conflictingTemplateAliases = new Dictionary(); + private readonly Dictionary _conflictingStyleSheetNames = new Dictionary(); + + private readonly List _binaryFileErrors = new List(); + + public string Name { get; private set; } + public string Version { get; private set; } + public string Url { get; private set; } + public string License { get; private set; } + public string LicenseUrl { get; private set; } + public string Author { get; private set; } + public string AuthorUrl { get; private set; } + public string ReadMe { get; private set; } + public string Control { get; private set; } + + public bool ContainsMacroConflict { get; private set; } + public IDictionary ConflictingMacroAliases { get { return _conflictingMacroAliases; } } + + public bool ContainsUnsecureFiles { get; private set; } + public List UnsecureFiles { get { return _unsecureFiles; } } + + public bool ContainsTemplateConflicts { get; private set; } + public IDictionary ConflictingTemplateAliases { get { return _conflictingTemplateAliases; } } + + /// + /// Indicates that the package contains assembly reference errors + /// + public bool ContainsBinaryFileErrors { get; private set; } + + /// + /// List each assembly reference error + /// + public List BinaryFileErrors { get { return _binaryFileErrors; } } + + /// + /// Indicates that the package contains legacy property editors + /// + public bool ContainsLegacyPropertyEditors { get; private set; } + + public bool ContainsStyleSheeConflicts { get; private set; } + public IDictionary ConflictingStyleSheetNames { get { return _conflictingStyleSheetNames; } } + + public int RequirementsMajor { get; private set; } + public int RequirementsMinor { get; private set; } + public int RequirementsPatch { get; private set; } + + /// + /// The xmldocument, describing the contents of a package. + /// + public XmlDocument Config { get; private set; } + + /// + /// Constructor + /// + public Installer() + { + ContainsBinaryFileErrors = false; + ContainsTemplateConflicts = false; + ContainsUnsecureFiles = false; + ContainsMacroConflict = false; + ContainsStyleSheeConflicts = false; + } + + /// + /// Constructor + /// + /// The name of the package + /// The version of the package + /// The url to a descriptionpage + /// The license under which the package is released (preferably GPL ;)) + /// The url to a licensedescription + /// The original author of the package + /// The url to the Authors website + /// Umbraco version major + /// Umbraco version minor + /// Umbraco version patch + /// The readme text + /// The name of the usercontrol used to configure the package after install + public Installer(string Name, string Version, string Url, string License, string LicenseUrl, string Author, string AuthorUrl, int RequirementsMajor, int RequirementsMinor, int RequirementsPatch, string Readme, string Control) + { + ContainsBinaryFileErrors = false; + ContainsTemplateConflicts = false; + ContainsUnsecureFiles = false; + ContainsMacroConflict = false; + ContainsStyleSheeConflicts = false; + this.Name = Name; + this.Version = Version; + this.Url = Url; + this.License = License; + this.LicenseUrl = LicenseUrl; + this.RequirementsMajor = RequirementsMajor; + this.RequirementsMinor = RequirementsMinor; + this.RequirementsPatch = RequirementsPatch; + this.Author = Author; + this.AuthorUrl = AuthorUrl; + ReadMe = Readme; + this.Control = Control; + } + + #region Public Methods + + /// + /// Imports the specified package + /// + /// Filename of the umbracopackage + /// + public string Import(string InputFile) + { + using (DisposableTimer.DebugDuration( + () => "Importing package file " + InputFile, + () => "Package file " + InputFile + "imported")) + { + var tempDir = ""; + if (File.Exists(IOHelper.MapPath(SystemDirectories.Data + Path.DirectorySeparatorChar + InputFile))) + { + var fi = new FileInfo(IOHelper.MapPath(SystemDirectories.Data + Path.DirectorySeparatorChar + InputFile)); + // Check if the file is a valid package + if (fi.Extension.ToLower() == ".umb") + { + try + { + tempDir = UnPack(fi.FullName); + LoadConfig(tempDir); + } + catch (Exception unpackE) + { + throw new Exception("Error unpacking extension...", unpackE); + } + } + else + throw new Exception("Error - file isn't a package (doesn't have a .umb extension). Check if the file automatically got named '.zip' upon download."); + } + else + throw new Exception("Error - file not found. Could find file named '" + IOHelper.MapPath(SystemDirectories.Data + Path.DirectorySeparatorChar + InputFile) + "'"); + 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 + var packName = XmlHelper.GetNodeValue(Config.DocumentElement.SelectSingleNode("/umbPackage/info/package/name")); + var packAuthor = XmlHelper.GetNodeValue(Config.DocumentElement.SelectSingleNode("/umbPackage/info/author/name")); + var packAuthorUrl = XmlHelper.GetNodeValue(Config.DocumentElement.SelectSingleNode("/umbPackage/info/author/website")); + var packVersion = XmlHelper.GetNodeValue(Config.DocumentElement.SelectSingleNode("/umbPackage/info/package/version")); + var packReadme = XmlHelper.GetNodeValue(Config.DocumentElement.SelectSingleNode("/umbPackage/info/readme")); + var packLicense = XmlHelper.GetNodeValue(Config.DocumentElement.SelectSingleNode("/umbPackage/info/package/license ")); + var packUrl = XmlHelper.GetNodeValue(Config.DocumentElement.SelectSingleNode("/umbPackage/info/package/url ")); + + var enableSkins = false; + var skinRepoGuid = ""; + + if (Config.DocumentElement.SelectSingleNode("/umbPackage/enableSkins") != null) + { + var skinNode = Config.DocumentElement.SelectSingleNode("/umbPackage/enableSkins"); + enableSkins = bool.Parse(XmlHelper.GetNodeValue(skinNode)); + if (skinNode.Attributes["repository"] != null && string.IsNullOrEmpty(skinNode.Attributes["repository"].Value) == false) + skinRepoGuid = skinNode.Attributes["repository"].Value; + } + + //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 + 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.Url = packUrl; + + //skinning + insPack.Data.EnableSkins = enableSkins; + insPack.Data.SkinRepoGuid = string.IsNullOrEmpty(skinRepoGuid) ? Guid.Empty : new Guid(skinRepoGuid); + + 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. + insPack.Save(); + + return insPack.Data.Id; + } + + public void InstallFiles(int packageId, string tempDir) + { + using (DisposableTimer.DebugDuration( + () => "Installing package files for package id " + packageId + " into temp folder " + tempDir, + () => "Package file installation complete for package id " + packageId)) + { + //retrieve the manifest to continue installation + var insPack = InstalledPackage.GetById(packageId); + + // Move files + //string virtualBasePath = System.Web.HttpContext.Current.Request.ApplicationPath; + string basePath = System.Web.Hosting.HostingEnvironment.ApplicationPhysicalPath; + + foreach (XmlNode n in Config.DocumentElement.SelectNodes("//file")) + { + //we enclose the whole file-moving to ensure that the entire installer doesn't crash + try + { + var destPath = GetFileName(basePath, XmlHelper.GetNodeValue(n.SelectSingleNode("orgPath"))); + var sourceFile = GetFileName(tempDir, XmlHelper.GetNodeValue(n.SelectSingleNode("guid"))); + var destFile = GetFileName(destPath, XmlHelper.GetNodeValue(n.SelectSingleNode("orgName"))); + + // Create the destination directory if it doesn't exist + if (Directory.Exists(destPath) == false) + Directory.CreateDirectory(destPath); + //If a file with this name exists, delete it + else if (File.Exists(destFile)) + File.Delete(destFile); + + // Move the file + File.Move(sourceFile, destFile); + + //PPH log file install + insPack.Data.Files.Add(XmlHelper.GetNodeValue(n.SelectSingleNode("orgPath")) + "/" + XmlHelper.GetNodeValue(n.SelectSingleNode("orgName"))); + } + catch (Exception ex) + { + LogHelper.Error("Package install error", ex); + } + } + + 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 + var insPack = InstalledPackage.GetById(packageId); + //bool saveNeeded = false; + + // 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 = Config.DocumentElement.GetXElement(); + var packagingService = ApplicationContext.Current.Services.PackagingService; + + //Perhaps it would have been a good idea to put the following into methods eh?!? + + #region DataTypes + var dataTypeElement = rootElement.Descendants("DataTypes").FirstOrDefault(); + if(dataTypeElement != null) + { + 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); + + if (newDtd != null) + { + insPack.Data.DataTypes.Add(newDtd.Id.ToString()); + saveNeeded = true; + } + }*/ + + //if (saveNeeded) { insPack.Save(); saveNeeded = false; } + #endregion + + #region Languages + foreach (XmlNode n in Config.DocumentElement.SelectNodes("//Language")) + { + language.Language newLang = language.Language.Import(n); + + if (newLang != null) + { + insPack.Data.Languages.Add(newLang.id.ToString(CultureInfo.InvariantCulture)); + //saveNeeded = true; + } + } + + //if (saveNeeded) { insPack.Save(); saveNeeded = false; } + #endregion + + #region Dictionary items + foreach (XmlNode n in Config.DocumentElement.SelectNodes("./DictionaryItems/DictionaryItem")) + { + Dictionary.DictionaryItem newDi = Dictionary.DictionaryItem.Import(n); + + if (newDi != null) + { + insPack.Data.DictionaryItems.Add(newDi.id.ToString()); + //saveNeeded = true; + } + } + + //if (saveNeeded) { insPack.Save(); saveNeeded = false; } + #endregion + + #region Macros + foreach (XmlNode n in Config.DocumentElement.SelectNodes("//macro")) + { + Macro m = Macro.Import(n); + + if (m != null) + { + insPack.Data.Macros.Add(m.Id.ToString(CultureInfo.InvariantCulture)); + //saveNeeded = true; + } + } + + //if (saveNeeded) { insPack.Save(); saveNeeded = false; } + #endregion + + #region Templates + var templateElement = rootElement.Descendants("Templates").FirstOrDefault(); + if (templateElement != null) + { + var templates = packagingService.ImportTemplates(templateElement, currentUser.Id); + foreach (var template in templates) + { + insPack.Data.Templates.Add(template.Id.ToString(CultureInfo.InvariantCulture)); + //saveNeeded = true; + } + } + + //if (saveNeeded) { insPack.Save(); saveNeeded = false; } + + /*foreach (XmlNode n in _packageConfig.DocumentElement.SelectNodes("Templates/Template")) + { + var t = Template.Import(n, currentUser); + + insPack.Data.Templates.Add(t.Id.ToString()); + + saveNeeded = true; + } + + if (saveNeeded) { insPack.Save(); saveNeeded = false; } + + + //NOTE: SD: I'm pretty sure the only thing the below script does is ensure that the Master template Id is set + // in the database, but this is also duplicating the saving of the design content since the above Template.Import + // already does this. I've left this for now because I'm not sure the reprocussions of removing it but seems there + // is a lot of excess database calls happening here. + foreach (XmlNode n in _packageConfig.DocumentElement.SelectNodes("Templates/Template")) + { + string master = XmlHelper.GetNodeValue(n.SelectSingleNode("Master")); + Template t = Template.GetByAlias(XmlHelper.GetNodeValue(n.SelectSingleNode("Alias"))); + if (master.Trim() != "") + { + var masterTemplate = Template.GetByAlias(master); + if (masterTemplate != null) + { + 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 + // MVC which means that the package will not work anymore. + // The code below that imports the templates should suffice because it's actually importing + // template data not just blank data. + + //if (UmbracoConfiguration.Current.UmbracoSettings.Templates.UseAspNetMasterPages) + // t.SaveMasterPageFile(t.Design); + } + } + // Master templates can only be generated when their master is known + if (UmbracoConfiguration.Current.UmbracoSettings.Templates.UseAspNetMasterPages) + { + t.ImportDesign(XmlHelper.GetNodeValue(n.SelectSingleNode("Design"))); + t.SaveMasterPageFile(t.Design); + } + }*/ + #endregion + + #region DocumentTypes + //Check whether the root element is a doc type rather then a complete package + var docTypeElement = rootElement.Name.LocalName.Equals("DocumentType") || + rootElement.Name.LocalName.Equals("DocumentTypes") + ? rootElement + : rootElement.Descendants("DocumentTypes").FirstOrDefault(); + + if (docTypeElement != null) + { + var contentTypes = packagingService.ImportContentTypes(docTypeElement, currentUser.Id); + foreach (var contentType in contentTypes) + { + insPack.Data.Documenttypes.Add(contentType.Id.ToString(CultureInfo.InvariantCulture)); + //saveNeeded = true; + } + } + + //if (saveNeeded) { insPack.Save(); saveNeeded = false; } + + /*foreach (XmlNode n in _packageConfig.DocumentElement.SelectNodes("DocumentTypes/DocumentType")) + { + ImportDocumentType(n, currentUser, false); + saveNeeded = true; + } + + if (saveNeeded) { insPack.Save(); saveNeeded = false; } + + + // Add documenttype structure + foreach (XmlNode n in _packageConfig.DocumentElement.SelectNodes("DocumentTypes/DocumentType")) + { + DocumentType dt = DocumentType.GetByAlias(XmlHelper.GetNodeValue(n.SelectSingleNode("Info/Alias"))); + 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; + dt.Save(); + //PPH we log the document type install here. + insPack.Data.Documenttypes.Add(dt.Id.ToString()); + saveNeeded = true; + } + } + + if (saveNeeded) { insPack.Save(); saveNeeded = false; }*/ + #endregion + + #region Stylesheets + foreach (XmlNode n in Config.DocumentElement.SelectNodes("Stylesheets/Stylesheet")) + { + StyleSheet s = StyleSheet.Import(n, currentUser); + + insPack.Data.Stylesheets.Add(s.Id.ToString()); + //saveNeeded = true; + } + + //if (saveNeeded) { insPack.Save(); saveNeeded = false; } + #endregion + + #region Documents + var documentElement = rootElement.Descendants("DocumentSet").FirstOrDefault(); + if (documentElement != null) + { + 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, currentUser, n).ToString(); + }*/ + #endregion + + #region Package Actions + foreach (XmlNode n in Config.DocumentElement.SelectNodes("Actions/Action")) + { + if (n.Attributes["undo"] == null || n.Attributes["undo"].Value == "true") + { + insPack.Data.Actions += n.OuterXml; + } + + if (n.Attributes["runat"] != null && n.Attributes["runat"].Value == "install") + { + try + { + PackageAction.RunPackageAction(insPack.Data.Name, n.Attributes["alias"].Value, n); + } + catch + { + + } + } + } + #endregion + + // Trigger update of Apps / Trees config. + // (These are ApplicationStartupHandlers so just instantiating them will trigger them) + new ApplicationRegistrar(); + new ApplicationTreeRegistrar(); + + insPack.Save(); + } + } + + /// + /// Remove the temp installation folder + /// + /// + /// + public void InstallCleanUp(int packageId, string tempDir) + { + if (Directory.Exists(tempDir)) + { + Directory.Delete(tempDir, true); + } + } + + /// + /// Reads the configuration of the package from the configuration xmldocument + /// + /// The folder to which the contents of the package is extracted + public void LoadConfig(string tempDir) + { + Config = new XmlDocument(); + Config.Load(tempDir + Path.DirectorySeparatorChar + "package.xml"); + + Name = Config.DocumentElement.SelectSingleNode("/umbPackage/info/package/name").FirstChild.Value; + Version = Config.DocumentElement.SelectSingleNode("/umbPackage/info/package/version").FirstChild.Value; + Url = Config.DocumentElement.SelectSingleNode("/umbPackage/info/package/url").FirstChild.Value; + License = Config.DocumentElement.SelectSingleNode("/umbPackage/info/package/license").FirstChild.Value; + LicenseUrl = Config.DocumentElement.SelectSingleNode("/umbPackage/info/package/license").Attributes.GetNamedItem("url").Value; + RequirementsMajor = int.Parse(Config.DocumentElement.SelectSingleNode("/umbPackage/info/package/requirements/major").FirstChild.Value); + RequirementsMinor = int.Parse(Config.DocumentElement.SelectSingleNode("/umbPackage/info/package/requirements/minor").FirstChild.Value); + RequirementsPatch = int.Parse(Config.DocumentElement.SelectSingleNode("/umbPackage/info/package/requirements/patch").FirstChild.Value); + Author = Config.DocumentElement.SelectSingleNode("/umbPackage/info/author/name").FirstChild.Value; + AuthorUrl = Config.DocumentElement.SelectSingleNode("/umbPackage/info/author/website").FirstChild.Value; + + var basePath = System.Web.Hosting.HostingEnvironment.ApplicationPhysicalPath; + var dllBinFiles = new List(); + + foreach (XmlNode n in Config.DocumentElement.SelectNodes("//file")) + { + var badFile = false; + var destPath = GetFileName(basePath, XmlHelper.GetNodeValue(n.SelectSingleNode("orgPath"))); + var orgName = XmlHelper.GetNodeValue(n.SelectSingleNode("orgName")); + var destFile = GetFileName(destPath, orgName); + + if (destPath.ToLower().Contains(IOHelper.DirSepChar + "app_code")) + { + badFile = true; + } + + if (destPath.ToLower().Contains(IOHelper.DirSepChar + "bin")) + { + badFile = true; + } + + if (destFile.ToLower().EndsWith(".dll")) + { + badFile = true; + dllBinFiles.Add(Path.Combine(tempDir, orgName)); + } + + if (badFile) + { + ContainsUnsecureFiles = true; + _unsecureFiles.Add(XmlHelper.GetNodeValue(n.SelectSingleNode("orgName"))); + } + } + + if (ContainsUnsecureFiles) + { + //Now we want to see if the DLLs contain any legacy data types since we want to warn people about that + string[] assemblyErrors; + var assembliesWithReferences = PackageBinaryInspector.ScanAssembliesForTypeReference(tempDir, out assemblyErrors).ToArray(); + if (assemblyErrors.Any()) + { + ContainsBinaryFileErrors = true; + BinaryFileErrors.AddRange(assemblyErrors); + } + if (assembliesWithReferences.Any()) + { + ContainsLegacyPropertyEditors = true; + } + } + + //this will check for existing macros with the same alias + //since we will not overwrite on import it's a good idea to inform the user what will be overwritten + foreach (XmlNode n in Config.DocumentElement.SelectNodes("//macro")) + { + var alias = n.SelectSingleNode("alias").InnerText; + if (!string.IsNullOrEmpty(alias)) + { + var m = ApplicationContext.Current.Services.MacroService.GetByAlias(alias); + if (m != null) + { + ContainsMacroConflict = true; + _conflictingMacroAliases.Add(m.Name, alias); + } + } + } + + foreach (XmlNode n in Config.DocumentElement.SelectNodes("Templates/Template")) + { + var alias = n.SelectSingleNode("Alias").InnerText; + if (!string.IsNullOrEmpty(alias)) + { + var t = Template.GetByAlias(alias); + if (t != null) + { + this.ContainsTemplateConflicts = true; + this._conflictingTemplateAliases.Add(t.Text, alias); + } + } + } + + foreach (XmlNode n in Config.DocumentElement.SelectNodes("Stylesheets/Stylesheet")) + { + var alias = n.SelectSingleNode("Name").InnerText; + if (!string.IsNullOrEmpty(alias)) + { + var s = StyleSheet.GetByName(alias); + if (s != null) + { + this.ContainsStyleSheeConflicts = true; + this._conflictingStyleSheetNames.Add(s.Text, alias); + } + } + } + + try + { + ReadMe = XmlHelper.GetNodeValue(Config.DocumentElement.SelectSingleNode("/umbPackage/info/readme")); + } + catch { } + + try + { + Control = XmlHelper.GetNodeValue(Config.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)) == false) + Directory.CreateDirectory(IOHelper.MapPath(SystemDirectories.Packages)); + + var wc = new System.Net.WebClient(); + + wc.DownloadFile( + "http://" + PackageServer + "/fetch?package=" + Package.ToString(), + IOHelper.MapPath(SystemDirectories.Packages + "/" + Package.ToString() + ".umb")); + + return "packages\\" + Package.ToString() + ".umb"; + } + + #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]", SystemDirectories.Umbraco); + path = path.Replace("[$UMBRACOCLIENT]", SystemDirectories.UmbracoClient); + path = path.Replace("[$CONFIG]", SystemDirectories.Config); + path = path.Replace("[$DATA]", 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; + return path + fileName.Substring(1); + } + if (fileNameStartsWithSlash) + // Required slash specified, just concatenate + return path + fileName; + return path + Path.DirectorySeparatorChar + fileName; + } + + private static string UnPack(string zipName) + { + // Unzip + + //the temp directory will be the package GUID - this keeps it consistent! + //the zipName is always the package Guid.umb + + var packageFileName = Path.GetFileNameWithoutExtension(zipName); + var packageId = Guid.NewGuid(); + Guid.TryParse(packageFileName, out packageId); + + string tempDir = IOHelper.MapPath(SystemDirectories.Data) + Path.DirectorySeparatorChar + packageId.ToString(); + //clear the directory if it exists + if (Directory.Exists(tempDir)) Directory.Delete(tempDir, true); + Directory.CreateDirectory(tempDir); + + var s = new ZipInputStream(File.OpenRead(zipName)); + + ZipEntry theEntry; + while ((theEntry = s.GetNextEntry()) != null) + { + string fileName = Path.GetFileName(theEntry.Name); + + if (fileName != String.Empty) + { + FileStream streamWriter = File.Create(tempDir + Path.DirectorySeparatorChar + fileName); + + int size = 2048; + byte[] data = new byte[2048]; + while (true) + { + size = s.Read(data, 0, data.Length); + if (size > 0) + { + streamWriter.Write(data, 0, size); + } + else + { + break; + } + } + + streamWriter.Close(); + + } + } + + // Clean up + s.Close(); + File.Delete(zipName); + + return tempDir; + + } + + #endregion + } +} diff --git a/src/umbraco.interfaces/ITask.cs b/src/umbraco.interfaces/ITask.cs index 0b50fcc541..8ea902cc39 100644 --- a/src/umbraco.interfaces/ITask.cs +++ b/src/umbraco.interfaces/ITask.cs @@ -5,6 +5,7 @@ namespace umbraco.interfaces /// /// Summary description for ITask. /// + [Obsolete("ITask is used for legacy webforms back office editors, change to using the v7 angular approach")] public interface ITask { int ParentID {set; get;} diff --git a/src/umbraco.interfaces/ITaskReturnUrl.cs b/src/umbraco.interfaces/ITaskReturnUrl.cs index 687ddd8a14..98b132689c 100644 --- a/src/umbraco.interfaces/ITaskReturnUrl.cs +++ b/src/umbraco.interfaces/ITaskReturnUrl.cs @@ -1,5 +1,8 @@ +using System; + namespace umbraco.interfaces { + [Obsolete("ITask is used for legacy webforms back office editors, change to using the v7 angular approach")] public interface ITaskReturnUrl : ITask { string ReturnUrl {get;}