From b6d0fa3dd216a12051fdd10b9cc69742ad69437c Mon Sep 17 00:00:00 2001 From: Daniel Stolt Date: Tue, 14 Jul 2015 17:43:40 +0100 Subject: [PATCH] Implemented tenant reset action. --- .../Controllers/AdminController.cs | 143 ++++++++++++------ .../Orchard.MultiTenancy.csproj | 12 ++ .../Services/ITenantResetEventHandler.cs | 10 ++ .../Services/ITenantService.cs | 22 ++- .../Services/TenantService.cs | 87 ++++++++++- .../ViewModels/TenantResetViewModel.cs | 17 +++ .../ActionsForDisabled.cshtml | 5 +- .../DisplayTemplates/ActionsForRunning.cshtml | 4 +- .../Views/Admin/Index.cshtml | 45 +++--- .../Views/Admin/Reset.cshtml | 30 ++++ 10 files changed, 291 insertions(+), 84 deletions(-) create mode 100644 src/Orchard.Web/Modules/Orchard.MultiTenancy/Services/ITenantResetEventHandler.cs create mode 100644 src/Orchard.Web/Modules/Orchard.MultiTenancy/ViewModels/TenantResetViewModel.cs create mode 100644 src/Orchard.Web/Modules/Orchard.MultiTenancy/Views/Admin/Reset.cshtml diff --git a/src/Orchard.Web/Modules/Orchard.MultiTenancy/Controllers/AdminController.cs b/src/Orchard.Web/Modules/Orchard.MultiTenancy/Controllers/AdminController.cs index 38d6091b7..fb172f67c 100644 --- a/src/Orchard.Web/Modules/Orchard.MultiTenancy/Controllers/AdminController.cs +++ b/src/Orchard.Web/Modules/Orchard.MultiTenancy/Controllers/AdminController.cs @@ -19,7 +19,7 @@ namespace Orchard.MultiTenancy.Controllers { public AdminController(ITenantService tenantService, IOrchardServices orchardServices, ShellSettings shellSettings) { _tenantService = tenantService; _thisShellSettings = shellSettings; - + Services = orchardServices; T = NullLocalizer.Instance; Logger = NullLogger.Instance; @@ -30,32 +30,34 @@ namespace Orchard.MultiTenancy.Controllers { public ILogger Logger { get; set; } public ActionResult Index() { - return View(new TenantsIndexViewModel { TenantSettings = _tenantService.GetTenants() }); + return View(new TenantsIndexViewModel { + TenantSettings = _tenantService.GetTenants() + }); } public ActionResult Add() { - if (!Services.Authorizer.Authorize(StandardPermissions.SiteOwner, T("Cannot create tenant"))) + if (!Services.Authorizer.Authorize(StandardPermissions.SiteOwner, T("You don't have permission to create tenants."))) return new HttpUnauthorizedResult(); - if ( !EnsureDefaultTenant() ) + if (!IsExecutingInDefaultTenant()) return new HttpUnauthorizedResult(); - var model = new TenantAddViewModel(); + var viewModel = new TenantAddViewModel(); - // fetches all available themes and modules - model.Themes = _tenantService.GetInstalledThemes().Select(x => new ThemeEntry { ThemeId = x.Id, ThemeName = x.Name }).ToList(); - model.Modules = _tenantService.GetInstalledModules().Select(x => new ModuleEntry { ModuleId = x.Id, ModuleName = x.Name }).ToList(); + // Fetches all available themes and modules. + viewModel.Themes = _tenantService.GetInstalledThemes().Select(x => new ThemeEntry { ThemeId = x.Id, ThemeName = x.Name }).ToList(); + viewModel.Modules = _tenantService.GetInstalledModules().Select(x => new ModuleEntry { ModuleId = x.Id, ModuleName = x.Name }).ToList(); - return View(model); + return View(viewModel); } [HttpPost, ActionName("Add")] - public ActionResult AddPOST(TenantAddViewModel viewModel) { - if (!Services.Authorizer.Authorize(StandardPermissions.SiteOwner, T("Couldn't create tenant"))) { + public ActionResult AddPost(TenantAddViewModel viewModel) { + if (!Services.Authorizer.Authorize(StandardPermissions.SiteOwner, T("You don't have permission to create tenants."))) { return new HttpUnauthorizedResult(); } - if (!EnsureDefaultTenant()) { + if (!IsExecutingInDefaultTenant()) { return new HttpUnauthorizedResult(); } @@ -63,7 +65,7 @@ namespace Orchard.MultiTenancy.Controllers { ModelState.AddModelError("Name", T("A tenant with the same name already exists.", viewModel.Name).Text); } - // ensure tenants name are valid + // Ensure tenants name are valid. if (!String.IsNullOrEmpty(viewModel.Name) && !Regex.IsMatch(viewModel.Name, @"^\w+$")) { ModelState.AddModelError("Name", T("Invalid tenant name. Must contain characters only and no spaces.").Text); } @@ -88,56 +90,58 @@ namespace Orchard.MultiTenancy.Controllers { return RedirectToAction("Index"); } - catch (ArgumentException exception) { - Services.Notifier.Error(T("Creating Tenant failed: {0}", exception.Message)); + catch (ArgumentException ex) { + Logger.Error(ex, "Error while creating tenant."); + Services.Notifier.Error(T("Tenant creation failed with error: {0}", ex.Message)); return View(viewModel); } } public ActionResult Edit(string name) { - if (!Services.Authorizer.Authorize(StandardPermissions.SiteOwner, T("Cannot edit tenant"))) + if (!Services.Authorizer.Authorize(StandardPermissions.SiteOwner, T("You don't have permission to edit tenants."))) return new HttpUnauthorizedResult(); - if ( !EnsureDefaultTenant() ) + if (!IsExecutingInDefaultTenant()) return new HttpUnauthorizedResult(); var tenant = _tenantService.GetTenants().FirstOrDefault(ss => ss.Name == name); - if (tenant == null) return HttpNotFound(); return View(new TenantEditViewModel { - Name = tenant.Name, - RequestUrlHost = tenant.RequestUrlHost, - RequestUrlPrefix = tenant.RequestUrlPrefix, - DataProvider = tenant.DataProvider, - DatabaseConnectionString = tenant.DataConnectionString, - DatabaseTablePrefix = tenant.DataTablePrefix, - State = tenant.State, - Themes = _tenantService.GetInstalledThemes().Select(x => new ThemeEntry { - ThemeId = x.Id, - ThemeName = x.Name, - Checked = tenant.Themes.Contains(x.Id) - }).ToList(), - Modules = _tenantService.GetInstalledModules().Select(x => new ModuleEntry { - ModuleId = x.Id, - ModuleName = x.Name, - Checked = tenant.Modules.Contains(x.Id) - }).ToList() - }); + Name = tenant.Name, + RequestUrlHost = tenant.RequestUrlHost, + RequestUrlPrefix = tenant.RequestUrlPrefix, + DataProvider = tenant.DataProvider, + DatabaseConnectionString = tenant.DataConnectionString, + DatabaseTablePrefix = tenant.DataTablePrefix, + State = tenant.State, + Themes = _tenantService.GetInstalledThemes().Select(x => new ThemeEntry { + ThemeId = x.Id, + ThemeName = x.Name, + Checked = tenant.Themes.Contains(x.Id) + }).ToList(), + Modules = _tenantService.GetInstalledModules().Select(x => new ModuleEntry { + ModuleId = x.Id, + ModuleName = x.Name, + Checked = tenant.Modules.Contains(x.Id) + }).ToList() + }); } [HttpPost, ActionName("Edit")] public ActionResult EditPost(TenantEditViewModel viewModel) { - if (!Services.Authorizer.Authorize(StandardPermissions.SiteOwner, T("Couldn't edit tenant"))) + if (!Services.Authorizer.Authorize(StandardPermissions.SiteOwner, T("You don't have permission to edit tenants."))) return new HttpUnauthorizedResult(); - if ( !EnsureDefaultTenant() ) + if (!IsExecutingInDefaultTenant()) return new HttpUnauthorizedResult(); var tenant = _tenantService.GetTenants().FirstOrDefault(ss => ss.Name == viewModel.Name); if (tenant == null) return HttpNotFound(); + else if (tenant.Name == _thisShellSettings.Name) + return new HttpUnauthorizedResult(); if (!ModelState.IsValid) { return View(viewModel); @@ -163,18 +167,19 @@ namespace Orchard.MultiTenancy.Controllers { return RedirectToAction("Index"); } - catch (Exception exception) { - Services.Notifier.Error(T("Failed to edit tenant: {0} ", exception.Message)); + catch (Exception ex) { + Logger.Error(ex, "Error while editing tenant."); + Services.Notifier.Error(T("Failed to edit tenant: {0} ", ex.Message)); return View(viewModel); } } [HttpPost] public ActionResult Disable(string name) { - if (!Services.Authorizer.Authorize(StandardPermissions.SiteOwner, T("Couldn't disable tenant"))) + if (!Services.Authorizer.Authorize(StandardPermissions.SiteOwner, T("You don't have permission to disable tenants."))) return new HttpUnauthorizedResult(); - if ( !EnsureDefaultTenant() ) + if (!IsExecutingInDefaultTenant()) return new HttpUnauthorizedResult(); var tenant = _tenantService.GetTenants().FirstOrDefault(ss => ss.Name == name); @@ -189,10 +194,10 @@ namespace Orchard.MultiTenancy.Controllers { [HttpPost] public ActionResult Enable(string name) { - if (!Services.Authorizer.Authorize(StandardPermissions.SiteOwner, T("Couldn't enable tenant"))) + if (!Services.Authorizer.Authorize(StandardPermissions.SiteOwner, T("You don't have permission to enable tenants."))) return new HttpUnauthorizedResult(); - if ( !EnsureDefaultTenant() ) + if (!IsExecutingInDefaultTenant()) return new HttpUnauthorizedResult(); var tenant = _tenantService.GetTenants().FirstOrDefault(ss => ss.Name == name); @@ -205,7 +210,55 @@ namespace Orchard.MultiTenancy.Controllers { return RedirectToAction("Index"); } - private bool EnsureDefaultTenant() { + public ActionResult Reset(string name) { + if (!Services.Authorizer.Authorize(StandardPermissions.SiteOwner, T("You don't have permission to reset tenants."))) + return new HttpUnauthorizedResult(); + + if (!IsExecutingInDefaultTenant()) + return new HttpUnauthorizedResult(); + + var tenant = _tenantService.GetTenants().FirstOrDefault(ss => ss.Name == name); + if (tenant == null) + return HttpNotFound(); + + return View(new TenantResetViewModel() { + Name = name, + DatabaseTableNames = _tenantService.GetTenantDatabaseTableNames(tenant) + }); + } + + [HttpPost, ActionName("Reset")] + public ActionResult ResetPost(TenantResetViewModel viewModel) { + if (!Services.Authorizer.Authorize(StandardPermissions.SiteOwner, T("You don't have permission to reset tenants."))) + return new HttpUnauthorizedResult(); + + if (!IsExecutingInDefaultTenant()) + return new HttpUnauthorizedResult(); + + var tenant = _tenantService.GetTenants().FirstOrDefault(ss => ss.Name == viewModel.Name); + if (tenant == null) + return HttpNotFound(); + else if (tenant.Name == _thisShellSettings.Name) + return new HttpUnauthorizedResult(); + + if (!ModelState.IsValid) { + viewModel.DatabaseTableNames = _tenantService.GetTenantDatabaseTableNames(tenant); + return View(viewModel); + } + + try { + _tenantService.ResetTenant(tenant, viewModel.DropDatabaseTables); + return RedirectToAction("Index"); + } + catch (Exception ex) { + Logger.Error(ex, "Error while resetting tenant."); + Services.Notifier.Error(T("Failed to reset tenant: {0} ", ex.Message)); + viewModel.DatabaseTableNames = _tenantService.GetTenantDatabaseTableNames(tenant); + return View(viewModel); + } + } + + private bool IsExecutingInDefaultTenant() { return _thisShellSettings.Name == ShellSettings.DefaultName; } } diff --git a/src/Orchard.Web/Modules/Orchard.MultiTenancy/Orchard.MultiTenancy.csproj b/src/Orchard.Web/Modules/Orchard.MultiTenancy/Orchard.MultiTenancy.csproj index 46bf0f356..3fc0ac7b3 100644 --- a/src/Orchard.Web/Modules/Orchard.MultiTenancy/Orchard.MultiTenancy.csproj +++ b/src/Orchard.Web/Modules/Orchard.MultiTenancy/Orchard.MultiTenancy.csproj @@ -25,6 +25,7 @@ + true @@ -48,6 +49,12 @@ false + + ..\..\..\..\lib\autofac\Autofac.dll + + + ..\..\..\..\lib\nhibernate\NHibernate.dll + 3.5 @@ -73,9 +80,11 @@ + + @@ -123,6 +132,9 @@ + + + 10.0 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) diff --git a/src/Orchard.Web/Modules/Orchard.MultiTenancy/Services/ITenantResetEventHandler.cs b/src/Orchard.Web/Modules/Orchard.MultiTenancy/Services/ITenantResetEventHandler.cs new file mode 100644 index 000000000..aba7b77a9 --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.MultiTenancy/Services/ITenantResetEventHandler.cs @@ -0,0 +1,10 @@ +using Orchard.Events; + +namespace Orchard.MultiTenancy.Services { + /// + /// An event handler interface that allows implementers to execute code when a tenant is being reset. + /// + public interface ITenantResetEventHandler : IEventHandler { + void Resetting(); + } +} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.MultiTenancy/Services/ITenantService.cs b/src/Orchard.Web/Modules/Orchard.MultiTenancy/Services/ITenantService.cs index 4d0c3366b..d38dcf0b8 100644 --- a/src/Orchard.Web/Modules/Orchard.MultiTenancy/Services/ITenantService.cs +++ b/src/Orchard.Web/Modules/Orchard.MultiTenancy/Services/ITenantService.cs @@ -5,23 +5,35 @@ using Orchard.Environment.Extensions.Models; namespace Orchard.MultiTenancy.Services { public interface ITenantService : IDependency { /// - /// Retrieves all tenants' shell settings. + /// Retrieves ShellSettings objects for all tenants. /// - /// All tenants' shell settings. IEnumerable GetTenants(); /// /// Creates a new tenant. /// - /// Shell settings of the tenant. + /// A ShellSettings object specifying the settings for the new tenant. void CreateTenant(ShellSettings settings); /// - /// Updates the shell settings of a tenant. + /// Updates the settings of a tenant. /// - /// Shell settings of the tenant. + /// The new ShellSettings object for the tenant. void UpdateTenant(ShellSettings settings); + /// + /// Resets a tenant to its uninitialized state. + /// + /// A ShellSettings object for the tenant to reset. + /// A boolean indicated whether tenant database tables should be dropped also. + void ResetTenant(ShellSettings settings, bool dropDatabaseTables); + + /// + /// Returns a list of all known database tables in a tenant. + /// + /// A ShellSettings object for the tenant. + IEnumerable GetTenantDatabaseTableNames(ShellSettings settings); + /// /// Returns a list of all installed themes. /// diff --git a/src/Orchard.Web/Modules/Orchard.MultiTenancy/Services/TenantService.cs b/src/Orchard.Web/Modules/Orchard.MultiTenancy/Services/TenantService.cs index e907b7104..791b161a1 100644 --- a/src/Orchard.Web/Modules/Orchard.MultiTenancy/Services/TenantService.cs +++ b/src/Orchard.Web/Modules/Orchard.MultiTenancy/Services/TenantService.cs @@ -1,21 +1,36 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Linq; using Orchard.Environment.Configuration; using Orchard.Environment.Extensions.Models; using Orchard.Environment.Extensions; +using Orchard.Environment.ShellBuilders; +using Orchard.Data.Migration.Interpreters; +using Orchard.Data.Migration.Schema; +using Orchard.Data; +using Orchard.Logging; namespace Orchard.MultiTenancy.Services { public class TenantService : ITenantService { private readonly IShellSettingsManager _shellSettingsManager; private readonly IExtensionManager _extensionManager; + private readonly IShellContextFactory _shellContextFactory; + private readonly IShellContainerFactory _shellContainerFactory; public TenantService( IShellSettingsManager shellSettingsManager, - IExtensionManager extensionManager) { + IExtensionManager extensionManager, + IShellContextFactory shellContextFactory, + IShellContainerFactory shellContainerFactory) { _shellSettingsManager = shellSettingsManager; _extensionManager = extensionManager; + _shellContextFactory = shellContextFactory; + _shellContainerFactory = shellContainerFactory; + Logger = NullLogger.Instance; } + public ILogger Logger { get; set; } + public IEnumerable GetTenants() { return _shellSettingsManager.LoadSettings(); } @@ -28,16 +43,32 @@ namespace Orchard.MultiTenancy.Services { _shellSettingsManager.SaveSettings(settings); } - /// - /// Loads only installed themes - /// + public void ResetTenant(ShellSettings settings, bool dropDatabaseTables) { + if (settings.State != TenantState.Disabled) + throw new InvalidOperationException(String.Format("Tenant state is '{0}'; must be '{1}' to perform reset action.", settings.State, TenantState.Disabled)); + + ExecuteOnTenantScope(settings, environment => { + ExecuteResetEventHandlers(environment); + if (dropDatabaseTables) + DropTenantDatabaseTables(environment); + }); + + settings.State = TenantState.Uninitialized; + _shellSettingsManager.SaveSettings(settings); + } + + public IEnumerable GetTenantDatabaseTableNames(ShellSettings settings) { + IEnumerable result = null; + ExecuteOnTenantScope(settings, environment => { + result = GetTenantDatabaseTableNames(environment); + }); + return result; + } + public IEnumerable GetInstalledThemes() { return GetThemes(_extensionManager.AvailableExtensions()); } - /// - /// Loads only installed modules - /// public IEnumerable GetInstalledModules() { return _extensionManager.AvailableExtensions().Where(descriptor => DefaultExtensionTypes.IsModule(descriptor.ExtensionType)); } @@ -58,5 +89,45 @@ namespace Orchard.MultiTenancy.Services { } return themes; } + + private void ExecuteOnTenantScope(ShellSettings settings, Action action) { + var shellContext = _shellContextFactory.CreateShellContext(settings); + using (var container = _shellContainerFactory.CreateContainer(shellContext.Settings, shellContext.Blueprint)) { + using (var environment = container.CreateWorkContextScope()) { + action(environment); + } + } + } + + private IEnumerable GetTenantDatabaseTableNames(IWorkContextScope environment) { + var sessionFactoryHolder = environment.Resolve(); + var schemaBuilder = new SchemaBuilder(environment.Resolve()); + var configuration = sessionFactoryHolder.GetConfiguration(); + + var result = + from mapping in configuration.ClassMappings + select mapping.Table.Name; + + return result.ToArray(); + } + + private void DropTenantDatabaseTables(IWorkContextScope environment) { + var sessionFactoryHolder = environment.Resolve(); + var schemaBuilder = new SchemaBuilder(environment.Resolve()); + var configuration = sessionFactoryHolder.GetConfiguration(); + foreach (var mapping in configuration.ClassMappings) { + try { + schemaBuilder.DropTable(mapping.Table.Name); + } + catch (Exception ex) { + Logger.Warning(ex, "Failed to drop table '{0}'.", mapping.Table.Name); + } + } + } + + private void ExecuteResetEventHandlers(IWorkContextScope environment) { + var handler = environment.Resolve(); + handler.Resetting(); + } } } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.MultiTenancy/ViewModels/TenantResetViewModel.cs b/src/Orchard.Web/Modules/Orchard.MultiTenancy/ViewModels/TenantResetViewModel.cs new file mode 100644 index 000000000..6969fa091 --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.MultiTenancy/ViewModels/TenantResetViewModel.cs @@ -0,0 +1,17 @@ +using System.ComponentModel.DataAnnotations; +using System.Collections.Generic; +using System.Linq; + +namespace Orchard.MultiTenancy.ViewModels { + public class TenantResetViewModel { + public TenantResetViewModel() { + DatabaseTableNames = Enumerable.Empty(); + } + + [Required] + public string Name { get; set; } + public bool DropDatabaseTables { get; set; } + public IEnumerable DatabaseTableNames { get; set; } + } +} + diff --git a/src/Orchard.Web/Modules/Orchard.MultiTenancy/Views/Admin/DisplayTemplates/ActionsForDisabled.cshtml b/src/Orchard.Web/Modules/Orchard.MultiTenancy/Views/Admin/DisplayTemplates/ActionsForDisabled.cshtml index 8b8d91eeb..4e3235c45 100644 --- a/src/Orchard.Web/Modules/Orchard.MultiTenancy/Views/Admin/DisplayTemplates/ActionsForDisabled.cshtml +++ b/src/Orchard.Web/Modules/Orchard.MultiTenancy/Views/Admin/DisplayTemplates/ActionsForDisabled.cshtml @@ -1,7 +1,8 @@ @model Orchard.Environment.Configuration.ShellSettings @using Orchard.MultiTenancy.Extensions; -@using(Html.BeginFormAntiForgeryPost(Url.Action("enable", new {area = "Orchard.MultiTenancy"}), FormMethod.Post, new {@class = "inline link"})) { +@using(Html.BeginFormAntiForgeryPost(Url.Action("Enable", new {area = "Orchard.MultiTenancy"}), FormMethod.Post, new {@class = "inline link"})) { @Html.HiddenFor(ss => ss.Name) -} +} @T(" | ") +@Html.ActionLink(T("Reset").ToString(), "Reset", new { name = Model.Name, area = "Orchard.MultiTenancy" }) \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.MultiTenancy/Views/Admin/DisplayTemplates/ActionsForRunning.cshtml b/src/Orchard.Web/Modules/Orchard.MultiTenancy/Views/Admin/DisplayTemplates/ActionsForRunning.cshtml index 4ca7ef259..02d1ece66 100644 --- a/src/Orchard.Web/Modules/Orchard.MultiTenancy/Views/Admin/DisplayTemplates/ActionsForRunning.cshtml +++ b/src/Orchard.Web/Modules/Orchard.MultiTenancy/Views/Admin/DisplayTemplates/ActionsForRunning.cshtml @@ -1,7 +1,7 @@ @model Orchard.Environment.Configuration.ShellSettings @using Orchard.MultiTenancy.Extensions; -@using(Html.BeginFormAntiForgeryPost(Url.Action("disable", new {area = "Orchard.MultiTenancy"}), FormMethod.Post, new {@class = "inline link"})) { +@using(Html.BeginFormAntiForgeryPost(Url.Action("Disable", new {area = "Orchard.MultiTenancy"}), FormMethod.Post, new {@class = "inline link"})) { @Html.HiddenFor(ss => ss.Name) -} +} diff --git a/src/Orchard.Web/Modules/Orchard.MultiTenancy/Views/Admin/Index.cshtml b/src/Orchard.Web/Modules/Orchard.MultiTenancy/Views/Admin/Index.cshtml index 25c564182..a7e6faa07 100644 --- a/src/Orchard.Web/Modules/Orchard.MultiTenancy/Views/Admin/Index.cshtml +++ b/src/Orchard.Web/Modules/Orchard.MultiTenancy/Views/Admin/Index.cshtml @@ -7,30 +7,31 @@ Layout.Title = T("List of Site's Tenants").ToString(); } -
@Html.ActionLink(T("Add a Tenant").ToString(), "Add", new {area = "Orchard.MultiTenancy"}, new { @class = "button primaryAction" })
+
@Html.ActionLink(T("Add a Tenant").ToString(), "Add", new { area = "Orchard.MultiTenancy" }, new { @class = "button primaryAction" })
    - @foreach (var tenant in Model.TenantSettings) { -
  • -
    -
    -

    @tenant.Name @if (!string.IsNullOrEmpty(tenant.RequestUrlHost)) { - var tenantClone = new ShellSettings(tenant); - foreach (var t in tenant.RequestUrlHost.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries)) { - tenantClone.RequestUrlHost = t; - var url = Url.Tenant(tenantClone); - - @Html.Link(url, url) - } - } -

    -
    -
  • +
    +
    +

    + @tenant.Name @if (!string.IsNullOrEmpty(tenant.RequestUrlHost)) { + var tenantClone = new ShellSettings(tenant); + foreach (var t in tenant.RequestUrlHost.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries)) { + tenantClone.RequestUrlHost = t; + var url = Url.Tenant(tenantClone); + - @Html.Link(url, url) + } + } +

    +
    +
    - -
  • + }
diff --git a/src/Orchard.Web/Modules/Orchard.MultiTenancy/Views/Admin/Reset.cshtml b/src/Orchard.Web/Modules/Orchard.MultiTenancy/Views/Admin/Reset.cshtml new file mode 100644 index 000000000..1a6dd7c4f --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.MultiTenancy/Views/Admin/Reset.cshtml @@ -0,0 +1,30 @@ +@model Orchard.MultiTenancy.ViewModels.TenantResetViewModel + +@{ + Layout.Title = T("Reset Tenant").ToString(); + + Script.Require("jQuery"); + Script.Include(Url.Content("~/Themes/TheAdmin/Scripts/admin.js")).AtFoot(); +} + +@using (Html.BeginFormAntiForgeryPost()) { + @Html.ValidationSummary() + +
+

@T("This will reset the tenant {0} to its uninitialized state, allowing you to set it up again.", Model.Name)

+
+ +
+ @Html.CheckBoxFor(m => Model.DropDatabaseTables) + +
    + @foreach (var tableName in Model.DatabaseTableNames) { +
  • @tableName
  • + } +
+
+ +
+ +
+}