Merge branch 'v13/dev' into v13/feature/extension-model

# Conflicts:
#	src/Umbraco.Cms.Api.Management/Controllers/Package/PackageControllerBase.cs
#	src/Umbraco.Cms.Api.Management/DependencyInjection/PackageBuilderExtensions.cs
#	src/Umbraco.Cms.Api.Management/ManagementApiComposer.cs
#	src/Umbraco.Core/CompatibilitySuppressions.xml
#	src/Umbraco.Infrastructure/CompatibilitySuppressions.xml
#	src/Umbraco.Infrastructure/Serialization/ContextualJsonSerializer.cs
#	src/Umbraco.Web.BackOffice/CompatibilitySuppressions.xml
This commit is contained in:
kjac
2023-02-23 15:28:44 +01:00
282 changed files with 9387 additions and 1597 deletions

View File

@@ -1,11 +1,17 @@
using System.Xml.Linq;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.FileProviders;
using Microsoft.Extensions.Hosting;
using Umbraco.Cms.Core.DependencyInjection;
using Umbraco.Cms.Core.Events;
using Umbraco.Cms.Core.Manifest;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Models.Packaging;
using Umbraco.Cms.Core.Notifications;
using Umbraco.Cms.Core.Packaging;
using Umbraco.Cms.Core.Services.OperationStatus;
using Umbraco.Extensions;
using Umbraco.New.Cms.Core.Models;
using File = System.IO.File;
namespace Umbraco.Cms.Core.Services.Implement;
@@ -23,6 +29,7 @@ public class PackagingService : IPackagingService
private readonly ILegacyManifestParser _legacyManifestParser;
private readonly IPackageInstallation _packageInstallation;
private readonly PackageMigrationPlanCollection _packageMigrationPlans;
private readonly IHostEnvironment _hostEnvironment;
public PackagingService(
IAuditService auditService,
@@ -31,7 +38,8 @@ public class PackagingService : IPackagingService
IEventAggregator eventAggregator,
ILegacyManifestParser legacyManifestParser,
IKeyValueService keyValueService,
PackageMigrationPlanCollection packageMigrationPlans)
PackageMigrationPlanCollection packageMigrationPlans,
IHostEnvironment hostEnvironment)
{
_auditService = auditService;
_createdPackages = createdPackages;
@@ -40,6 +48,28 @@ public class PackagingService : IPackagingService
_legacyManifestParser = legacyManifestParser;
_keyValueService = keyValueService;
_packageMigrationPlans = packageMigrationPlans;
_hostEnvironment = hostEnvironment;
}
[Obsolete("Use constructor that also takes an IHostEnvironment instead. Scheduled for removal in V15")]
public PackagingService(
IAuditService auditService,
ICreatedPackagesRepository createdPackages,
IPackageInstallation packageInstallation,
IEventAggregator eventAggregator,
IManifestParser manifestParser,
IKeyValueService keyValueService,
PackageMigrationPlanCollection packageMigrationPlans)
: this(
auditService,
createdPackages,
packageInstallation,
eventAggregator,
manifestParser,
keyValueService,
packageMigrationPlans,
StaticServiceProvider.Instance.GetRequiredService<IHostEnvironment>())
{
}
#region Installation
@@ -91,24 +121,70 @@ public class PackagingService : IPackagingService
#region Created/Installed Package Repositories
[Obsolete("Use DeleteCreatedPackageAsync instead. Scheduled for removal in Umbraco 15.")]
public void DeleteCreatedPackage(int id, int userId = Constants.Security.SuperUserId)
{
PackageDefinition? package = GetCreatedPackageById(id);
Guid key = package?.PackageId ?? Guid.Empty;
DeleteCreatedPackageAsync(key, userId).GetAwaiter().GetResult();
}
/// <inheritdoc/>
public async Task<Attempt<PackageDefinition?, PackageOperationStatus>> DeleteCreatedPackageAsync(Guid key, int userId = Constants.Security.SuperUserId)
{
PackageDefinition? package = await GetCreatedPackageByKeyAsync(key);
if (package == null)
{
return;
return Attempt.FailWithStatus<PackageDefinition?, PackageOperationStatus>(PackageOperationStatus.NotFound, null);
}
_auditService.Add(AuditType.PackagerUninstall, userId, -1, "Package", $"Created package '{package.Name}' deleted. Package id: {package.Id}");
_createdPackages.Delete(id);
_auditService.Add(AuditType.Delete, userId, -1, "Package", $"Created package '{package.Name}' deleted. Package key: {key}");
_createdPackages.Delete(package.Id);
return Attempt.SucceedWithStatus<PackageDefinition?, PackageOperationStatus>(PackageOperationStatus.Success, package);
}
public IEnumerable<PackageDefinition?> GetAllCreatedPackages() => _createdPackages.GetAll();
public PackageDefinition? GetCreatedPackageById(int id) => _createdPackages.GetById(id);
/// <inheritdoc/>
public Task<PackageDefinition?> GetCreatedPackageByKeyAsync(Guid key) => Task.FromResult(_createdPackages.GetByKey(key));
[Obsolete("Use CreateCreatedPackageAsync or UpdateCreatedPackageAsync instead. Scheduled for removal in Umbraco 15.")]
public bool SaveCreatedPackage(PackageDefinition definition) => _createdPackages.SavePackage(definition);
/// <inheritdoc/>
public async Task<Attempt<PackageDefinition, PackageOperationStatus>> CreateCreatedPackageAsync(PackageDefinition package, int userId)
{
if (_createdPackages.SavePackage(package) == false)
{
if (string.IsNullOrEmpty(package.Name))
{
return Attempt.FailWithStatus(PackageOperationStatus.InvalidName, package);
}
return Attempt.FailWithStatus(PackageOperationStatus.DuplicateItemName, package);
}
_auditService.Add(AuditType.New, userId, -1, "Package", $"Created package '{package.Name}' created. Package key: {package.PackageId}");
return await Task.FromResult(Attempt.SucceedWithStatus(PackageOperationStatus.Success, package));
}
/// <inheritdoc/>
public async Task<Attempt<PackageDefinition, PackageOperationStatus>> UpdateCreatedPackageAsync(PackageDefinition package, int userId)
{
if (_createdPackages.SavePackage(package) == false)
{
return Attempt.FailWithStatus(PackageOperationStatus.NotFound, package);
}
_auditService.Add(AuditType.New, userId, -1, "Package", $"Created package '{package.Name}' updated. Package key: {package.PackageId}");
return await Task.FromResult(Attempt.SucceedWithStatus(PackageOperationStatus.Success, package));
}
public string ExportCreatedPackage(PackageDefinition definition) => _createdPackages.ExportPackage(definition);
public InstalledPackage? GetInstalledPackageByName(string packageName)
@@ -116,36 +192,11 @@ public class PackagingService : IPackagingService
public IEnumerable<InstalledPackage> GetAllInstalledPackages()
{
IReadOnlyDictionary<string, string?>? keyValues =
_keyValueService.FindByKeyPrefix(Constants.Conventions.Migrations.KeyValuePrefix);
var installedPackages = new Dictionary<string, InstalledPackage>();
// Collect the package from the package migration plans
foreach (PackageMigrationPlan plan in _packageMigrationPlans)
{
if (!installedPackages.TryGetValue(plan.PackageName, out InstalledPackage? installedPackage))
{
installedPackage = new InstalledPackage { PackageName = plan.PackageName };
installedPackages.Add(plan.PackageName, installedPackage);
}
var currentPlans = installedPackage.PackageMigrationPlans.ToList();
if (keyValues is null || keyValues.TryGetValue(
Constants.Conventions.Migrations.KeyValuePrefix + plan.Name,
out var currentState) is false)
{
currentState = null;
}
currentPlans.Add(new InstalledPackageMigrationPlans
{
CurrentMigrationId = currentState,
FinalMigrationId = plan.FinalState,
});
installedPackage.PackageMigrationPlans = currentPlans;
}
// Collect the packages from the package migration plans
var installedPackages = GetInstalledPackagesFromMigrationPlansAsync(0, int.MaxValue)
.GetAwaiter()
.GetResult()
.Items.ToDictionary(package => package.PackageName!, package => package); // PackageName cannot be null here
// Collect and merge the packages from the manifests
foreach (LegacyPackageManifest package in _legacyManifestParser.GetManifests())
@@ -157,7 +208,8 @@ public class PackagingService : IPackagingService
if (!installedPackages.TryGetValue(package.PackageName, out InstalledPackage? installedPackage))
{
installedPackage = new InstalledPackage {
installedPackage = new InstalledPackage
{
PackageName = package.PackageName,
Version = string.IsNullOrEmpty(package.Version) ? "Unknown" : package.Version,
};
@@ -173,4 +225,55 @@ public class PackagingService : IPackagingService
}
#endregion
/// <inheritdoc/>
public async Task<PagedModel<InstalledPackage>> GetInstalledPackagesFromMigrationPlansAsync(int skip, int take)
{
IReadOnlyDictionary<string, string?>? keyValues =
_keyValueService.FindByKeyPrefix(Constants.Conventions.Migrations.KeyValuePrefix);
InstalledPackage[] installedPackages = _packageMigrationPlans
.GroupBy(plan => plan.PackageName)
.Select(group =>
{
var package = new InstalledPackage
{
PackageName = group.Key,
};
var currentState = keyValues?
.GetValueOrDefault(Constants.Conventions.Migrations.KeyValuePrefix + package.PackageName);
package.PackageMigrationPlans = group
.Select(plan => new InstalledPackageMigrationPlans
{
CurrentMigrationId = currentState,
FinalMigrationId = plan.FinalState,
});
return package;
}).ToArray();
return await Task.FromResult(new PagedModel<InstalledPackage>
{
Total = installedPackages.Count(),
Items = installedPackages.Skip(skip).Take(take),
});
}
/// <inheritdoc/>
public Stream? GetPackageFileStream(PackageDefinition definition)
{
// Removing the ContentRootPath from the package path as a sub path is required for GetFileInfo()
var subPath = definition.PackagePath.Replace(_hostEnvironment.ContentRootPath, string.Empty);
IFileInfo packageFile = _hostEnvironment.ContentRootFileProvider.GetFileInfo(subPath);
if (packageFile.Exists == false)
{
return null;
}
return packageFile.CreateReadStream();
}
}