Merge branch 'v8/dev' into feature/5702-custom-validation-messages

This commit is contained in:
Andy Butland
2019-09-30 18:45:00 +02:00
676 changed files with 20772 additions and 16228 deletions

View File

@@ -2,7 +2,6 @@
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text.RegularExpressions;
using System.Web;
using System.Xml.Linq;
using System.Xml.XPath;
@@ -12,7 +11,9 @@ using Umbraco.Core.Logging;
using Umbraco.Core.Models;
using Umbraco.Core.Models.Entities;
using Umbraco.Core.Models.Packaging;
using Umbraco.Core.Models.PublishedContent;
using Umbraco.Core.PropertyEditors;
using Umbraco.Core.Scoping;
using Umbraco.Core.Services;
using Umbraco.Core.Services.Implement;
@@ -26,13 +27,14 @@ namespace Umbraco.Core.Packaging
private readonly ILocalizationService _localizationService;
private readonly IDataTypeService _dataTypeService;
private readonly PropertyEditorCollection _propertyEditors;
private readonly IScopeProvider _scopeProvider;
private readonly IEntityService _entityService;
private readonly IContentTypeService _contentTypeService;
private readonly IContentService _contentService;
public PackageDataInstallation(ILogger logger, IFileService fileService, IMacroService macroService, ILocalizationService localizationService,
IDataTypeService dataTypeService, IEntityService entityService, IContentTypeService contentTypeService,
IContentService contentService, PropertyEditorCollection propertyEditors)
IContentService contentService, PropertyEditorCollection propertyEditors, IScopeProvider scopeProvider)
{
_logger = logger;
_fileService = fileService;
@@ -40,12 +42,13 @@ namespace Umbraco.Core.Packaging
_localizationService = localizationService;
_dataTypeService = dataTypeService;
_propertyEditors = propertyEditors;
_scopeProvider = scopeProvider;
_entityService = entityService;
_contentTypeService = contentTypeService;
_contentService = contentService;
}
#region Uninstall
#region Install/Uninstall
public UninstallationSummary UninstallPackageData(PackageDefinition package, int userId)
{
@@ -58,93 +61,97 @@ namespace Umbraco.Core.Packaging
var removedDataTypes = new List<IDataType>();
var removedLanguages = new List<ILanguage>();
//Uninstall templates
foreach (var item in package.Templates.ToArray())
using (var scope = _scopeProvider.CreateScope())
{
if (int.TryParse(item, out var nId) == false) continue;
var found = _fileService.GetTemplate(nId);
if (found != null)
//Uninstall templates
foreach (var item in package.Templates.ToArray())
{
removedTemplates.Add(found);
_fileService.DeleteTemplate(found.Alias, userId);
if (int.TryParse(item, out var nId) == false) continue;
var found = _fileService.GetTemplate(nId);
if (found != null)
{
removedTemplates.Add(found);
_fileService.DeleteTemplate(found.Alias, userId);
}
package.Templates.Remove(nId.ToString());
}
package.Templates.Remove(nId.ToString());
}
//Uninstall macros
foreach (var item in package.Macros.ToArray())
{
if (int.TryParse(item, out var nId) == false) continue;
var macro = _macroService.GetById(nId);
if (macro != null)
//Uninstall macros
foreach (var item in package.Macros.ToArray())
{
removedMacros.Add(macro);
_macroService.Delete(macro, userId);
if (int.TryParse(item, out var nId) == false) continue;
var macro = _macroService.GetById(nId);
if (macro != null)
{
removedMacros.Add(macro);
_macroService.Delete(macro, userId);
}
package.Macros.Remove(nId.ToString());
}
package.Macros.Remove(nId.ToString());
}
//Remove Document Types
var contentTypes = new List<IContentType>();
var contentTypeService = _contentTypeService;
foreach (var item in package.DocumentTypes.ToArray())
{
if (int.TryParse(item, out var nId) == false) continue;
var contentType = contentTypeService.Get(nId);
if (contentType == null) continue;
contentTypes.Add(contentType);
package.DocumentTypes.Remove(nId.ToString(CultureInfo.InvariantCulture));
}
//Order the DocumentTypes before removing them
if (contentTypes.Any())
{
// TODO: I don't think this ordering is necessary
var orderedTypes = (from contentType in contentTypes
orderby contentType.ParentId descending, contentType.Id descending
select contentType).ToList();
removedContentTypes.AddRange(orderedTypes);
contentTypeService.Delete(orderedTypes, userId);
}
//Remove Dictionary items
foreach (var item in package.DictionaryItems.ToArray())
{
if (int.TryParse(item, out var nId) == false) continue;
var di = _localizationService.GetDictionaryItemById(nId);
if (di != null)
//Remove Document Types
var contentTypes = new List<IContentType>();
var contentTypeService = _contentTypeService;
foreach (var item in package.DocumentTypes.ToArray())
{
removedDictionaryItems.Add(di);
_localizationService.Delete(di, userId);
if (int.TryParse(item, out var nId) == false) continue;
var contentType = contentTypeService.Get(nId);
if (contentType == null) continue;
contentTypes.Add(contentType);
package.DocumentTypes.Remove(nId.ToString(CultureInfo.InvariantCulture));
}
package.DictionaryItems.Remove(nId.ToString());
}
//Remove Data types
foreach (var item in package.DataTypes.ToArray())
{
if (int.TryParse(item, out var nId) == false) continue;
var dtd = _dataTypeService.GetDataType(nId);
if (dtd != null)
//Order the DocumentTypes before removing them
if (contentTypes.Any())
{
removedDataTypes.Add(dtd);
_dataTypeService.Delete(dtd, userId);
// TODO: I don't think this ordering is necessary
var orderedTypes = (from contentType in contentTypes
orderby contentType.ParentId descending, contentType.Id descending
select contentType).ToList();
removedContentTypes.AddRange(orderedTypes);
contentTypeService.Delete(orderedTypes, userId);
}
package.DataTypes.Remove(nId.ToString());
}
//Remove Langs
foreach (var item in package.Languages.ToArray())
{
if (int.TryParse(item, out var nId) == false) continue;
var lang = _localizationService.GetLanguageById(nId);
if (lang != null)
//Remove Dictionary items
foreach (var item in package.DictionaryItems.ToArray())
{
removedLanguages.Add(lang);
_localizationService.Delete(lang, userId);
if (int.TryParse(item, out var nId) == false) continue;
var di = _localizationService.GetDictionaryItemById(nId);
if (di != null)
{
removedDictionaryItems.Add(di);
_localizationService.Delete(di, userId);
}
package.DictionaryItems.Remove(nId.ToString());
}
package.Languages.Remove(nId.ToString());
//Remove Data types
foreach (var item in package.DataTypes.ToArray())
{
if (int.TryParse(item, out var nId) == false) continue;
var dtd = _dataTypeService.GetDataType(nId);
if (dtd != null)
{
removedDataTypes.Add(dtd);
_dataTypeService.Delete(dtd, userId);
}
package.DataTypes.Remove(nId.ToString());
}
//Remove Langs
foreach (var item in package.Languages.ToArray())
{
if (int.TryParse(item, out var nId) == false) continue;
var lang = _localizationService.GetLanguageById(nId);
if (lang != null)
{
removedLanguages.Add(lang);
_localizationService.Delete(lang, userId);
}
package.Languages.Remove(nId.ToString());
}
scope.Complete();
}
// create a summary of what was actually removed, for PackagingService.UninstalledPackage
@@ -165,14 +172,40 @@ namespace Umbraco.Core.Packaging
}
public InstallationSummary InstallPackageData(CompiledPackage compiledPackage, int userId)
{
using (var scope = _scopeProvider.CreateScope())
{
var installationSummary = new InstallationSummary
{
DataTypesInstalled = ImportDataTypes(compiledPackage.DataTypes.ToList(), userId),
LanguagesInstalled = ImportLanguages(compiledPackage.Languages, userId),
DictionaryItemsInstalled = ImportDictionaryItems(compiledPackage.DictionaryItems, userId),
MacrosInstalled = ImportMacros(compiledPackage.Macros, userId),
TemplatesInstalled = ImportTemplates(compiledPackage.Templates.ToList(), userId),
DocumentTypesInstalled = ImportDocumentTypes(compiledPackage.DocumentTypes, userId)
};
//we need a reference to the imported doc types to continue
var importedDocTypes = installationSummary.DocumentTypesInstalled.ToDictionary(x => x.Alias, x => x);
installationSummary.StylesheetsInstalled = ImportStylesheets(compiledPackage.Stylesheets, userId);
installationSummary.ContentInstalled = ImportContent(compiledPackage.Documents, importedDocTypes, userId);
scope.Complete();
return installationSummary;
}
}
#endregion
#region Content
public IEnumerable<IContent> ImportContent(IEnumerable<CompiledPackageDocument> docs, IDictionary<string, IContentType> importedDocumentTypes, int userId)
public IReadOnlyList<IContent> ImportContent(IEnumerable<CompiledPackageDocument> docs, IDictionary<string, IContentType> importedDocumentTypes, int userId)
{
return docs.SelectMany(x => ImportContent(x, -1, importedDocumentTypes, userId));
return docs.SelectMany(x => ImportContent(x, -1, importedDocumentTypes, userId)).ToList();
}
/// <summary>
@@ -353,7 +386,7 @@ namespace Umbraco.Core.Packaging
#region DocumentTypes
public IEnumerable<IContentType> ImportDocumentType(XElement docTypeElement, int userId)
public IReadOnlyList<IContentType> ImportDocumentType(XElement docTypeElement, int userId)
{
return ImportDocumentTypes(new[] { docTypeElement }, userId);
}
@@ -364,7 +397,7 @@ namespace Umbraco.Core.Packaging
/// <param name="docTypeElements">Xml to import</param>
/// <param name="userId">Optional id of the User performing the operation. Default is zero (admin).</param>
/// <returns>An enumerable list of generated ContentTypes</returns>
public IEnumerable<IContentType> ImportDocumentTypes(IEnumerable<XElement> docTypeElements, int userId)
public IReadOnlyList<IContentType> ImportDocumentTypes(IEnumerable<XElement> docTypeElements, int userId)
{
return ImportDocumentTypes(docTypeElements.ToList(), true, userId);
}
@@ -376,7 +409,7 @@ namespace Umbraco.Core.Packaging
/// <param name="importStructure">Boolean indicating whether or not to import the </param>
/// <param name="userId">Optional id of the User performing the operation. Default is zero (admin).</param>
/// <returns>An enumerable list of generated ContentTypes</returns>
public IEnumerable<IContentType> ImportDocumentTypes(IReadOnlyCollection<XElement> unsortedDocumentTypes, bool importStructure, int userId)
public IReadOnlyList<IContentType> ImportDocumentTypes(IReadOnlyCollection<XElement> unsortedDocumentTypes, bool importStructure, int userId)
{
var importedContentTypes = new Dictionary<string, IContentType>();
@@ -575,12 +608,11 @@ namespace Umbraco.Core.Packaging
contentType.Thumbnail = infoElement.Element("Thumbnail").Value;
contentType.Description = infoElement.Element("Description").Value;
//NOTE AllowAtRoot is a new property in the package xml so we need to verify it exists before using it.
//NOTE AllowAtRoot, IsListView, IsElement and Variations are new properties in the package xml so we need to verify it exists before using it.
var allowAtRoot = infoElement.Element("AllowAtRoot");
if (allowAtRoot != null)
contentType.AllowedAsRoot = allowAtRoot.Value.InvariantEquals("true");
//NOTE IsListView is a new property in the package xml so we need to verify it exists before using it.
var isListView = infoElement.Element("IsListView");
if (isListView != null)
contentType.IsContainer = isListView.Value.InvariantEquals("true");
@@ -589,6 +621,10 @@ namespace Umbraco.Core.Packaging
if (isElement != null)
contentType.IsElement = isElement.Value.InvariantEquals("true");
var variationsElement = infoElement.Element("Variations");
if (variationsElement != null)
contentType.Variations = (ContentVariation)Enum.Parse(typeof(ContentVariation), variationsElement.Value);
//Name of the master corresponds to the parent and we need to ensure that the Parent Id is set
var masterElement = infoElement.Element("Master");
if (masterElement != null)
@@ -614,7 +650,7 @@ namespace Umbraco.Core.Packaging
var compositionContentType = importedContentTypes.ContainsKey(compositionAlias)
? importedContentTypes[compositionAlias]
: _contentTypeService.Get(compositionAlias);
var added = contentType.AddContentType(compositionContentType);
contentType.AddContentType(compositionContentType);
}
}
}
@@ -748,11 +784,21 @@ namespace Umbraco.Core.Packaging
{
Name = property.Element("Name").Value,
Description = (string)property.Element("Description"),
Mandatory = property.Element("Mandatory") != null ? property.Element("Mandatory").Value.ToLowerInvariant().Equals("true") : false,
MandatoryMessage = property.Element("MandatoryMessage") != null ? (string)property.Element("MandatoryMessage") : string.Empty,
Mandatory = property.Element("Mandatory") != null
? property.Element("Mandatory").Value.ToLowerInvariant().Equals("true")
: false,
MandatoryMessage = property.Element("MandatoryMessage") != null
? (string)property.Element("MandatoryMessage")
: string.Empty,
ValidationRegExp = (string)property.Element("Validation"),
ValidationRegExpMessage = property.Element("ValidationRegExpMessage") != null ? (string)property.Element("ValidationRegExpMessage") : string.Empty,
SortOrder = sortOrder
ValidationRegExpMessage = property.Element("ValidationRegExpMessage") != null
? (string)property.Element("ValidationRegExpMessage")
: string.Empty,
SortOrder = sortOrder,
Variations = property.Element("Variations") != null
? (ContentVariation)Enum.Parse(typeof(ContentVariation), property.Element("Variations").Value)
: ContentVariation.Nothing
};
var tab = (string)property.Element("Tab");
@@ -819,7 +865,7 @@ namespace Umbraco.Core.Packaging
/// <param name="dataTypeElements">Xml to import</param>
/// <param name="userId">Optional id of the user</param>
/// <returns>An enumerable list of generated DataTypeDefinitions</returns>
public IEnumerable<IDataType> ImportDataTypes(IReadOnlyCollection<XElement> dataTypeElements, int userId)
public IReadOnlyList<IDataType> ImportDataTypes(IReadOnlyCollection<XElement> dataTypeElements, int userId)
{
var dataTypes = new List<IDataType>();
@@ -948,13 +994,13 @@ namespace Umbraco.Core.Packaging
/// <param name="dictionaryItemElementList">Xml to import</param>
/// <param name="userId"></param>
/// <returns>An enumerable list of dictionary items</returns>
public IEnumerable<IDictionaryItem> ImportDictionaryItems(IEnumerable<XElement> dictionaryItemElementList, int userId)
public IReadOnlyList<IDictionaryItem> ImportDictionaryItems(IEnumerable<XElement> dictionaryItemElementList, int userId)
{
var languages = _localizationService.GetAllLanguages().ToList();
return ImportDictionaryItems(dictionaryItemElementList, languages, null, userId);
}
private IEnumerable<IDictionaryItem> ImportDictionaryItems(IEnumerable<XElement> dictionaryItemElementList, List<ILanguage> languages, Guid? parentId, int userId)
private IReadOnlyList<IDictionaryItem> ImportDictionaryItems(IEnumerable<XElement> dictionaryItemElementList, List<ILanguage> languages, Guid? parentId, int userId)
{
var items = new List<IDictionaryItem>();
foreach (var dictionaryItemElement in dictionaryItemElementList)
@@ -1031,7 +1077,7 @@ namespace Umbraco.Core.Packaging
/// <param name="languageElements">Xml to import</param>
/// <param name="userId">Optional id of the User performing the operation</param>
/// <returns>An enumerable list of generated languages</returns>
public IEnumerable<ILanguage> ImportLanguages(IEnumerable<XElement> languageElements, int userId)
public IReadOnlyList<ILanguage> ImportLanguages(IEnumerable<XElement> languageElements, int userId)
{
var list = new List<ILanguage>();
foreach (var languageElement in languageElements)
@@ -1060,7 +1106,7 @@ namespace Umbraco.Core.Packaging
/// <param name="macroElements">Xml to import</param>
/// <param name="userId">Optional id of the User performing the operation</param>
/// <returns></returns>
public IEnumerable<IMacro> ImportMacros(IEnumerable<XElement> macroElements, int userId)
public IReadOnlyList<IMacro> ImportMacros(IEnumerable<XElement> macroElements, int userId)
{
var macros = macroElements.Select(ParseMacroElement).ToList();
@@ -1150,7 +1196,7 @@ namespace Umbraco.Core.Packaging
#region Stylesheets
public IEnumerable<IFile> ImportStylesheets(IEnumerable<XElement> stylesheetElements, int userId)
public IReadOnlyList<IFile> ImportStylesheets(IEnumerable<XElement> stylesheetElements, int userId)
{
var result = new List<IFile>();
@@ -1218,7 +1264,7 @@ namespace Umbraco.Core.Packaging
/// <param name="templateElements">Xml to import</param>
/// <param name="userId">Optional user id</param>
/// <returns>An enumerable list of generated Templates</returns>
public IEnumerable<ITemplate> ImportTemplates(IReadOnlyCollection<XElement> templateElements, int userId)
public IReadOnlyList<ITemplate> ImportTemplates(IReadOnlyCollection<XElement> templateElements, int userId)
{
var templates = new List<ITemplate>();