Merge branch 'feature/module-uninstall' into 1.x

This commit is contained in:
Zoltán Lehóczky
2015-01-29 23:06:06 +01:00
12 changed files with 291 additions and 105 deletions

View File

@@ -92,9 +92,13 @@ namespace Orchard.Modules.Controllers {
modules = modules.Skip((pager.Page - 1) * pager.PageSize).Take(pager.PageSize);
}
// This way we can more or less reliably handle this implicit dependency.
var installModules = _featureManager.GetEnabledFeatures().FirstOrDefault(f => f.Id == "PackagingServices") != null;
modules = modules.ToList();
foreach (ModuleEntry moduleEntry in modules) {
moduleEntry.IsRecentlyInstalled = _moduleService.IsRecentlyInstalled(moduleEntry.Descriptor);
moduleEntry.CanUninstall = installModules;
if (_extensionDisplayEventHandler != null) {
foreach (string notification in _extensionDisplayEventHandler.Displaying(moduleEntry.Descriptor, ControllerContext.RequestContext)) {
@@ -103,9 +107,10 @@ namespace Orchard.Modules.Controllers {
}
}
return View(new ModulesIndexViewModel {
Modules = modules,
InstallModules = _featureManager.GetEnabledFeatures().FirstOrDefault(f => f.Id == "PackagingServices") != null,
InstallModules = installModules,
Options = options,
Pager = Shape.Pager(pager).TotalItemCount(totalItemCount)
});

View File

@@ -32,5 +32,10 @@ namespace Orchard.Modules.Models {
/// List of module notifications.
/// </summary>
public List<string> Notifications { get; set; }
/// <summary>
/// Indicates whether the module can be uninstalled by the user.
/// </summary>
public bool CanUninstall { get; set; }
}
}

View File

@@ -17,16 +17,17 @@
</fieldset>
if (Model.InstallModules) {
<span>@Html.ActionLink(T("Install a module from your computer").ToString(), "AddModule", "PackagingServices", new { area = "Orchard.Packaging", returnUrl = HttpContext.Current.Request.RawUrl }, null)</span>
}
<span>@Html.ActionLink(T("Install a module from your computer").ToString(), "AddModule", "PackagingServices", new { area = "Orchard.Packaging", returnUrl = HttpContext.Current.Request.RawUrl }, null)</span>
}
if (Model.Modules.Any()) {
<ul class="contentItems">
@foreach (ModuleEntry module in Model.Modules.OrderBy(m => m.Descriptor.Name)) {
<li>@Display.ModuleEntry(ContentPart: module)</li>
<li>@Display.ModuleEntry(Module: module)</li>
}
</ul>
} else {
}
else {
<p>@T("No modules available").ToString()</p>
}

View File

@@ -6,34 +6,34 @@
}
@using (Html.BeginFormAntiForgeryPost()) {
if (Model.Modules.Any()) {
<ul class="contentItems">
@foreach (var moduleEntry in Model.Modules.OrderBy(m => m.Module.Descriptor.Name)) {
var module = moduleEntry.Module;
var descriptor = module.Descriptor;
<ul class="contentItems">
@foreach (var moduleEntry in Model.Modules.OrderBy(m => m.Module.Descriptor.Name)) {
var module = moduleEntry.Module;
var descriptor = module.Descriptor;
<li>
<div class="summary">
<div class="properties">
<h2>@descriptor.Name<span> - @T("Version: {0}", !string.IsNullOrEmpty(descriptor.Version) ? descriptor.Version : T("1.0").ToString())</span></h2>
<li>
<div class="summary">
<div class="properties">
<h2>@descriptor.Name<span> - @T("Version: {0}", !string.IsNullOrEmpty(descriptor.Version) ? descriptor.Version : T("1.0").ToString())</span></h2>
@*@if (!string.IsNullOrEmpty(descriptor.Description)) {
<p>@descriptor.Description</p>
}*@
@foreach (var recipe in moduleEntry.Recipes) {
<br/>
<div>
<h4>@recipe.Name.CamelFriendly() - @Html.ActionLink(T("Execute").Text, "Recipes", "Admin", new {area = "Orchard.Modules", moduleId = descriptor.Id, name = recipe.Name}, new {itemprop = "UnsafeUrl"})</h4>
<p>@(!string.IsNullOrEmpty(recipe.Description) ? recipe.Description : T("No description").ToString())</p>
</div>
}
</div>
</div>
</li>
}
</ul>
}
else {
<p>@T("No modules available").ToString()</p>
}
@*@if (!string.IsNullOrEmpty(descriptor.Description)) {
<p>@descriptor.Description</p>
}*@
@foreach (var recipe in moduleEntry.Recipes) {
<br />
<div>
<h4>@recipe.Name.CamelFriendly() - @Html.ActionLink(T("Execute").Text, "Recipes", "Admin", new { area = "Orchard.Modules", moduleId = descriptor.Id, name = recipe.Name }, new { itemprop = "UnsafeUrl" })</h4>
<p>@(!string.IsNullOrEmpty(recipe.Description) ? recipe.Description : T("No description").ToString())</p>
</div>
}
</div>
</div>
</li>
}
</ul>
}
else {
<p>@T("No modules available").ToString()</p>
}
}

View File

@@ -2,30 +2,46 @@
@using Orchard.Mvc.Html;
@using Orchard.Modules.ViewModels;
@using Orchard.Environment.Extensions.Models;
@using Orchard.Utility.Extensions;
@{ string moduleClasses = Model.ContentPart.IsRecentlyInstalled ? "recentlyInstalledModule" : string.Empty; }
@{
Script.Require("ShapesBase").AtFoot();
Orchard.Modules.Models.ModuleEntry module = Model.Module;
var moduleClasses = module.IsRecentlyInstalled ? "class=\"recentlyInstalledModule\"" : String.Empty;
}
<div class="summary">
@if (Model.ContentPart.Notifications != null && Model.ContentPart.Notifications.Count > 0) {
<div class="notifications">
@foreach (string notification in Model.ContentPart.Notifications) {
@if (module.Notifications != null && module.Notifications.Count > 0) {
<div class="notifications">
@foreach (var notification in module.Notifications) {
<h5>@Html.Raw(notification)</h5>
}
</div>
}
</div>
}
<div class="properties">
<h2@{ if(!string.IsNullOrEmpty(moduleClasses)) {<text> class="@moduleClasses"</text>}}>@Model.ContentPart.Descriptor.Name<span> - @T("Version: {0}", !string.IsNullOrEmpty(Model.ContentPart.Descriptor.Version) ? Model.ContentPart.Descriptor.Version : T("1.0").ToString())</span></h2>
<h2 @Html.Raw(moduleClasses)>
@module.Descriptor.Name<span> - @T("Version: {0}", !String.IsNullOrEmpty(module.Descriptor.Version) ? module.Descriptor.Version : T("1.0").ToString())</span>
</h2>
@if (!string.IsNullOrEmpty(Model.ContentPart.Descriptor.Description)) {
<p>@Model.ContentPart.Descriptor.Description</p>
@Html.ActionLink(
T("Uninstall").Text,
"UninstallModule",
"PackagingServices",
new { ModuleId = module.Descriptor.Id, ReturnUrl = Request.ToUrlString(), Area = "Orchard.Packaging" },
new { itemprop = "RemoveUrl UnsafeUrl" })
@if (!String.IsNullOrEmpty(module.Descriptor.Description)) {
<p>@module.Descriptor.Description</p>
}
<ul class="pageStatus" style="color:#666; margin:.6em 0 0 0;">
@{ IEnumerable<FeatureDescriptor> features = Model.ContentPart.Descriptor.Features; }
<li>@T("Features: {0}", MvcHtmlString.Create(string.Join(", ", 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(Model.ContentPart.Descriptor.Author) ? Model.ContentPart.Descriptor.Author : T("Unknown").ToString())</li>
<li>&nbsp;&#124;&nbsp;@T("Website: ")
@if (!string.IsNullOrEmpty(Model.ContentPart.Descriptor.WebSite)) { <a href="@Model.ContentPart.Descriptor.WebSite">@Model.ContentPart.Descriptor.WebSite</a> }
@{ var features = module.Descriptor.Features; }
<li>@T("Features: {0}", MvcHtmlString.Create(String.Join(", ", 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.Descriptor.Author) ? module.Descriptor.Author : T("Unknown").ToString())</li>
<li>
&nbsp;&#124;&nbsp;@T("Website: ")
@if (!String.IsNullOrEmpty(module.Descriptor.WebSite)) { <a href="@module.Descriptor.WebSite">@module.Descriptor.WebSite</a> }
else { @T("Unknown").ToString() }
</li>
</ul>

View File

@@ -2,10 +2,12 @@ using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Web.Hosting;
using System.Web.Mvc;
using System.Xml.Linq;
using NuGet;
using Orchard.Environment;
using Orchard.Environment.Configuration;
using Orchard.Environment.Extensions.Models;
using Orchard.FileSystems.AppData;
@@ -33,6 +35,7 @@ namespace Orchard.Packaging.Controllers {
private readonly IPackagingSourceManager _packagingSourceManager;
private readonly IAppDataFolderRoot _appDataFolderRoot;
private readonly IModuleService _moduleService;
private readonly IHostEnvironment _hostEnvironment;
private readonly IRecipeHarvester _recipeHarvester;
private readonly IRecipeManager _recipeManager;
@@ -42,8 +45,9 @@ namespace Orchard.Packaging.Controllers {
IPackagingSourceManager packagingSourceManager,
IAppDataFolderRoot appDataFolderRoot,
IOrchardServices services,
IModuleService moduleService)
: this(shellSettings, packageManager, packagingSourceManager, appDataFolderRoot, services, moduleService, null, null) {
IModuleService moduleService,
IHostEnvironment hostEnvironment)
: this(shellSettings, packageManager, packagingSourceManager, appDataFolderRoot, services, moduleService, hostEnvironment, null, null) {
}
public PackagingServicesController(
@@ -53,6 +57,7 @@ namespace Orchard.Packaging.Controllers {
IAppDataFolderRoot appDataFolderRoot,
IOrchardServices services,
IModuleService moduleService,
IHostEnvironment hostEnvironment,
IRecipeHarvester recipeHarvester,
IRecipeManager recipeManager) {
@@ -60,6 +65,7 @@ namespace Orchard.Packaging.Controllers {
_packageManager = packageManager;
_appDataFolderRoot = appDataFolderRoot;
_moduleService = moduleService;
_hostEnvironment = hostEnvironment;
_recipeHarvester = recipeHarvester;
_recipeManager = recipeManager;
_packagingSourceManager = packagingSourceManager;
@@ -80,14 +86,30 @@ namespace Orchard.Packaging.Controllers {
return View();
}
[HttpPost, ActionName("RemoveTheme")]
public ActionResult RemoveThemePOST(string themeId, string returnUrl, string retryUrl) {
[HttpPost, ActionName("UninstallTheme")]
public ActionResult UninstallThemePost(string themeId, string returnUrl, string retryUrl) {
if (String.IsNullOrEmpty(themeId)) {
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
if (_shellSettings.Name != ShellSettings.DefaultName || !Services.Authorizer.Authorize(StandardPermissions.SiteOwner, T("Not authorized to remove themes")))
return new HttpUnauthorizedResult();
return UninstallPackage(PackageBuilder.BuildPackageId(themeId, DefaultExtensionTypes.Theme), returnUrl, retryUrl);
}
[HttpPost, ActionName("UninstallModule")]
public ActionResult UninstallModulePost(string moduleId, string returnUrl, string retryUrl) {
if (String.IsNullOrEmpty(moduleId)) {
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
if (_shellSettings.Name != ShellSettings.DefaultName || !Services.Authorizer.Authorize(StandardPermissions.SiteOwner, T("Not authorized to remove modules")))
return new HttpUnauthorizedResult();
return UninstallPackage(PackageBuilder.BuildPackageId(moduleId, DefaultExtensionTypes.Module), returnUrl, retryUrl);
}
public ActionResult AddModule(string returnUrl) {
if (_shellSettings.Name != ShellSettings.DefaultName || !Services.Authorizer.Authorize(StandardPermissions.SiteOwner, T("Not authorized to add modules")))
return new HttpUnauthorizedResult();
@@ -105,7 +127,7 @@ namespace Orchard.Packaging.Controllers {
}
try {
PackageInfo packageInfo = _packageManager.Install(packageId, version, source.FeedUrl, HostingEnvironment.MapPath("~/"));
PackageInfo packageInfo = _packageManager.Install(packageId, version, source.FeedUrl, MapAppRoot());
if (DefaultExtensionTypes.IsTheme(packageInfo.ExtensionType)) {
Services.Notifier.Information(T("The theme has been successfully installed. It can be enabled in the \"Themes\" page accessible from the menu."));
@@ -147,7 +169,7 @@ namespace Orchard.Packaging.Controllers {
string fullFileName = Path.Combine(_appDataFolderRoot.RootFolder, Path.GetFileName(httpPostedFileBase.FileName)).Replace(Path.DirectorySeparatorChar, '/');
httpPostedFileBase.SaveAs(fullFileName);
var package = new ZipPackage(fullFileName);
PackageInfo packageInfo = _packageManager.Install(package, _appDataFolderRoot.RootFolder, HostingEnvironment.MapPath("~/"));
PackageInfo packageInfo = _packageManager.Install(package, _appDataFolderRoot.RootFolder, MapAppRoot());
ExtensionDescriptor extensionDescriptor = package.GetExtensionDescriptor(packageInfo.ExtensionType);
System.IO.File.Delete(fullFileName);
@@ -247,20 +269,21 @@ namespace Orchard.Packaging.Controllers {
return Redirect(redirectUrl);
}
public ActionResult UninstallPackage(string id, string returnUrl, string retryUrl) {
if (_shellSettings.Name != ShellSettings.DefaultName || !Services.Authorizer.Authorize(StandardPermissions.SiteOwner, T("Not authorized to uninstall packages")))
return new HttpUnauthorizedResult();
private ActionResult UninstallPackage(string id, string returnUrl, string retryUrl) {
try {
_packageManager.Uninstall(id, HostingEnvironment.MapPath("~/"));
_packageManager.Uninstall(id, MapAppRoot());
}
catch (Exception exception) {
Services.Notifier.Error(T("Uninstall failed: {0}", exception.Message));
return Redirect(retryUrl);
return Redirect(!String.IsNullOrEmpty(retryUrl) ? retryUrl : returnUrl);
}
Services.Notifier.Information(T("Uninstalled package \"{0}\"", id));
return this.RedirectLocal(returnUrl, "~/");
}
private string MapAppRoot() {
return _hostEnvironment.MapPath("~/");
}
}
}

View File

@@ -110,6 +110,7 @@
<Compile Include="Services\PackageInstaller.cs" />
<Compile Include="Services\PackageManager.cs" />
<Compile Include="Models\PackagingEntry.cs" />
<Compile Include="Services\PackageUninstallHandler.cs" />
<Compile Include="Services\PackageUpdateManager.cs" />
<Compile Include="Services\PackagingSourceManager.cs" />
<Compile Include="ViewModels\PackagingAddSourceViewModel.cs" />

View File

@@ -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;
@@ -13,15 +15,24 @@ namespace Orchard.Packaging.Services {
public class PackageManager : IPackageManager {
private readonly IExtensionManager _extensionManager;
private readonly IPackageBuilder _packageBuilder;
private readonly IPackageInstaller _packageExpander;
private readonly IPackageInstaller _packageInstaller;
private readonly IShellStateManager _shellStateManager;
private readonly IFeatureManager _featureManager;
private readonly IPackageUninstallHandler _packageUninstallHandler;
public PackageManager(
IExtensionManager extensionManager,
IPackageBuilder packageBuilder,
IPackageInstaller packageExpander) {
IPackageInstaller packageInstaller,
IShellStateManager shellStateManager,
IFeatureManager featureManager,
IPackageUninstallHandler packageUninstallHandler) {
_extensionManager = extensionManager;
_packageBuilder = packageBuilder;
_packageExpander = packageExpander;
_packageInstaller = packageInstaller;
_shellStateManager = shellStateManager;
_featureManager = featureManager;
_packageUninstallHandler = packageUninstallHandler;
T = NullLocalizer.Instance;
}
@@ -61,15 +72,38 @@ namespace Orchard.Packaging.Services {
}
public PackageInfo Install(IPackage package, string location, string applicationPath) {
return DoInstall(() => _packageExpander.Install(package, location, applicationPath));
return DoInstall(() => _packageInstaller.Install(package, location, applicationPath));
}
public PackageInfo Install(string packageId, string version, string location, string applicationPath) {
return DoInstall(() => _packageExpander.Install(packageId, version, location, applicationPath));
return DoInstall(() => _packageInstaller.Install(packageId, version, location, applicationPath));
}
public void Uninstall(string packageId, string applicationPath) {
_packageExpander.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

View File

@@ -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 {
/// <summary>
/// Queues a package to be uninstalled after the request is processed.
/// </summary>
/// <param name="packageId">The textual ID of the package.</param>
void QueuePackageUninstall(string packageId);
/// <summary>
/// Uninstalls the given package from the system.
/// </summary>
/// <param name="packageId">The textual ID of the package.</param>
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<string, object> { { "packageId", packageId } });
}
public void UninstallPackage(string packageId) {
_packageInstaller.Uninstall(packageId, _hostEnvironment.MapPath("~/"));
}
}
}

View File

@@ -12,25 +12,27 @@
@T("There is no current theme in the application. The built-in theme will be used.")<br />
@Html.ActionLink(T("Install a new Theme").ToString(), "Install")
</p>
} else {
}
else {
<h3 id="currentThemeTitle">@T("Current Theme")</h3>
@Display.ThemeEntry_Current(ContentPart: Model.CurrentTheme)
@Display.ThemeEntry_Current(Theme: Model.CurrentTheme)
}
<div id="installedBar" class="group">
<h3>@T("Available")</h3>
@if (Model.InstallThemes) {
@Html.ActionLink(T("Install a theme from your computer").ToString(), "AddTheme", "PackagingServices", new { area = "Orchard.Packaging", returnUrl = HttpContext.Current.Request.RawUrl }, null)
}
@Html.ActionLink(T("Install a theme from your computer").ToString(), "AddTheme", "PackagingServices", new { area = "Orchard.Packaging", returnUrl = HttpContext.Current.Request.RawUrl }, null)
}
</div>
@if (Model.Themes == null || Model.Themes.Count() <= 0) {
<p>@T("There are no additional themes installed.")</p>
} else {
}
else {
<ul class="templates">
@foreach (ThemeEntry themeEntry in Model.Themes) {
<li>@Display.ThemeEntry(ContentPart: themeEntry)</li>
@foreach (var themeEntry in Model.Themes) {
<li>@Display.ThemeEntry(Theme: themeEntry)</li>
}
</ul>
}

View File

@@ -2,17 +2,23 @@
@using Orchard.Mvc.Html
@using Orchard.Environment.Extensions.Models
@{
Orchard.Themes.Models.ThemeEntry theme = Model.Theme;
}
<div id="currentTheme">
@Html.Image(Href(Html.ThemePath((ExtensionDescriptor)Model.ContentPart.Descriptor, "/Theme.png")), Html.Encode((string)Model.ContentPart.Name), new { @class = "themePreviewImage" })
@Html.Image(Href(Html.ThemePath(theme.Descriptor, "/Theme.png")), Html.Encode(theme.Name), new { @class = "themePreviewImage" })
<div class="details">
<h4>@Model.ContentPart.Name</h4>
<h5>@T("By") @Model.ContentPart.Descriptor.Author<br />
@T("Version:") @Model.ContentPart.Descriptor.Version<br />
@if (Model.ContentPart.Descriptor.WebSite != null) {
<a href="@Model.ContentPart.Descriptor.WebSite">@Model.ContentPart.Descriptor.WebSite</a><br />
}</h5>
<p class="themeInfo">@Model.ContentPart.Descriptor.Description</p>
<h4>@theme.Name</h4>
<h5>
@T("By") @theme.Descriptor.Author<br />
@T("Version:") @theme.Descriptor.Version<br />
@if (theme.Descriptor.WebSite != null) {
<a href="@theme.Descriptor.WebSite">@theme.Descriptor.WebSite</a><br />
}
</h5>
<p class="themeInfo">@theme.Descriptor.Description</p>
</div>
</div>

View File

@@ -1,65 +1,74 @@
@using Orchard.Themes.Models
@using Orchard.Mvc.Html
@using Orchard.Environment.Extensions.Models
@using Orchard.Utility.Extensions;
@{ string themeClasses = Model.ContentPart.IsRecentlyInstalled ? "recentlyInstalledTheme" : string.Empty; }
@{
Script.Require("ShapesBase").AtFoot();
Orchard.Themes.Models.ThemeEntry theme = Model.Theme;
var themeClasses = theme.IsRecentlyInstalled ? "class=\"recentlyInstalledTheme\"" : String.Empty;
}
<div>
<h3@{ if(!string.IsNullOrEmpty(themeClasses)) {<text> class="@themeClasses"</text>}}>@Model.ContentPart.Name</h3>
<h3 @Html.Raw(themeClasses)>@theme.Name</h3>
@Html.Image(Href(Html.ThemePath((ExtensionDescriptor) Model.ContentPart.Descriptor, "/Theme.png")), Html.Encode((string)Model.ContentPart.Name), null)
@Html.Image(Href(Html.ThemePath((ExtensionDescriptor)theme.Descriptor, "/Theme.png")), Html.Encode((string)theme.Name), null)
@using (Html.BeginFormAntiForgeryPost(Url.Action("Activate"), FormMethod.Post, new { @class = "inline" })) {
@Html.Hidden("themeId", (string)Model.ContentPart.Descriptor.Id)
@Html.Hidden("themeId", (string)theme.Descriptor.Id)
<button type="submit" title="@T("Activate")">@T("Set Current")</button>
}
@using (Html.BeginFormAntiForgeryPost(Url.Action("Preview"), FormMethod.Post, new { @class = "inline" })) {
@Html.Hidden("themeId", (string)Model.ContentPart.Descriptor.Id)
@Html.Hidden("themeId", (string)theme.Descriptor.Id)
<button type="submit" title="@T("Preview")">@T("Preview")</button>
}
<p class="themeInfo smallText">
@T("By") @Model.ContentPart.Descriptor.Author<br />
@T("Version:") @Model.ContentPart.Descriptor.Version<br />
@Model.ContentPart.Descriptor.Description<br />
@if (Model.ContentPart.Descriptor.WebSite != null) {
<a href="@Model.ContentPart.Descriptor.WebSite">@Model.ContentPart.Descriptor.WebSite</a><br />
@T("By") @theme.Descriptor.Author<br />
@T("Version:") @theme.Descriptor.Version<br />
@theme.Descriptor.Description<br />
@if (theme.Descriptor.WebSite != null) {
<a href="@theme.Descriptor.WebSite">@theme.Descriptor.WebSite</a><br />
}
</p>
@if (Model.ContentPart.Notifications != null && Model.ContentPart.Notifications.Count > 0) {
@if (theme.Notifications != null && theme.Notifications.Count > 0) {
<ul class="notifications">
@foreach (string notification in Model.ContentPart.Notifications) {
<li>@notification</li>
}
@foreach (string notification in theme.Notifications) {
<li>@notification</li>
}
</ul>
}
@if (Model.ContentPart.Enabled) {
@if (theme.Enabled) {
using (Html.BeginFormAntiForgeryPost(Url.Action("Disable"), FormMethod.Post, new { @class = "inline link" })) {
@Html.Hidden("themeId", (string)Model.ContentPart.Descriptor.Id)
@Html.Hidden("themeId", (string)theme.Descriptor.Id)
<button type="submit" class="disable" title="Disable">@T("Disable")</button>
}
}
else {
using (Html.BeginFormAntiForgeryPost(Url.Action("Enable"), FormMethod.Post, new { @class = "inline link" })) {
@Html.Hidden("themeId", (string)Model.ContentPart.Descriptor.Id)
@Html.Hidden("themeId", (string)theme.Descriptor.Id)
<button type="submit" class="enable" title="Enable">@T("Enable")</button>
}
}
@if (Model.ContentPart.NeedsUpdate) {
@if (theme.NeedsUpdate) {
<span> | </span>
using (Html.BeginFormAntiForgeryPost(Url.Action("Update"), FormMethod.Post, new { @class = "inline link" })) {
@Html.Hidden("themeId", (string)Model.ContentPart.Descriptor.Id)
<button type="submit" class="update">@T("Update")</button> <br/>
@Html.Hidden("themeId", (string)theme.Descriptor.Id)
<button type="submit" class="update">@T("Update")</button> <br />
}
}
@if (Model.ContentPart.CanUninstall) {
@if (theme.CanUninstall) {
<span> | </span>
using (Html.BeginFormAntiForgeryPost(Url.Action("RemoveTheme", "PackagingServices", new { area = "Orchard.Packaging", returnUrl = HttpContext.Current.Request.RawUrl, retryUrl = HttpContext.Current.Request.RawUrl, themeId = Model.ContentPart.Descriptor.Id }), FormMethod.Post, new { @class = "inline link" })) {
<button type="submit" class="uninstall" title="@T("Uninstall")">@T("Uninstall")</button>
}
@Html.ActionLink(
T("Uninstall").Text,
"UninstallTheme",
"PackagingServices",
new { ThemeId = theme.Descriptor.Id, ReturnUrl = Request.ToUrlString(), Area = "Orchard.Packaging" },
new { itemprop = "RemoveUrl UnsafeUrl" })
}
</div>