diff --git a/src/Orchard.Web/Modules/Orchard.Packaging/Orchard.Packaging.csproj b/src/Orchard.Web/Modules/Orchard.Packaging/Orchard.Packaging.csproj
index 41fb44184..50846ff2a 100644
--- a/src/Orchard.Web/Modules/Orchard.Packaging/Orchard.Packaging.csproj
+++ b/src/Orchard.Web/Modules/Orchard.Packaging/Orchard.Packaging.csproj
@@ -110,6 +110,7 @@
+
diff --git a/src/Orchard.Web/Modules/Orchard.Packaging/Services/PackageManager.cs b/src/Orchard.Web/Modules/Orchard.Packaging/Services/PackageManager.cs
index 60d3e44cc..03f0bfa41 100644
--- a/src/Orchard.Web/Modules/Orchard.Packaging/Services/PackageManager.cs
+++ b/src/Orchard.Web/Modules/Orchard.Packaging/Services/PackageManager.cs
@@ -5,6 +5,8 @@ using NuGet;
using Orchard.Environment.Extensions;
using Orchard.Environment.Extensions.Folders;
using Orchard.Environment.Extensions.Models;
+using Orchard.Environment.Features;
+using Orchard.Environment.State;
using Orchard.Localization;
using Orchard.Packaging.Models;
@@ -14,14 +16,23 @@ namespace Orchard.Packaging.Services {
private readonly IExtensionManager _extensionManager;
private readonly IPackageBuilder _packageBuilder;
private readonly IPackageInstaller _packageInstaller;
+ private readonly IShellStateManager _shellStateManager;
+ private readonly IFeatureManager _featureManager;
+ private readonly IPackageUninstallHandler _packageUninstallHandler;
public PackageManager(
IExtensionManager extensionManager,
IPackageBuilder packageBuilder,
- IPackageInstaller packageInstaller) {
+ IPackageInstaller packageInstaller,
+ IShellStateManager shellStateManager,
+ IFeatureManager featureManager,
+ IPackageUninstallHandler packageUninstallHandler) {
_extensionManager = extensionManager;
_packageBuilder = packageBuilder;
_packageInstaller = packageInstaller;
+ _shellStateManager = shellStateManager;
+ _featureManager = featureManager;
+ _packageUninstallHandler = packageUninstallHandler;
T = NullLocalizer.Instance;
}
@@ -69,7 +80,30 @@ namespace Orchard.Packaging.Services {
}
public void Uninstall(string packageId, string applicationPath) {
- _packageInstaller.Uninstall(packageId, applicationPath);
+ var extensionToUninstall = _extensionManager.AvailableExtensions()
+ .FirstOrDefault(extension => PackageBuilder.BuildPackageId(extension.Id, extension.ExtensionType) == packageId);
+
+ if (extensionToUninstall == null) {
+ throw new OrchardException(T("There is no extension that has the package ID \"{0}\".", packageId));
+ }
+
+ var featureIdsToUninstall = extensionToUninstall.Features.Select(feature => feature.Id);
+ var shellState = _shellStateManager.GetShellState();
+ var featureStates = shellState.Features.Where(featureState => featureIdsToUninstall.Contains(featureState.Name));
+
+ // This means that no feature from this extension wasn enabled yet, can be uninstalled directly.
+ if (!featureStates.Any()) {
+ _packageUninstallHandler.QueuePackageUninstall(packageId);
+ }
+ else {
+ _featureManager.DisableFeatures(extensionToUninstall.Features.Select(feature => feature.Id), true);
+
+ // Installed state can't be deduced from the shell state changes like for enabled state, so have to
+ // set that explicitly.
+ foreach (var featureState in featureStates) {
+ _shellStateManager.UpdateInstalledState(featureState, Environment.State.Models.ShellFeatureState.State.Falling);
+ }
+ }
}
#endregion
diff --git a/src/Orchard.Web/Modules/Orchard.Packaging/Services/PackageUninstallHandler.cs b/src/Orchard.Web/Modules/Orchard.Packaging/Services/PackageUninstallHandler.cs
new file mode 100644
index 000000000..77fb61a7e
--- /dev/null
+++ b/src/Orchard.Web/Modules/Orchard.Packaging/Services/PackageUninstallHandler.cs
@@ -0,0 +1,84 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Web;
+using Orchard.Environment;
+using Orchard.Environment.Configuration;
+using Orchard.Environment.Descriptor;
+using Orchard.Environment.Extensions.Models;
+using Orchard.Environment.State;
+using Orchard.Events;
+
+namespace Orchard.Packaging.Services {
+ public interface IPackageUninstallHandler : IEventHandler {
+ ///
+ /// Queues a package to be uninstalled after the request is processed.
+ ///
+ /// The textual ID of the package.
+ void QueuePackageUninstall(string packageId);
+
+ ///
+ /// Uninstalls the given package from the system.
+ ///
+ /// The textual ID of the package.
+ void UninstallPackage(string packageId);
+ }
+
+ public class PackageUninstallHandler : IFeatureEventHandler, IPackageUninstallHandler {
+ private readonly ShellSettings _shellSettings;
+ private readonly IShellDescriptorManager _shellDescriptorManager;
+ private readonly IProcessingEngine _processingEngine;
+ private readonly IHostEnvironment _hostEnvironment;
+ private readonly IPackageInstaller _packageInstaller;
+
+ public PackageUninstallHandler(
+ ShellSettings shellSettings,
+ IShellDescriptorManager shellDescriptorManager,
+ IProcessingEngine processingEngine,
+ IHostEnvironment hostEnvironment,
+ IPackageInstaller packageInstaller) {
+ _shellSettings = shellSettings;
+ _shellDescriptorManager = shellDescriptorManager;
+ _processingEngine = processingEngine;
+ _hostEnvironment = hostEnvironment;
+ _packageInstaller = packageInstaller;
+ }
+
+ public void Installing(Feature feature) {
+ }
+
+ public void Installed(Feature feature) {
+ }
+
+ public void Enabling(Feature feature) {
+ }
+
+ public void Enabled(Feature feature) {
+ }
+
+ public void Disabling(Feature feature) {
+ }
+
+ public void Disabled(Feature feature) {
+ }
+
+ public void Uninstalling(Feature feature) {
+ }
+
+ public void Uninstalled(Feature feature) {
+ QueuePackageUninstall(PackageBuilder.BuildPackageId(feature.Descriptor.Extension.Id, feature.Descriptor.Extension.ExtensionType));
+ }
+
+ public void QueuePackageUninstall(string packageId) {
+ _processingEngine.AddTask(
+ _shellSettings,
+ _shellDescriptorManager.GetShellDescriptor(),
+ "IPackageUninstallHandler.UninstallPackage",
+ new Dictionary { { "packageId", packageId } });
+ }
+
+ public void UninstallPackage(string packageId) {
+ _packageInstaller.Uninstall(packageId, _hostEnvironment.MapPath("~/"));
+ }
+ }
+}
\ No newline at end of file