/// <summary> /// SORRY :( I didn't have time to put this in a service somewhere - the old packager did this all manually too /// </summary> /// <param name="pack"></param> protected void PerformUninstall(InstalledPackage pack) { if (pack == null) { throw new ArgumentNullException("pack"); } var refreshCache = false; var removedTemplates = new List <ITemplate>(); var removedMacros = new List <IMacro>(); var removedContentTypes = new List <IContentType>(); var removedDictionaryItems = new List <IDictionaryItem>(); var removedDataTypes = new List <IDataTypeDefinition>(); var removedFiles = new List <string>(); //Uninstall templates foreach (var item in pack.Data.Templates.ToArray()) { int nId; if (int.TryParse(item, out nId) == false) { continue; } var found = Services.FileService.GetTemplate(nId); if (found != null) { removedTemplates.Add(found); ApplicationContext.Services.FileService.DeleteTemplate(found.Alias, Security.GetUserId()); } pack.Data.Templates.Remove(nId.ToString()); } //Uninstall macros foreach (var item in pack.Data.Macros.ToArray()) { int nId; if (int.TryParse(item, out nId) == false) { continue; } var macro = Services.MacroService.GetById(nId); if (macro != null) { removedMacros.Add(macro); Services.MacroService.Delete(macro); } pack.Data.Macros.Remove(nId.ToString()); } //Remove Document Types var contentTypes = new List <IContentType>(); var contentTypeService = Services.ContentTypeService; foreach (var item in pack.Data.Documenttypes.ToArray()) { int nId; if (int.TryParse(item, out nId) == false) { continue; } var contentType = contentTypeService.GetContentType(nId); if (contentType == null) { continue; } contentTypes.Add(contentType); pack.Data.Documenttypes.Remove(nId.ToString(CultureInfo.InvariantCulture)); // refresh content cache when document types are removed refreshCache = true; } //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; removedContentTypes.AddRange(orderedTypes); contentTypeService.Delete(orderedTypes); } //Remove Dictionary items foreach (var item in pack.Data.DictionaryItems.ToArray()) { int nId; if (int.TryParse(item, out nId) == false) { continue; } var di = Services.LocalizationService.GetDictionaryItemById(nId); if (di != null) { removedDictionaryItems.Add(di); Services.LocalizationService.Delete(di); } pack.Data.DictionaryItems.Remove(nId.ToString()); } //Remove Data types foreach (var item in pack.Data.DataTypes.ToArray()) { int nId; if (int.TryParse(item, out nId) == false) { continue; } var dtd = Services.DataTypeService.GetDataTypeDefinitionById(nId); if (dtd != null) { removedDataTypes.Add(dtd); Services.DataTypeService.Delete(dtd); } pack.Data.DataTypes.Remove(nId.ToString()); } pack.Save(); // uninstall actions //TODO: We should probably report errors to the UI!! // This never happened before though, but we should do something now if (pack.Data.Actions.IsNullOrWhiteSpace() == false) { try { var actionsXml = new XmlDocument(); actionsXml.LoadXml("<Actions>" + pack.Data.Actions + "</Actions>"); LogHelper.Debug <PackageInstallController>("executing undo actions: {0}", () => actionsXml.OuterXml); foreach (XmlNode n in actionsXml.DocumentElement.SelectNodes("//Action")) { try { global::umbraco.cms.businesslogic.packager.PackageAction .UndoPackageAction(pack.Data.Name, n.Attributes["alias"].Value, n); } catch (Exception ex) { LogHelper.Error <PackageInstallController>("An error occurred running undo actions", ex); } } } catch (Exception ex) { LogHelper.Error <PackageInstallController>("An error occurred running undo actions", ex); } } //moved remove of files here so custom package actions can still undo //Remove files foreach (var item in pack.Data.Files.ToArray()) { removedFiles.Add(item.GetRelativePath()); //here we need to try to find the file in question as most packages does not support the tilde char var file = IOHelper.FindFile(item); if (file != null) { if (file.StartsWith("/") == false) { file = string.Format("/{0}", file); } var filePath = IOHelper.MapPath(file); if (File.Exists(filePath)) { File.Delete(filePath); } } pack.Data.Files.Remove(file); } pack.Save(); pack.Delete(Security.GetUserId()); // create a summary of what was actually removed, for PackagingService.UninstalledPackage var summary = new UninstallationSummary { MetaData = pack.GetMetaData(), TemplatesUninstalled = removedTemplates, MacrosUninstalled = removedMacros, ContentTypesUninstalled = removedContentTypes, DictionaryItemsUninstalled = removedDictionaryItems, DataTypesUninstalled = removedDataTypes, FilesUninstalled = removedFiles, PackageUninstalled = true }; // trigger the UninstalledPackage event PackagingService.OnUninstalledPackage(new UninstallPackageEventArgs <UninstallationSummary>(summary, false)); //TODO: Legacy - probably not needed if (refreshCache) { library.RefreshContent(); } TreeDefinitionCollection.Instance.ReRegisterTrees(); global::umbraco.BusinessLogic.Actions.Action.ReRegisterActionsAndHandlers(); }