Created ExportAction abstraction and RecipeBuilder implementation.

This commit is contained in:
Sipke Schoorstra
2015-07-15 17:03:48 +01:00
parent 7a7a9b1943
commit edd6db2331
11 changed files with 201 additions and 57 deletions

View File

@@ -7,28 +7,26 @@ using Orchard.ContentManagement;
using Orchard.ImportExport.Services; using Orchard.ImportExport.Services;
using Orchard.ImportExport.ViewModels; using Orchard.ImportExport.ViewModels;
using Orchard.Localization; using Orchard.Localization;
using Orchard.Recipes.Models;
using Orchard.Recipes.Services; using Orchard.Recipes.Services;
using Orchard.UI.Notify; using Orchard.UI.Notify;
using Orchard.Utility.Extensions;
namespace Orchard.ImportExport.Controllers { namespace Orchard.ImportExport.Controllers {
public class AdminController : Controller, IUpdateModel { public class AdminController : Controller, IUpdateModel {
private readonly IImportExportService _importExportService; private readonly IImportExportService _importExportService;
private readonly IRecipeResultAccessor _recipeResultAccessor; private readonly IRecipeResultAccessor _recipeResultAccessor;
private readonly IEnumerable<IRecipeBuilderStep> _exportStepProviders; private readonly IEnumerable<IExportAction> _exportActions;
private readonly IRecipeParser _recipeParser; private readonly IRecipeParser _recipeParser;
public AdminController( public AdminController(
IOrchardServices services, IOrchardServices services,
IImportExportService importExportService, IImportExportService importExportService,
IRecipeResultAccessor recipeResultAccessor, IRecipeResultAccessor recipeResultAccessor,
IEnumerable<IRecipeBuilderStep> exportStepProviders, IEnumerable<IExportAction> exportActions,
IRecipeParser recipeParser) { IRecipeParser recipeParser) {
_importExportService = importExportService; _importExportService = importExportService;
_recipeResultAccessor = recipeResultAccessor; _recipeResultAccessor = recipeResultAccessor;
_exportStepProviders = exportStepProviders; _exportActions = exportActions;
_recipeParser = recipeParser; _recipeParser = recipeParser;
Services = services; Services = services;
T = NullLocalizer.Instance; T = NullLocalizer.Instance;
@@ -72,15 +70,12 @@ namespace Orchard.ImportExport.Controllers {
} }
public ActionResult Export() { public ActionResult Export() {
var exportSteps = _exportStepProviders.OrderBy(x => x.Priority).Select(x => new ExportStepViewModel { var actions = _exportActions.OrderBy(x => x.Priority).Select(x => new ExportActionViewModel {
Name = x.Name,
DisplayName = x.DisplayName,
Description = x.Description,
Editor = x.BuildEditor(Services.New) Editor = x.BuildEditor(Services.New)
}).Where(x => x != null); }).Where(x => x != null).ToList();
var viewModel = new ExportViewModel { var viewModel = new ExportViewModel {
ExportSteps = exportSteps.ToList() Actions = actions
}; };
return View(viewModel); return View(viewModel);
@@ -90,32 +85,22 @@ namespace Orchard.ImportExport.Controllers {
public ActionResult ExportPOST(ExportViewModel viewModel) { public ActionResult ExportPOST(ExportViewModel viewModel) {
if (!Services.Authorizer.Authorize(Permissions.Export, T("Not allowed to export."))) if (!Services.Authorizer.Authorize(Permissions.Export, T("Not allowed to export.")))
return new HttpUnauthorizedResult(); return new HttpUnauthorizedResult();
var exportStepNames = viewModel.ExportSteps.Where(x => x.IsSelected).Select(x => x.Name); var actions = _exportActions.OrderBy(x => x.Priority).ToList();
var exportStepsQuery = from name in exportStepNames
let provider = _exportStepProviders.SingleOrDefault(x => x.Name == name) foreach (var action in actions) {
where provider != null action.UpdateEditor(Services.New, this);
select provider;
var exportSteps = exportStepsQuery.ToArray();
foreach (var exportStep in exportSteps) {
exportStep.UpdateEditor(Services.New, this);
} }
var recipeDocument = _importExportService.ExportXml(exportSteps); var exportActionContext = new ExportActionContext {
var recipe = _recipeParser.ParseRecipe(recipeDocument); ActionResult = RedirectToAction("Export")
var exportFileName = GetExportFileName(recipe); };
var exportFilePath = _importExportService.WriteExportFile(recipeDocument);
return File(exportFilePath, "text/xml", exportFileName); foreach (var action in actions) {
} action.Execute(exportActionContext);
}
private string GetExportFileName(Recipe recipe) {
return String.IsNullOrWhiteSpace(recipe.Name) return exportActionContext.ActionResult;
? "export.xml"
: String.Format(recipe.IsSetupRecipe
? "{0}.recipe.xml"
: "{0}.export.xml", recipe.Name.HtmlClassify());
} }
bool IUpdateModel.TryUpdateModel<TModel>(TModel model, string prefix, string[] includeProperties, string[] excludeProperties) { bool IUpdateModel.TryUpdateModel<TModel>(TModel model, string prefix, string[] includeProperties, string[] excludeProperties) {

View File

@@ -71,18 +71,24 @@
<Compile Include="Models\ExportOptions.cs" /> <Compile Include="Models\ExportOptions.cs" />
<Compile Include="Permissions.cs" /> <Compile Include="Permissions.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Providers\ExportActions\RecipeBuilder.cs" />
<Compile Include="Recipes\Builders\CustomStepsStep.cs" /> <Compile Include="Recipes\Builders\CustomStepsStep.cs" />
<Compile Include="Services\ExportAction.cs" />
<Compile Include="Services\ExportActionContext.cs" />
<Compile Include="Services\ExportContext.cs" /> <Compile Include="Services\ExportContext.cs" />
<Compile Include="Services\IExportAction.cs" />
<Compile Include="ViewModels\CustomStepEntry.cs" /> <Compile Include="ViewModels\CustomStepEntry.cs" />
<Compile Include="Services\ICustomExportStep.cs" /> <Compile Include="Services\ICustomExportStep.cs" />
<Compile Include="Services\IExportEventHandler.cs" /> <Compile Include="Services\IExportEventHandler.cs" />
<Compile Include="Services\IImportExportService.cs" /> <Compile Include="Services\IImportExportService.cs" />
<Compile Include="Services\ImportExportService.cs" /> <Compile Include="Services\ImportExportService.cs" />
<Compile Include="ViewModels\CustomStepsViewModel.cs" /> <Compile Include="ViewModels\CustomStepsViewModel.cs" />
<Compile Include="ViewModels\ExportActionViewModel.cs" />
<Compile Include="ViewModels\ExportStepViewModel.cs" /> <Compile Include="ViewModels\ExportStepViewModel.cs" />
<Compile Include="ViewModels\ExportViewModel.cs" /> <Compile Include="ViewModels\ExportViewModel.cs" />
<Compile Include="ViewModels\ImportResultViewModel.cs" /> <Compile Include="ViewModels\ImportResultViewModel.cs" />
<Compile Include="ViewModels\ImportViewModel.cs" /> <Compile Include="ViewModels\ImportViewModel.cs" />
<Compile Include="ViewModels\RecipeBuilderViewModel.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Content Include="Module.txt" /> <Content Include="Module.txt" />
@@ -123,10 +129,15 @@
<ItemGroup> <ItemGroup>
<Content Include="Views\Admin\ImportResult.cshtml" /> <Content Include="Views\Admin\ImportResult.cshtml" />
</ItemGroup> </ItemGroup>
<ItemGroup /> <ItemGroup>
<Folder Include="Providers\ImportActions\" />
</ItemGroup>
<ItemGroup> <ItemGroup>
<Content Include="Views\EditorTemplates\ExportSteps\CustomSteps.cshtml" /> <Content Include="Views\EditorTemplates\ExportSteps\CustomSteps.cshtml" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<Content Include="Views\EditorTemplates\ExportActions\RecipeBuilder.cshtml" />
</ItemGroup>
<PropertyGroup> <PropertyGroup>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">10.0</VisualStudioVersion> <VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">10.0</VisualStudioVersion>
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath> <VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>

View File

@@ -0,0 +1,86 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Mvc;
using Orchard.ContentManagement;
using Orchard.ImportExport.Services;
using Orchard.ImportExport.ViewModels;
using Orchard.Mvc;
using Orchard.Recipes.Models;
using Orchard.Recipes.Services;
using Orchard.Utility.Extensions;
namespace Orchard.ImportExport.Providers.ExportActions {
public class RecipeBuilder : ExportAction {
private readonly IEnumerable<IRecipeBuilderStep> _recipeBuilderSteps;
private readonly IImportExportService _importExportService;
private readonly IRecipeParser _recipeParser;
public RecipeBuilder(IEnumerable<IRecipeBuilderStep> recipeBuilderSteps, IImportExportService importExportService, IRecipeParser recipeParser) {
_recipeBuilderSteps = recipeBuilderSteps;
_importExportService = importExportService;
_recipeParser = recipeParser;
RecipeBuilderSteps = new List<IRecipeBuilderStep>();
}
public override string Name { get { return "RecipeBuilder"; } }
public IList<IRecipeBuilderStep> RecipeBuilderSteps { get; set; }
public override dynamic BuildEditor(dynamic shapeFactory) {
return UpdateEditor(shapeFactory, null);
}
public override dynamic UpdateEditor(dynamic shapeFactory, IUpdateModel updater) {
var builderSteps = _recipeBuilderSteps.OrderBy(x => x.Priority).Select(x => new ExportStepViewModel {
Name = x.Name,
DisplayName = x.DisplayName,
Description = x.Description,
Editor = x.BuildEditor(shapeFactory)
}).Where(x => x != null);
var viewModel = new RecipeBuilderViewModel {
Steps = builderSteps.ToList()
};
if (updater != null) {
if (updater.TryUpdateModel(viewModel, Prefix, null, null)) {
var exportStepNames = viewModel.Steps.Where(x => x.IsSelected).Select(x => x.Name);
var stepsQuery = from name in exportStepNames
let provider = _recipeBuilderSteps.SingleOrDefault(x => x.Name == name)
where provider != null
select provider;
var steps = stepsQuery.ToArray();
var stepUpdater = new Updater(updater, secondHalf => String.Format("{0}.{1}", Prefix, secondHalf));
foreach (var exportStep in steps) {
exportStep.UpdateEditor(shapeFactory, stepUpdater);
}
RecipeBuilderSteps = steps;
}
}
return shapeFactory.EditorTemplate(TemplateName: "ExportActions/RecipeBuilder", Model: viewModel, Prefix: Prefix);
}
public override void Execute(ExportActionContext context) {
var recipeDocument = _importExportService.ExportXml(RecipeBuilderSteps);
var recipe = _recipeParser.ParseRecipe(recipeDocument);
var exportFileName = GetExportFileName(recipe);
var exportFilePath = _importExportService.WriteExportFile(recipeDocument);
var actionResult = new FilePathResult(exportFilePath, "text/xml");
actionResult.FileDownloadName = exportFileName;
context.ActionResult = actionResult;
}
private string GetExportFileName(Recipe recipe) {
return String.IsNullOrWhiteSpace(recipe.Name)
? "export.xml"
: String.Format(recipe.IsSetupRecipe
? "{0}.recipe.xml"
: "{0}.export.xml", recipe.Name.HtmlClassify());
}
}
}

View File

@@ -0,0 +1,22 @@
using Orchard.ContentManagement;
namespace Orchard.ImportExport.Services {
public abstract class ExportAction : IExportAction {
public virtual int Priority { get { return 0; } }
public abstract string Name { get; }
protected virtual string Prefix {
get { return GetType().Name; }
}
public virtual dynamic BuildEditor(dynamic shapeFactory) {
return null;
}
public virtual dynamic UpdateEditor(dynamic shapeFactory, IUpdateModel updater) {
return null;
}
public abstract void Execute(ExportActionContext exportActionContext);
}
}

View File

@@ -0,0 +1,7 @@
using System.Web.Mvc;
namespace Orchard.ImportExport.Services {
public class ExportActionContext {
public ActionResult ActionResult { get; set; }
}
}

View File

@@ -0,0 +1,12 @@
using Orchard.ContentManagement;
namespace Orchard.ImportExport.Services {
public interface IExportAction : IDependency {
int Priority { get; }
string Name { get; }
dynamic BuildEditor(dynamic shapeFactory);
dynamic UpdateEditor(dynamic shapeFactory, IUpdateModel updater);
void Execute(ExportActionContext exportActionContext);
}
}

View File

@@ -0,0 +1,5 @@
namespace Orchard.ImportExport.ViewModels {
public class ExportActionViewModel {
public dynamic Editor { get; set; }
}
}

View File

@@ -2,6 +2,6 @@
namespace Orchard.ImportExport.ViewModels { namespace Orchard.ImportExport.ViewModels {
public class ExportViewModel { public class ExportViewModel {
public IList<ExportStepViewModel> ExportSteps { get; set; } public IList<ExportActionViewModel> Actions { get; set; }
} }
} }

View File

@@ -0,0 +1,7 @@
using System.Collections.Generic;
namespace Orchard.ImportExport.ViewModels {
public class RecipeBuilderViewModel {
public IList<ExportStepViewModel> Steps { get; set; }
}
}

View File

@@ -1,28 +1,12 @@
@using Orchard.Utility.Extensions @model Orchard.ImportExport.ViewModels.ExportViewModel
@model Orchard.ImportExport.ViewModels.ExportViewModel
@{ Layout.Title = T("Export").ToString(); } @{ Layout.Title = T("Export").ToString(); }
@using (Html.BeginFormAntiForgeryPost()) { @using (Html.BeginFormAntiForgeryPost()) {
Html.ValidationSummary(); Html.ValidationSummary();
var exportStepIndex = 0;
foreach (var exportStep in Model.ExportSteps) {
var stepName = Html.NameFor(m => m.ExportSteps[exportStepIndex].IsSelected).ToString();
var stepId = stepName.HtmlClassify();
<fieldset class="recipe-builder-step recipe-builder-step-@exportStep.Name.HtmlClassify()"> foreach(var action in Model.Actions) {
<legend> <div class="export-action">
<input type="hidden" name="@Html.NameFor(m => m.ExportSteps[exportStepIndex].Name)" value="@Model.ExportSteps[exportStepIndex].Name"/> @Display(action.Editor)
<input type="checkbox" id="@stepId" name="@stepName" value="true"/> </div>
<label for="@stepId" class="forcheckbox">@exportStep.DisplayName</label>
</legend>
@Html.Hint(@exportStep.Description)
<div data-controllerid="@stepId">
@Display(exportStep.Editor)
</div>
</fieldset>
exportStepIndex++;
if (exportStepIndex < Model.ExportSteps.Count) {
<hr />
}
} }
<button type="submit" class="primaryAction">@T("Export")</button> <button type="submit" class="primaryAction">@T("Export")</button>

View File

@@ -0,0 +1,25 @@
@using Orchard.Utility.Extensions
@model Orchard.ImportExport.ViewModels.RecipeBuilderViewModel
@{
var exportStepIndex = 0;
foreach (var exportStep in Model.Steps) {
var stepName = Html.NameFor(m => m.Steps[exportStepIndex].IsSelected).ToString();
var stepId = stepName.HtmlClassify();
<fieldset class="recipe-builder-step recipe-builder-step-@exportStep.Name.HtmlClassify()">
<legend>
<input type="hidden" name="@Html.NameFor(m => m.Steps[exportStepIndex].Name)" value="@Model.Steps[exportStepIndex].Name" />
<input type="checkbox" id="@stepId" name="@stepName" value="true" />
<label for="@stepId" class="forcheckbox">@exportStep.DisplayName</label>
</legend>
@Html.Hint(@exportStep.Description)
<div data-controllerid="@stepId">
@Display(exportStep.Editor)
</div>
</fieldset>
exportStepIndex++;
if (exportStepIndex < Model.Steps.Count) {
<hr />
}
}
}