Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Exposes the entity containers (folders) created during a package installation in the summary available from the ImportedPackageNotification. #11303

Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/Umbraco.Core/Packaging/InstallationSummary.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ public InstallationSummary(string packageName)
public IEnumerable<IPartialView> PartialViewsInstalled { get; set; } = Enumerable.Empty<IPartialView>();
public IEnumerable<IContent> ContentInstalled { get; set; } = Enumerable.Empty<IContent>();
public IEnumerable<IMedia> MediaInstalled { get; set; } = Enumerable.Empty<IMedia>();
public IEnumerable<EntityContainer> EntityContainersInstalled { get; set; } = Enumerable.Empty<EntityContainer>();
AndyButland marked this conversation as resolved.
Show resolved Hide resolved

public override string ToString()
{
Expand Down Expand Up @@ -77,6 +78,7 @@ void WriteCount<T>(string message, IEnumerable<T> source, bool appendLine = true
WriteCount("Stylesheets installed: ", StylesheetsInstalled);
WriteCount("Scripts installed: ", ScriptsInstalled);
WriteCount("Partial views installed: ", PartialViewsInstalled);
WriteCount("Entity containers installed: ", EntityContainersInstalled);
WriteCount("Content items installed: ", ContentInstalled);
WriteCount("Media items installed: ", MediaInstalled, false);

Expand Down
81 changes: 70 additions & 11 deletions src/Umbraco.Infrastructure/Packaging/PackageDataInstallation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -91,19 +91,25 @@ public InstallationSummary InstallPackageData(CompiledPackage compiledPackage, i
var installationSummary = new InstallationSummary(compiledPackage.Name)
{
Warnings = compiledPackage.Warnings,
DataTypesInstalled = ImportDataTypes(compiledPackage.DataTypes.ToList(), userId),
DataTypesInstalled = ImportDataTypes(compiledPackage.DataTypes.ToList(), userId, out IEnumerable<EntityContainer> dataTypeEntityContainersInstalled),
LanguagesInstalled = ImportLanguages(compiledPackage.Languages, userId),
DictionaryItemsInstalled = ImportDictionaryItems(compiledPackage.DictionaryItems, userId),
MacrosInstalled = ImportMacros(compiledPackage.Macros, userId),
MacroPartialViewsInstalled = ImportMacroPartialViews(compiledPackage.MacroPartialViews, userId),
TemplatesInstalled = ImportTemplates(compiledPackage.Templates.ToList(), userId),
DocumentTypesInstalled = ImportDocumentTypes(compiledPackage.DocumentTypes, userId),
MediaTypesInstalled = ImportMediaTypes(compiledPackage.MediaTypes, userId),
DocumentTypesInstalled = ImportDocumentTypes(compiledPackage.DocumentTypes, userId, out IEnumerable<EntityContainer> documentTypeEntityContainersInstalled),
MediaTypesInstalled = ImportMediaTypes(compiledPackage.MediaTypes, userId, out IEnumerable<EntityContainer> mediaTypeEntityContainersInstalled),
StylesheetsInstalled = ImportStylesheets(compiledPackage.Stylesheets, userId),
ScriptsInstalled = ImportScripts(compiledPackage.Scripts, userId),
PartialViewsInstalled = ImportPartialViews(compiledPackage.PartialViews, userId)
};

var entityContainersInstalled = new List<EntityContainer>();
entityContainersInstalled.AddRange(dataTypeEntityContainersInstalled);
entityContainersInstalled.AddRange(documentTypeEntityContainersInstalled);
entityContainersInstalled.AddRange(mediaTypeEntityContainersInstalled);
installationSummary.EntityContainersInstalled = entityContainersInstalled;

// We need a reference to the imported doc types to continue
var importedDocTypes = installationSummary.DocumentTypesInstalled.ToDictionary(x => x.Alias, x => x);
var importedMediaTypes = installationSummary.MediaTypesInstalled.ToDictionary(x => x.Alias, x => x);
Expand All @@ -116,14 +122,25 @@ public InstallationSummary InstallPackageData(CompiledPackage compiledPackage, i
return installationSummary;
}
}

/// <summary>
/// Imports and saves package xml as <see cref="IContentType"/>
/// </summary>
/// <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 IReadOnlyList<IMediaType> ImportMediaTypes(IEnumerable<XElement> docTypeElements, int userId)
=> ImportDocumentTypes(docTypeElements.ToList(), true, userId, _mediaTypeService);
=> ImportMediaTypes(docTypeElements, userId, out _);

/// <summary>
/// Imports and saves package xml as <see cref="IContentType"/>
/// </summary>
/// <param name="docTypeElements">Xml to import</param>
/// <param name="userId">Optional id of the User performing the operation. Default is zero (admin).</param>
/// <param name="entityContainersInstalled">Collection of entity containers installed by the package to be populated with those created in installing data types.</param>
/// <returns>An enumerable list of generated ContentTypes</returns>
public IReadOnlyList<IMediaType> ImportMediaTypes(IEnumerable<XElement> docTypeElements, int userId, out IEnumerable<EntityContainer> entityContainersInstalled)
=> ImportDocumentTypes(docTypeElements.ToList(), true, userId, _mediaTypeService, out entityContainersInstalled);

#endregion

Expand Down Expand Up @@ -408,7 +425,7 @@ private TContentBase CreateContent<TContentBase, TContentTypeComposition>(string
#region DocumentTypes

public IReadOnlyList<IContentType> ImportDocumentType(XElement docTypeElement, int userId)
=> ImportDocumentTypes(new[] { docTypeElement }, userId);
=> ImportDocumentTypes(new[] { docTypeElement }, userId, out _);

/// <summary>
/// Imports and saves package xml as <see cref="IContentType"/>
Expand All @@ -417,7 +434,17 @@ public IReadOnlyList<IContentType> ImportDocumentType(XElement docTypeElement, i
/// <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 IReadOnlyList<IContentType> ImportDocumentTypes(IEnumerable<XElement> docTypeElements, int userId)
=> ImportDocumentTypes(docTypeElements.ToList(), true, userId, _contentTypeService);
=> ImportDocumentTypes(docTypeElements.ToList(), true, userId, _contentTypeService, out _);

/// <summary>
/// Imports and saves package xml as <see cref="IContentType"/>
/// </summary>
/// <param name="docTypeElements">Xml to import</param>
/// <param name="userId">Optional id of the User performing the operation. Default is zero (admin).</param>
/// <param name="entityContainersInstalled">Collection of entity containers installed by the package to be populated with those created in installing data types.</param>
/// <returns>An enumerable list of generated ContentTypes</returns>
public IReadOnlyList<IContentType> ImportDocumentTypes(IEnumerable<XElement> docTypeElements, int userId, out IEnumerable<EntityContainer> entityContainersInstalled)
=> ImportDocumentTypes(docTypeElements.ToList(), true, userId, _contentTypeService, out entityContainersInstalled);

/// <summary>
/// Imports and saves package xml as <see cref="IContentType"/>
Expand All @@ -428,15 +455,28 @@ public IReadOnlyList<IContentType> ImportDocumentTypes(IEnumerable<XElement> doc
/// <returns>An enumerable list of generated ContentTypes</returns>
public IReadOnlyList<T> ImportDocumentTypes<T>(IReadOnlyCollection<XElement> unsortedDocumentTypes, bool importStructure, int userId, IContentTypeBaseService<T> service)
where T : class, IContentTypeComposition
=> ImportDocumentTypes(unsortedDocumentTypes, importStructure, userId, service);

/// <summary>
/// Imports and saves package xml as <see cref="IContentType"/>
/// </summary>
/// <param name="unsortedDocumentTypes">Xml to import</param>
/// <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>
/// <param name="entityContainersInstalled">Collection of entity containers installed by the package to be populated with those created in installing data types.</param>
/// <returns>An enumerable list of generated ContentTypes</returns>
public IReadOnlyList<T> ImportDocumentTypes<T>(IReadOnlyCollection<XElement> unsortedDocumentTypes, bool importStructure, int userId, IContentTypeBaseService<T> service, out IEnumerable<EntityContainer> entityContainersInstalled)
where T : class, IContentTypeComposition
{
var importedContentTypes = new Dictionary<string, T>();
entityContainersInstalled = new List<EntityContainer>();
AndyButland marked this conversation as resolved.
Show resolved Hide resolved

//When you are importing a single doc type we have to assume that the dependencies are already there.
//Otherwise something like uSync won't work.
var graph = new TopoGraph<string, TopoGraph.Node<string, XElement>>(x => x.Key, x => x.Dependencies);
var isSingleDocTypeImport = unsortedDocumentTypes.Count == 1;

var importedFolders = CreateContentTypeFolderStructure(unsortedDocumentTypes);
var importedFolders = CreateContentTypeFolderStructure(unsortedDocumentTypes, out entityContainersInstalled);

if (isSingleDocTypeImport == false)
{
Expand Down Expand Up @@ -532,9 +572,10 @@ public IReadOnlyList<T> ImportDocumentTypes<T>(IReadOnlyCollection<XElement> uns
return list;
}

private Dictionary<string, int> CreateContentTypeFolderStructure(IEnumerable<XElement> unsortedDocumentTypes)
private Dictionary<string, int> CreateContentTypeFolderStructure(IEnumerable<XElement> unsortedDocumentTypes, out IEnumerable<EntityContainer> entityContainersInstalled)
{
var importedFolders = new Dictionary<string, int>();
var trackEntityContainersInstalled = new List<EntityContainer>();
AndyButland marked this conversation as resolved.
Show resolved Hide resolved
foreach (var documentType in unsortedDocumentTypes)
{
var foldersAttribute = documentType.Attribute("Folders");
Expand Down Expand Up @@ -578,8 +619,10 @@ private Dictionary<string, int> CreateContentTypeFolderStructure(IEnumerable<XEl
_logger.LogError(tryCreateFolder.Exception, "Could not create folder: {FolderName}", rootFolder);
throw tryCreateFolder.Exception;
}

var rootFolderId = tryCreateFolder.Result.Entity.Id;
current = _contentTypeService.GetContainer(rootFolderId);
trackEntityContainersInstalled.Add(current);
}

importedFolders.Add(alias, current.Id);
Expand All @@ -589,11 +632,13 @@ private Dictionary<string, int> CreateContentTypeFolderStructure(IEnumerable<XEl
var folderName = WebUtility.UrlDecode(folders[i]);
Guid? folderKey = (folderKeys.Length == folders.Length) ? folderKeys[i] : null;
current = CreateContentTypeChildFolder(folderName, folderKey ?? Guid.NewGuid(), current);
trackEntityContainersInstalled.Add(current);
importedFolders[alias] = current.Id;
}
}
}

entityContainersInstalled = trackEntityContainersInstalled;
return importedFolders;
}

Expand Down Expand Up @@ -1012,10 +1057,20 @@ private T FindContentTypeByAlias<T>(string contentTypeAlias, IContentTypeBaseSer
/// <param name="userId">Optional id of the user</param>
/// <returns>An enumerable list of generated DataTypeDefinitions</returns>
public IReadOnlyList<IDataType> ImportDataTypes(IReadOnlyCollection<XElement> dataTypeElements, int userId)
=> ImportDataTypes(dataTypeElements, userId, out _);

/// <summary>
/// Imports and saves package xml as <see cref="IDataType"/>
/// </summary>
/// <param name="dataTypeElements">Xml to import</param>
/// <param name="userId">Optional id of the user</param>
/// <param name="entityContainersInstalled">Collection of entity containers installed by the package to be populated with those created in installing data types.</param>
/// <returns>An enumerable list of generated DataTypeDefinitions</returns>
public IReadOnlyList<IDataType> ImportDataTypes(IReadOnlyCollection<XElement> dataTypeElements, int userId, out IEnumerable<EntityContainer> entityContainersInstalled)
{
var dataTypes = new List<IDataType>();

var importedFolders = CreateDataTypeFolderStructure(dataTypeElements);
var importedFolders = CreateDataTypeFolderStructure(dataTypeElements, out entityContainersInstalled);

foreach (var dataTypeElement in dataTypeElements)
{
Expand Down Expand Up @@ -1072,9 +1127,10 @@ public IReadOnlyList<IDataType> ImportDataTypes(IReadOnlyCollection<XElement> da
return dataTypes;
}

private Dictionary<string, int> CreateDataTypeFolderStructure(IEnumerable<XElement> datatypeElements)
private Dictionary<string, int> CreateDataTypeFolderStructure(IEnumerable<XElement> datatypeElements, out IEnumerable<EntityContainer> entityContainersInstalled)
{
var importedFolders = new Dictionary<string, int>();
var trackEntityContainersInstalled = new List<EntityContainer>();
AndyButland marked this conversation as resolved.
Show resolved Hide resolved
foreach (var datatypeElement in datatypeElements)
{
var foldersAttribute = datatypeElement.Attribute("Folders");
Expand Down Expand Up @@ -1103,7 +1159,9 @@ private Dictionary<string, int> CreateDataTypeFolderStructure(IEnumerable<XEleme
_logger.LogError(tryCreateFolder.Exception, "Could not create folder: {FolderName}", rootFolder);
throw tryCreateFolder.Exception;
}

current = _dataTypeService.GetContainer(tryCreateFolder.Result.Entity.Id);
trackEntityContainersInstalled.Add(current);
}

importedFolders.Add(name, current.Id);
Expand All @@ -1113,11 +1171,12 @@ private Dictionary<string, int> CreateDataTypeFolderStructure(IEnumerable<XEleme
var folderName = WebUtility.UrlDecode(folders[i]);
Guid? folderKey = (folderKeys.Length == folders.Length) ? folderKeys[i] : null;
current = CreateDataTypeChildFolder(folderName, folderKey ?? Guid.NewGuid(), current);
trackEntityContainersInstalled.Add(current);
importedFolders[name] = current.Id;
}
}
}

entityContainersInstalled = trackEntityContainersInstalled;
return importedFolders;
}

Expand Down