#16841, #16495: Fixing theme installation.

--HG--
branch : dev
This commit is contained in:
Andre Rodrigues
2010-12-02 15:27:00 -08:00
parent 625ad33476
commit 6789e39370
7 changed files with 138 additions and 74 deletions

View File

@@ -24,7 +24,7 @@
<p>@module.Description</p>}
<ul class="pageStatus" style="color:#666; margin:.6em 0 0 0;">
<li>@T("Features: {0}", MvcHtmlString.Create(string.Join(", ", module.Features.Select(f => Html.Link(string.IsNullOrEmpty(f.Name) ? f.Id : f.Name, string.Format("{0}#{1}", Url.Action("features", new { area = "Orchard.Modules" }), f.Id.AsFeatureId(n => T(n)))).ToString()).OrderBy(s => s).ToArray())))</li>
<li>&nbsp;&#124;&nbsp;@T("Author: {0}", !string.IsNullOrEmpty(module.Author) ? module.Author : "Unknown")</li>
<li>&nbsp;&#124;&nbsp;@T("Author: {0}", !string.IsNullOrEmpty(module.Author) ? module.Author : T("Unknown").ToString())</li>
<li>&nbsp;&#124;&nbsp;@T("Website: {0}", !string.IsNullOrEmpty(module.WebSite) ? module.WebSite : "http://orchardproject.net")</li>
</ul>
</div>

View File

@@ -6,6 +6,7 @@ using System.Web.Hosting;
using System.Web.Mvc;
using System.Xml.Linq;
using NuGet;
using Orchard.Environment;
using Orchard.Environment.Extensions;
using Orchard.FileSystems.AppData;
using Orchard.Localization;
@@ -25,16 +26,19 @@ namespace Orchard.Packaging.Controllers {
private readonly IPackagingSourceManager _packagingSourceManager;
private readonly IAppDataFolderRoot _appDataFolderRoot;
private readonly INotifier _notifier;
private readonly IHostEnvironment _hostEnvironment;
public GalleryController(
IPackageManager packageManager,
IPackagingSourceManager packagingSourceManager,
INotifier notifier,
IAppDataFolderRoot appDataFolderRoot) {
IAppDataFolderRoot appDataFolderRoot,
IHostEnvironment hostEnvironment) {
_packageManager = packageManager;
_packagingSourceManager = packagingSourceManager;
_notifier = notifier;
_appDataFolderRoot = appDataFolderRoot;
_hostEnvironment = hostEnvironment;
T = NullLocalizer.Instance;
}
@@ -60,12 +64,11 @@ namespace Orchard.Packaging.Controllers {
[HttpPost]
public ActionResult AddSource(string url) {
try {
if ( !String.IsNullOrEmpty(url) ) {
if (!String.IsNullOrEmpty(url)) {
if (!url.StartsWith("http")) {
ModelState.AddModelError("Url", T("The Url is not valid").Text);
}
}
else if ( String.IsNullOrWhiteSpace(url)) {
} else if (String.IsNullOrWhiteSpace(url)) {
ModelState.AddModelError("Url", T("Url is required").Text);
}
@@ -73,29 +76,27 @@ namespace Orchard.Packaging.Controllers {
// try to load the feed
try {
XNamespace atomns = "http://www.w3.org/2005/Atom" ;
XNamespace atomns = "http://www.w3.org/2005/Atom";
var feed = XDocument.Load(url, LoadOptions.PreserveWhitespace);
var titleNode = feed.Descendants(atomns + "title").FirstOrDefault();
if ( titleNode != null )
if (titleNode != null)
title = titleNode.Value;
if(String.IsNullOrWhiteSpace(title)) {
if (String.IsNullOrWhiteSpace(title)) {
ModelState.AddModelError("Url", T("The feed has no title.").Text);
}
}
catch {
} catch {
ModelState.AddModelError("Url", T("The url of the feed or its content is not valid.").Text);
}
if ( !ModelState.IsValid )
if (!ModelState.IsValid)
return View(new PackagingAddSourceViewModel { Url = url });
_packagingSourceManager.AddSource(title, url);
_notifier.Information(T("The feed has been added successfully."));
return RedirectToAction("Sources");
}
catch ( Exception exception ) {
} catch (Exception exception) {
_notifier.Error(T("Adding feed failed: {0}", exception.Message));
return View(new PackagingAddSourceViewModel { Url = url });
}
@@ -104,8 +105,8 @@ namespace Orchard.Packaging.Controllers {
public ActionResult Modules(int? sourceId) {
var selectedSource = _packagingSourceManager.GetSources().Where(s => s.Id == sourceId).FirstOrDefault();
var sources = selectedSource != null
? new [] { selectedSource }
var sources = selectedSource != null
? new[] { selectedSource }
: _packagingSourceManager.GetSources()
;
@@ -134,7 +135,7 @@ namespace Orchard.Packaging.Controllers {
public ActionResult Install(string packageId, string version, int sourceId, string redirectTo) {
var source = _packagingSourceManager.GetSources().Where(s => s.Id == sourceId).FirstOrDefault();
if(source == null) {
if (source == null) {
return HttpNotFound();
}
@@ -147,15 +148,30 @@ namespace Orchard.Packaging.Controllers {
return View();
}
[HttpPost, ActionName("AddTheme")]
public ActionResult AddThemePOST(string returnUrl) {
return InstallPackage(returnUrl, Request.RawUrl);
}
[HttpPost, ActionName("RemoveTheme")]
public ActionResult RemoveThemePOST(string themeId, string returnUrl, string retryUrl) {
return UninstallPackage(PackagingSourceManager.ThemesFilter + themeId, returnUrl, retryUrl);
}
public ActionResult AddModule(string returnUrl) {
return View();
}
[HttpPost, ActionName("AddModule")]
public ActionResult AddModulePOST(string returnUrl) {
// module not used for anything o2ther than display (and that only to not have object in the view 'T')
return InstallPackage(returnUrl, Request.RawUrl);
}
public ActionResult InstallPackage(string returnUrl, string retryUrl) {
try {
if (string.IsNullOrWhiteSpace(Request.Files[0].FileName)) {
if (Request.Files != null &&
Request.Files.Count > 0 &&
!string.IsNullOrWhiteSpace(Request.Files[0].FileName)) {
ModelState.AddModelError("File", T("Select a file to upload.").ToString());
}
@@ -172,16 +188,29 @@ namespace Orchard.Packaging.Controllers {
}
}
if (!string.IsNullOrEmpty(returnUrl))
return Redirect(returnUrl);
return RedirectToAction("Modules");
return Redirect(returnUrl);
} catch (Exception exception) {
for (var scan = exception; scan != null; scan = scan.InnerException) {
for (Exception scan = exception; scan != null; scan = scan.InnerException) {
_notifier.Error(T("Uploading module package failed: {0}", exception.Message));
}
return View("AddModule");
return Redirect(retryUrl);
}
}
public ActionResult UninstallPackage(string id, string returnUrl, string retryUrl) {
try {
_packageManager.Uninstall(id, HostingEnvironment.MapPath("~/"));
_notifier.Information(T("Uninstalled package \"{0}\"", id));
return Redirect(returnUrl);
} catch (Exception exception) {
for (Exception scan = exception; scan != null; scan = scan.InnerException) {
_notifier.Error(T("Uninstall failed: {0}", exception.Message));
}
return Redirect(retryUrl);
}
}
}

View File

@@ -1,9 +1,9 @@
using System;
using System.IO;
using System.Web.Hosting;
using NuGet;
using Orchard.Environment.Extensions;
using Orchard.Environment.Extensions.Models;
using Orchard.FileSystems.AppData;
using Orchard.Localization;
using Orchard.UI.Notify;
using NuGetPackageManager = NuGet.PackageManager;
@@ -12,17 +12,15 @@ namespace Orchard.Packaging.Services {
[OrchardFeature("PackagingServices")]
public class PackageInstaller : IPackageInstaller {
private const string PackagesPath = "packages";
private const string SolutionFilename = "Orchard.sln";
private readonly INotifier _notifier;
private readonly IExtensionManager _extensionManager;
private readonly IAppDataFolderRoot _appDataFolderRoot;
public PackageInstaller(INotifier notifier,
IExtensionManager extensionManager,
IAppDataFolderRoot appDataFolderRoot) {
IExtensionManager extensionManager) {
_notifier = notifier;
_extensionManager = extensionManager;
_appDataFolderRoot = appDataFolderRoot;
T = NullLocalizer.Instance;
}
@@ -57,22 +55,23 @@ namespace Orchard.Packaging.Services {
bool installed = false;
// if we can access the parent directory, and the solution is inside, NuGet-install the package here
var installedPackagesPath = Path.Combine(_appDataFolderRoot.RootFolder, PackagesPath);
try
{
var packageManager = new NuGetPackageManager(
string solutionPath;
var installedPackagesPath = String.Empty;
if (TryGetSolutionPath(applicationPath, out solutionPath)) {
installedPackagesPath = Path.Combine(solutionPath, PackagesPath);
try {
var packageManager = new NuGetPackageManager(
packageRepository,
new DefaultPackagePathResolver(location),
new PhysicalFileSystem(installedPackagesPath) { Logger = logger }
) { Logger = logger };
new PhysicalFileSystem(installedPackagesPath) {Logger = logger}
) {Logger = logger};
packageManager.InstallPackage(package, ignoreDependencies: true);
installed = true;
}
catch
{
// installing the package in the appdata folder failed
packageManager.InstallPackage(package, true);
installed = true;
}
catch {
// installing the package at the solution level failed
}
}
// if the package got installed successfully, use it, otherwise use the previous repository
@@ -95,7 +94,7 @@ namespace Orchard.Packaging.Services {
{
ExtensionName = package.Title ?? package.Id,
ExtensionVersion = package.Version.ToString(),
ExtensionType = package.Id.StartsWith("Orchard.Theme") ? DefaultExtensionTypes.Theme : DefaultExtensionTypes.Module,
ExtensionType = package.Id.StartsWith(PackagingSourceManager.ThemesFilter) ? DefaultExtensionTypes.Theme : DefaultExtensionTypes.Module,
ExtensionPath = applicationPath
};
}
@@ -104,26 +103,58 @@ namespace Orchard.Packaging.Services {
// this logger is used to render NuGet's log on the notifier
var logger = new NugetLogger(_notifier);
var installedPackagesPath = Path.Combine(_appDataFolderRoot.RootFolder, PackagesPath);
var sourcePackageRepository = new LocalPackageRepository(installedPackagesPath);
var project = new FileBasedProjectSystem(applicationPath) { Logger = logger };
var projectManager = new ProjectManager(
sourcePackageRepository,
new DefaultPackagePathResolver(installedPackagesPath),
project,
new ExtensionReferenceRepository(project, sourcePackageRepository, _extensionManager)
) { Logger = logger };
string solutionPath;
// if we can access the parent directory, and the solution is inside, NuGet-uninstall the package here
if (TryGetSolutionPath(applicationPath, out solutionPath)) {
var installedPackagesPath = Path.Combine(solutionPath, PackagesPath);
var sourcePackageRepository = new LocalPackageRepository(installedPackagesPath);
var project = new FileBasedProjectSystem(applicationPath) { Logger = logger };
var projectManager = new ProjectManager(
sourcePackageRepository,
new DefaultPackagePathResolver(installedPackagesPath),
project,
new ExtensionReferenceRepository(project, sourcePackageRepository, _extensionManager)
) { Logger = logger };
// add the package to the project
projectManager.RemovePackageReference(packageId);
// add the package to the project
projectManager.RemovePackageReference(packageId);
var packageManager = new NuGetPackageManager(
var packageManager = new NuGetPackageManager(
sourcePackageRepository,
new DefaultPackagePathResolver(applicationPath),
new PhysicalFileSystem(installedPackagesPath) { Logger = logger }
) { Logger = logger };
) { Logger = logger };
packageManager.UninstallPackage(packageId);
packageManager.UninstallPackage(packageId);
} else {
// otherwise delete the folder
string extensionPath = packageId.StartsWith(PackagingSourceManager.ThemesFilter)
? "~/Themes/" + packageId.Substring(PackagingSourceManager.ThemesFilter.Length)
: "~/Modules/" + packageId.Substring(PackagingSourceManager.ModulesFilter.Length);
string extensionFullPath = HostingEnvironment.MapPath(extensionPath);
if (Directory.Exists(extensionFullPath)) {
Directory.Delete(extensionFullPath, true);
}
else {
throw new OrchardException(T("Package not found: ", packageId));
}
}
}
private bool TryGetSolutionPath(string applicationPath, out string parentPath) {
try {
parentPath = Directory.GetParent(applicationPath).Parent.FullName;
var solutionPath = Path.Combine(parentPath, SolutionFilename);
return File.Exists(solutionPath);
}
catch {
// Either solution does not exist or we are running under medium trust
parentPath = null;
return false;
}
}
}
}

View File

@@ -46,6 +46,7 @@ namespace Orchard.Packaging.Services {
public void Uninstall(string packageId, string applicationPath) {
_packageExpander.Uninstall(packageId, applicationPath);
}
#endregion
}
}

View File

@@ -10,8 +10,8 @@ using Orchard.Packaging.Models;
namespace Orchard.Packaging.Services {
[OrchardFeature("Gallery")]
public class PackagingSourceManager : IPackagingSourceManager {
private const string ModulesFilter = "Orchard.Module.";
private const string ThemesFilter = "Orchard.Theme.";
public const string ModulesFilter = "Orchard.Module.";
public const string ThemesFilter = "Orchard.Theme.";
private readonly IRepository<PackagingSource> _packagingSourceRecordRepository;

View File

@@ -1,10 +1,11 @@
<h1>@Html.TitleForPage(T("Install Theme").ToString())</h1>
@using (Html.BeginForm("Install", "Admin", FormMethod.Post, new { enctype = "multipart/form-data" })) {
@Html.ValidationSummary()
<fieldset>
<label for="ThemeZipPath">@T("File Path to the zip file:")</label>
<input id="ThemeZipPath" name="ThemeZipPath" type="file" class="text" value="@T("Browse")" size="64" /><br />
<button class="primaryAction" type="submit">@T("Install")</button>
@Html.AntiForgeryTokenOrchard()
</fieldset>
}
@{
<h1>@Html.TitleForPage(T("Install a Theme").ToString())</h1>
using (Html.BeginFormAntiForgeryPost(Url.Action("AddTheme", new { area = "Orchard.Gallery" }), FormMethod.Post, new { enctype = "multipart/form-data" })) {
Html.ValidationSummary();
<fieldset>
<label for="ModulePackage">@T("Theme Package")</label>
<input type="file" id="ThemePackage" size="64" name="ThemePackage" />
</fieldset>
<button type="submit" class="primaryAction">@T("Install")</button>
}
}

View File

@@ -19,7 +19,7 @@
</p>
if (Model.InstallThemes) {
@Html.ActionLink(T("Install a new Theme").ToString(), "Install", null, new { @class = "button primaryAction" })
@Html.ActionLink(T("Install a new Theme").ToString(), "AddTheme", "Gallery", new { area = "Orchard.Packaging", returnUrl = HttpContext.Current.Request.RawUrl }, new { @class = "button primaryAction" })
}
}
@@ -55,11 +55,13 @@
<button type="submit" class="update">@T("Update")</button> <br/>
}
}
@using (Html.BeginFormAntiForgeryPost(Url.Action("Uninstall"), FormMethod.Post, new { @class = "inline link" })) {
@Html.Hidden("themeName", theme.Id)
<button type="submit" class="uninstall" title="@T("Uninstall")">@T("Uninstall")</button>
@if (Model.InstallThemes) {
using (Html.BeginFormAntiForgeryPost(Url.Action("RemoveTheme", "Gallery", new { area = "Orchard.Packaging", returnUrl = HttpContext.Current.Request.RawUrl, retryUrl = HttpContext.Current.Request.RawUrl, themeId = theme.Id }), FormMethod.Post, new { @class = "inline link" })) {
<button type="submit" class="uninstall" title="@T("Uninstall")">@T("Uninstall")</button>
}
}
</div>
</div>
</li>
}
}