Incremental refactoring of ImportExport and Recipes.

This commit is contained in:
Sipke Schoorstra
2015-07-15 00:01:23 +01:00
parent 18469ad462
commit 19126126d6
44 changed files with 371 additions and 238 deletions

View File

@@ -4,9 +4,11 @@ using System.IO;
using System.Linq; using System.Linq;
using Orchard.Commands; using Orchard.Commands;
using Orchard.ContentManagement.MetaData; using Orchard.ContentManagement.MetaData;
using Orchard.ImportExport.Models; using Orchard.ImportExport.RecipeBuilderSteps;
using Orchard.ImportExport.Providers;
using Orchard.ImportExport.Services; using Orchard.ImportExport.Services;
using Orchard.Recipes.Models;
using Orchard.Recipes.RecipeBuilders;
using Orchard.Recipes.Services;
using Orchard.Security; using Orchard.Security;
using Orchard.Settings; using Orchard.Settings;
@@ -95,13 +97,10 @@ namespace Orchard.ImportExport.Commands {
.ToList(); .ToList();
var enteredSteps = (Steps ?? String.Empty).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries); var enteredSteps = (Steps ?? String.Empty).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
var exportSteps = new List<IExportStepProvider>(); var recipeBuilderSteps = new List<IRecipeBuilderStep>();
var exportOptions = new ExportOptions {
CustomSteps = enteredSteps
};
if (Metadata || Data) { if (Metadata || Data) {
var dataStep = _orchardServices.WorkContext.Resolve<DataExportStep>(); var dataStep = _orchardServices.WorkContext.Resolve<DataRecipeBuilderStep>();
if(Data) if(Data)
dataStep.DataContentTypes = exportTypes; dataStep.DataContentTypes = exportTypes;
@@ -110,17 +109,22 @@ namespace Orchard.ImportExport.Commands {
dataStep.SchemaContentTypes = exportTypes; dataStep.SchemaContentTypes = exportTypes;
dataStep.VersionHistoryOptions = versionOption; dataStep.VersionHistoryOptions = versionOption;
exportSteps.Add(dataStep); recipeBuilderSteps.Add(dataStep);
} }
if (SiteSettings) { if (SiteSettings) {
var siteSettingsStep = _orchardServices.WorkContext.Resolve<SiteSettingsExportStep>(); var siteSettingsStep = _orchardServices.WorkContext.Resolve<SiteSettingsBuilderStep>();
exportSteps.Add(siteSettingsStep); recipeBuilderSteps.Add(siteSettingsStep);
}
if (enteredSteps.Any()) {
var customStepsStep = _orchardServices.WorkContext.Resolve<CustomStepsRecipeBuilderStep>();
recipeBuilderSteps.Add(customStepsStep);
} }
Context.Output.WriteLine(T("Export starting...")); Context.Output.WriteLine(T("Export starting..."));
var exportFilePath = _importExportService.Export(exportSteps, exportOptions); var exportFilePath = _importExportService.Export(recipeBuilderSteps);
Context.Output.WriteLine(T("Export completed at {0}", exportFilePath)); Context.Output.WriteLine(T("Export completed at {0}", exportFilePath));
} }

View File

@@ -4,8 +4,6 @@ using System.IO;
using System.Linq; using System.Linq;
using System.Web.Mvc; using System.Web.Mvc;
using Orchard.ContentManagement; using Orchard.ContentManagement;
using Orchard.ContentManagement.MetaData;
using Orchard.ImportExport.Models;
using Orchard.ImportExport.Services; using Orchard.ImportExport.Services;
using Orchard.ImportExport.ViewModels; using Orchard.ImportExport.ViewModels;
using Orchard.Localization; using Orchard.Localization;
@@ -15,22 +13,16 @@ using Orchard.UI.Notify;
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 IContentDefinitionManager _contentDefinitionManager;
private readonly ICustomExportStep _customExportStep;
private readonly IRecipeResultAccessor _recipeResultAccessor; private readonly IRecipeResultAccessor _recipeResultAccessor;
private readonly IEnumerable<IExportStepProvider> _exportStepProviders; private readonly IEnumerable<IRecipeBuilderStep> _exportStepProviders;
public AdminController( public AdminController(
IOrchardServices services, IOrchardServices services,
IImportExportService importExportService, IImportExportService importExportService,
IContentDefinitionManager contentDefinitionManager, IRecipeResultAccessor recipeResultAccessor,
ICustomExportStep customExportStep, IEnumerable<IRecipeBuilderStep> exportStepProviders) {
IRecipeResultAccessor recipeResultAccessor,
IEnumerable<IExportStepProvider> exportStepProviders) {
_importExportService = importExportService; _importExportService = importExportService;
_contentDefinitionManager = contentDefinitionManager;
_customExportStep = customExportStep;
_recipeResultAccessor = recipeResultAccessor; _recipeResultAccessor = recipeResultAccessor;
_exportStepProviders = exportStepProviders; _exportStepProviders = exportStepProviders;
Services = services; Services = services;
@@ -75,10 +67,7 @@ namespace Orchard.ImportExport.Controllers {
} }
public ActionResult Export() { public ActionResult Export() {
var customSteps = new List<string>(); var exportSteps = _exportStepProviders.OrderBy(x => x.Priority).Select(x => new ExportStepViewModel {
_customExportStep.Register(customSteps);
var exportSteps = _exportStepProviders.OrderBy(x => x.Position).Select(x => new ExportStepViewModel {
Name = x.Name, Name = x.Name,
DisplayName = x.DisplayName, DisplayName = x.DisplayName,
Description = x.Description, Description = x.Description,
@@ -86,7 +75,6 @@ namespace Orchard.ImportExport.Controllers {
}).Where(x => x != null); }).Where(x => x != null);
var viewModel = new ExportViewModel { var viewModel = new ExportViewModel {
CustomSteps = customSteps.Select(x => new CustomStepEntry { CustomStep = x }).ToList(),
ExportSteps = exportSteps.ToList() ExportSteps = exportSteps.ToList()
}; };
@@ -94,33 +82,22 @@ namespace Orchard.ImportExport.Controllers {
} }
[HttpPost, ActionName("Export")] [HttpPost, ActionName("Export")]
public ActionResult ExportPOST() { 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 viewModel = new ExportViewModel {
CustomSteps = new List<CustomStepEntry>(),
ExportSteps = new List<ExportStepViewModel>()
};
UpdateModel(viewModel);
var exportStepNames = viewModel.ExportSteps.Where(x => x.IsSelected).Select(x => x.Name); var exportStepNames = viewModel.ExportSteps.Where(x => x.IsSelected).Select(x => x.Name);
var exportStepsQuery = from name in exportStepNames var exportStepsQuery = from name in exportStepNames
let provider = _exportStepProviders.SingleOrDefault(x => x.Name == name) let provider = _exportStepProviders.SingleOrDefault(x => x.Name == name)
where provider != null where provider != null
select provider; select provider;
var exportSteps = exportStepsQuery.ToArray(); var exportSteps = exportStepsQuery.ToArray();
var customSteps = viewModel.CustomSteps.Where(c => c.IsChecked).Select(c => c.CustomStep);
var exportOptions = new ExportOptions {
CustomSteps = customSteps
};
foreach (var exportStep in exportSteps) { foreach (var exportStep in exportSteps) {
exportStep.UpdateEditor(Services.New, this); exportStep.UpdateEditor(Services.New, this);
} }
var exportFilePath = _importExportService.Export(exportSteps, exportOptions); var exportFilePath = _importExportService.Export(exportSteps);
var exportFileName = "export.xml"; var exportFileName = "export.xml";
return File(exportFilePath, "text/xml", exportFileName); return File(exportFilePath, "text/xml", exportFileName);

View File

@@ -4,10 +4,4 @@ namespace Orchard.ImportExport.Models {
public class ExportOptions { public class ExportOptions {
public IEnumerable<string> CustomSteps { get; set; } public IEnumerable<string> CustomSteps { get; set; }
} }
public enum VersionHistoryOptions {
Published,
Draft,
Latest
}
} }

View File

@@ -8,4 +8,4 @@ OrchardVersion: 1.9
Description: Provides content item data import and export capability. Description: Provides content item data import and export capability.
FeatureDescription: Imports and exports content item data FeatureDescription: Imports and exports content item data
Category: Content Category: Content
Dependencies: Orchard.jQuery Dependencies: Orchard.jQuery, Orchard.Recipes

View File

@@ -71,23 +71,15 @@
<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\SetupRecipeExportStep.cs" /> <Compile Include="RecipeBuilderSteps\CustomStepsRecipeBuilderStep.cs" />
<Compile Include="Providers\SiteSettingsExportStep.cs" /> <Compile Include="Services\ExportContext.cs" />
<Compile Include="Providers\DataExportStep.cs" />
<Compile Include="ViewModels\ContentTypeEntry.cs" />
<Compile Include="ViewModels\CustomStepEntry.cs" /> <Compile Include="ViewModels\CustomStepEntry.cs" />
<Compile Include="ViewModels\ExportStepViewModel.cs" />
<Compile Include="ViewModels\SetupRecipeStepViewModel.cs" />
<Compile Include="ViewModels\SiteSettingsStepViewModel.cs" />
<Compile Include="ViewModels\DataExportStepViewModel.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\IImportStepProvider.cs" />
<Compile Include="Services\ImportExportService.cs" /> <Compile Include="Services\ImportExportService.cs" />
<Compile Include="Services\IExportStepProvider.cs" /> <Compile Include="ViewModels\CustomStepsViewModel.cs" />
<Compile Include="Services\ImportStepProvider.cs" /> <Compile Include="ViewModels\ExportStepViewModel.cs" />
<Compile Include="Services\ExportStepProvider.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" />
@@ -106,9 +98,12 @@
<Name>Orchard.Core</Name> <Name>Orchard.Core</Name>
<Private>false</Private> <Private>false</Private>
</ProjectReference> </ProjectReference>
<ProjectReference Include="..\Orchard.Recipes\Orchard.Recipes.csproj">
<Project>{fc1d74e8-7a4d-48f4-83de-95c6173780c4}</Project>
<Name>Orchard.Recipes</Name>
</ProjectReference>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Content Include="Scripts\exportstep-data.js" />
<Content Include="Styles\images\menu.importexport.png" /> <Content Include="Styles\images\menu.importexport.png" />
<Content Include="Styles\exportstep-data.css" /> <Content Include="Styles\exportstep-data.css" />
<Content Include="Styles\menu.importexport-admin.css" /> <Content Include="Styles\menu.importexport-admin.css" />
@@ -128,19 +123,9 @@
<ItemGroup> <ItemGroup>
<Content Include="Views\Admin\ImportResult.cshtml" /> <Content Include="Views\Admin\ImportResult.cshtml" />
</ItemGroup> </ItemGroup>
<ItemGroup />
<ItemGroup> <ItemGroup>
<Content Include="Views\EditorTemplates\ExportSteps\Data.cshtml" /> <Content Include="Views\EditorTemplates\ExportSteps\CustomSteps.cshtml" />
</ItemGroup>
<ItemGroup>
<Content Include="Views\EditorTemplates\ExportSteps\SiteSettings.cshtml" />
</ItemGroup>
<ItemGroup>
<Content Include="Views\EditorTemplates\ExportSteps\SetupRecipe.cshtml" />
</ItemGroup>
<ItemGroup>
<Content Include="Scripts\Web.config">
<SubType>Designer</SubType>
</Content>
</ItemGroup> </ItemGroup>
<PropertyGroup> <PropertyGroup>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">10.0</VisualStudioVersion> <VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">10.0</VisualStudioVersion>

View File

@@ -0,0 +1,67 @@
using System.Collections.Generic;
using System.Linq;
using Orchard.ContentManagement;
using Orchard.ImportExport.Models;
using Orchard.ImportExport.Services;
using Orchard.ImportExport.ViewModels;
using Orchard.Localization;
using Orchard.Recipes.Services;
namespace Orchard.ImportExport.RecipeBuilderSteps {
public class CustomStepsRecipeBuilderStep : RecipeBuilderStep {
private readonly IEnumerable<IExportEventHandler> _exportEventHandlers;
private readonly ICustomExportStep _customExportStep;
public CustomStepsRecipeBuilderStep(IEnumerable<IExportEventHandler> exportEventHandlers, ICustomExportStep customExportStep) {
_exportEventHandlers = exportEventHandlers;
_customExportStep = customExportStep;
CustomSteps = new List<string>();
}
public override string Name {
get { return "CustomSteps"; }
}
public override LocalizedString DisplayName {
get { return T("Additional Export Steps"); }
}
public override LocalizedString Description {
get { return T("Exports additional items."); }
}
public override int Priority { get { return 60; } }
public IList<string> CustomSteps { get; set; }
public override dynamic BuildEditor(dynamic shapeFactory) {
return UpdateEditor(shapeFactory, null);
}
public override dynamic UpdateEditor(dynamic shapeFactory, IUpdateModel updater) {
var customSteps = new List<string>();
_customExportStep.Register(customSteps);
var viewModel = new CustomStepsViewModel {
CustomSteps = customSteps.Select(x => new CustomStepEntry { CustomStep = x}).ToList()
};
if (updater != null && updater.TryUpdateModel(viewModel, Prefix, null, null)) {
CustomSteps = viewModel.CustomSteps.Where(x => x.IsChecked).Select(x => x.CustomStep).ToList();
}
return shapeFactory.EditorTemplate(TemplateName: "ExportSteps/CustomSteps", Model: viewModel, Prefix: Prefix);
}
public override void Build(BuildContext context) {
var exportContext = new ExportContext {
Document = context.RecipeDocument,
ExportOptions = new ExportOptions {
CustomSteps = CustomSteps
}
};
_exportEventHandlers.Invoke(x => x.Exporting(exportContext), Logger);
_exportEventHandlers.Invoke(x => x.Exported(exportContext), Logger);
}
}
}

View File

@@ -0,0 +1,9 @@
using System.Xml.Linq;
using Orchard.ImportExport.Models;
namespace Orchard.ImportExport.Services {
public class ExportContext {
public XDocument Document { get; set; }
public ExportOptions ExportOptions { get; set; }
}
}

View File

@@ -1,13 +1,6 @@
using System.Xml.Linq; using Orchard.Events;
using Orchard.Events;
using Orchard.ImportExport.Models;
namespace Orchard.ImportExport.Services { namespace Orchard.ImportExport.Services {
public class ExportContext {
public XDocument Document { get; set; }
public ExportOptions ExportOptions { get; set; }
}
public interface IExportEventHandler : IEventHandler { public interface IExportEventHandler : IEventHandler {
void Exporting(ExportContext context); void Exporting(ExportContext context);
void Exported(ExportContext context); void Exported(ExportContext context);

View File

@@ -1,12 +1,9 @@
using System.Collections.Generic; using System.Collections.Generic;
using Orchard.ImportExport.Models; using Orchard.Recipes.Services;
namespace Orchard.ImportExport.Services { namespace Orchard.ImportExport.Services {
public interface IImportExportService : IDependency { public interface IImportExportService : IDependency {
string Import(string recipeText); string Import(string recipeText);
string Export(IEnumerable<IExportStepProvider> steps, ExportOptions exportOptions); string Export(IEnumerable<IRecipeBuilderStep> steps);
} }
} }

View File

@@ -1,11 +0,0 @@
using Orchard.ContentManagement;
using Orchard.Localization;
namespace Orchard.ImportExport.Services {
public interface IImportStepProvider : IDependency {
string Name { get; }
LocalizedString DisplayName { get; }
dynamic BuildEditor(dynamic shapeFactory);
dynamic UpdateEditor(dynamic shapeFactory, IUpdateModel updater);
}
}

View File

@@ -1,11 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Xml;
using System.Xml.Linq;
using Orchard.ContentManagement;
using Orchard.Environment.Descriptor;
using Orchard.FileSystems.AppData; using Orchard.FileSystems.AppData;
using Orchard.ImportExport.Models;
using Orchard.Localization; using Orchard.Localization;
using Orchard.Logging; using Orchard.Logging;
using Orchard.Recipes.Services; using Orchard.Recipes.Services;
@@ -15,29 +10,23 @@ namespace Orchard.ImportExport.Services {
public class ImportExportService : IImportExportService { public class ImportExportService : IImportExportService {
private readonly IOrchardServices _orchardServices; private readonly IOrchardServices _orchardServices;
private readonly IAppDataFolder _appDataFolder; private readonly IAppDataFolder _appDataFolder;
private readonly IRecipeParser _recipeParser; private readonly IRecipeBuilder _recipeBuilder;
private readonly IRecipeManager _recipeManager; private readonly IRecipeExecutor _recipeExecutor;
private readonly IShellDescriptorManager _shellDescriptorManager;
private readonly IClock _clock; private readonly IClock _clock;
private readonly IEnumerable<IExportEventHandler> _exportEventHandlers;
private const string ExportsDirectory = "Exports"; private const string ExportsDirectory = "Exports";
public ImportExportService( public ImportExportService(
IOrchardServices orchardServices, IOrchardServices orchardServices,
IAppDataFolder appDataFolder, IAppDataFolder appDataFolder,
IRecipeParser recipeParser, IRecipeBuilder recipeBuilder,
IRecipeManager recipeManager, IRecipeExecutor recipeExecutor,
IShellDescriptorManager shellDescriptorManager, IClock clock) {
IClock clock,
IEnumerable<IExportEventHandler> exportEventHandlers) {
_orchardServices = orchardServices; _orchardServices = orchardServices;
_appDataFolder = appDataFolder; _appDataFolder = appDataFolder;
_recipeParser = recipeParser; _recipeBuilder = recipeBuilder;
_recipeManager = recipeManager; _recipeExecutor = recipeExecutor;
_shellDescriptorManager = shellDescriptorManager;
_clock = clock; _clock = clock;
_exportEventHandlers = exportEventHandlers;
Logger = NullLogger.Instance; Logger = NullLogger.Instance;
T = NullLocalizer.Instance; T = NullLocalizer.Instance;
} }
@@ -46,46 +35,16 @@ namespace Orchard.ImportExport.Services {
public ILogger Logger { get; set; } public ILogger Logger { get; set; }
public string Import(string recipeText) { public string Import(string recipeText) {
var recipe = _recipeParser.ParseRecipe(recipeText); return _recipeExecutor.Execute(recipeText);
var executionId = _recipeManager.Execute(recipe);
UpdateShell();
return executionId;
} }
public string Export(IEnumerable<IExportStepProvider> steps, ExportOptions exportOptions) { public string Export(IEnumerable<IRecipeBuilderStep> steps) {
var exportDocument = CreateExportRoot(); var recipe = _recipeBuilder.Build(steps);
return WriteExportFile(recipe);
var context = new ExportContext {
Document = exportDocument,
ExportOptions = exportOptions
};
_exportEventHandlers.Invoke(x => x.Exporting(context), Logger);
foreach (var step in steps) {
step.Export(context);
}
_exportEventHandlers.Invoke(x => x.Exported(context), Logger);
return WriteExportFile(exportDocument.ToString());
}
private XDocument CreateExportRoot() {
var exportRoot = new XDocument(
new XDeclaration("1.0", "", "yes"),
new XComment("Exported from Orchard"),
new XElement("Orchard",
new XElement("Recipe",
new XElement("ExportUtc", XmlConvert.ToString(_clock.UtcNow, XmlDateTimeSerializationMode.Utc))
)
)
);
return exportRoot;
} }
private string WriteExportFile(string exportDocument) { private string WriteExportFile(string exportDocument) {
var exportFile = String.Format("Export-{0}-{1}.xml", _orchardServices.WorkContext.CurrentUser.UserName, DateTime.UtcNow.Ticks); var exportFile = String.Format("Export-{0}-{1}.xml", _orchardServices.WorkContext.CurrentUser.UserName, _clock.UtcNow.Ticks);
if (!_appDataFolder.DirectoryExists(ExportsDirectory)) { if (!_appDataFolder.DirectoryExists(ExportsDirectory)) {
_appDataFolder.CreateDirectory(ExportsDirectory); _appDataFolder.CreateDirectory(ExportsDirectory);
} }
@@ -95,10 +54,5 @@ namespace Orchard.ImportExport.Services {
return _appDataFolder.MapPath(path); return _appDataFolder.MapPath(path);
} }
private void UpdateShell() {
var descriptor = _shellDescriptorManager.GetShellDescriptor();
_shellDescriptorManager.UpdateShellDescriptor(descriptor.SerialNumber, descriptor.Features, descriptor.Parameters);
}
} }
} }

View File

@@ -1,21 +0,0 @@
using Orchard.ContentManagement;
using Orchard.Localization;
namespace Orchard.ImportExport.Services {
public abstract class ImportStepProvider : Component, IImportStepProvider {
public abstract string Name { get; }
public abstract LocalizedString DisplayName { 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;
}
}
}

View File

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

View File

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

View File

@@ -1,5 +1,5 @@
@using Orchard.Utility.Extensions @using Orchard.Utility.Extensions
@model Orchard.ImportExport.ViewModels.ExportViewModel @model Orchard.ImportExport.ViewModels.CustomStepsViewModel
@{ Layout.Title = T("Export").ToString(); } @{ Layout.Title = T("Export").ToString(); }
@using (Html.BeginFormAntiForgeryPost()) { @using (Html.BeginFormAntiForgeryPost()) {
Html.ValidationSummary(); Html.ValidationSummary();
@@ -25,20 +25,5 @@
} }
} }
if (Model.CustomSteps.Any()) {
<fieldset>
<legend>@T("Choose the custom steps to execute in the export file:")</legend>
<ol>
@for (var customStepIndex = 0; customStepIndex < Model.CustomSteps.Count; customStepIndex++) {
<li>
<input type="hidden" value="@Model.CustomSteps[customStepIndex].CustomStep" name="@Html.NameOf(m => m.CustomSteps[customStepIndex].CustomStep)" />
<input type="checkbox" value="true" name="@Html.NameOf(m => m.CustomSteps[customStepIndex].IsChecked)" id="@Html.NameOf(m => m.CustomSteps[customStepIndex].IsChecked)" />
<label class="forcheckbox" for="@Html.NameOf(m => m.CustomSteps[customStepIndex].IsChecked)">@Model.CustomSteps[customStepIndex].CustomStep.CamelFriendly()</label>
</li>
}
</ol>
</fieldset>
}
<button type="submit" class="primaryAction">@T("Export")</button> <button type="submit" class="primaryAction">@T("Export")</button>
} }

View File

@@ -0,0 +1,17 @@
@using Orchard.Utility.Extensions
@model Orchard.ImportExport.ViewModels.CustomStepsViewModel
@if (Model.CustomSteps.Any()) {
<fieldset>
<legend>@T("Choose the custom steps to execute in the export file:")</legend>
<ol>
@for (var customStepIndex = 0; customStepIndex < Model.CustomSteps.Count; customStepIndex++) {
var closureIndex = customStepIndex;
<li>
<input type="hidden" value="@Model.CustomSteps[customStepIndex].CustomStep" name="@Html.NameOf(m => m.CustomSteps[closureIndex].CustomStep)" />
<input type="checkbox" value="true" name="@Html.NameOf(m => m.CustomSteps[closureIndex].IsChecked)" id="@Html.NameOf(m => m.CustomSteps[closureIndex].IsChecked)" />
<label class="forcheckbox" for="@Html.NameOf(m => m.CustomSteps[closureIndex].IsChecked)">@Model.CustomSteps[closureIndex].CustomStep.CamelFriendly()</label>
</li>
}
</ol>
</fieldset>
}

View File

@@ -0,0 +1,7 @@
namespace Orchard.Recipes.Models {
public enum VersionHistoryOptions {
Published,
Draft,
Latest
}
}

View File

@@ -51,6 +51,7 @@
<Reference Include="Autofac"> <Reference Include="Autofac">
<HintPath>..\..\..\..\lib\autofac\Autofac.dll</HintPath> <HintPath>..\..\..\..\lib\autofac\Autofac.dll</HintPath>
</Reference> </Reference>
<Reference Include="Microsoft.CSharp" />
<Reference Include="System" /> <Reference Include="System" />
<Reference Include="System.Data.DataSetExtensions" /> <Reference Include="System.Data.DataSetExtensions" />
<Reference Include="System.Web.ApplicationServices" /> <Reference Include="System.Web.ApplicationServices" />
@@ -68,6 +69,10 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Content Include="Module.txt" /> <Content Include="Module.txt" />
<Content Include="Scripts\exportstep-data.js" />
<Content Include="Styles\exportstep-data.css" />
<Content Include="Styles\images\menu.importexport.png" />
<Content Include="Styles\menu.importexport-admin.css" />
<Content Include="Web.config" /> <Content Include="Web.config" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
@@ -75,7 +80,11 @@
<Compile Include="Migrations.cs" /> <Compile Include="Migrations.cs" />
<Compile Include="Models\RecipeResultRecord.cs" /> <Compile Include="Models\RecipeResultRecord.cs" />
<Compile Include="Models\RecipeStepResultRecord.cs" /> <Compile Include="Models\RecipeStepResultRecord.cs" />
<Compile Include="Models\VersionHistoryOptions.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="RecipeBuilders\DataRecipeBuilderStep.cs" />
<Compile Include="RecipeBuilders\SetupRecipeBuilderStep.cs" />
<Compile Include="RecipeBuilders\SiteSettingsBuilderStep.cs" />
<Compile Include="RecipeHandlers\CommandRecipeHandler.cs" /> <Compile Include="RecipeHandlers\CommandRecipeHandler.cs" />
<Compile Include="RecipeHandlers\DataRecipeHandler.cs" /> <Compile Include="RecipeHandlers\DataRecipeHandler.cs" />
<Compile Include="RecipeHandlers\FeatureRecipeHandler.cs" /> <Compile Include="RecipeHandlers\FeatureRecipeHandler.cs" />
@@ -85,6 +94,13 @@
<Compile Include="RecipeHandlers\SettingsRecipeHandler.cs" /> <Compile Include="RecipeHandlers\SettingsRecipeHandler.cs" />
<Compile Include="RecipeHandlers\ThemeRecipeHandler.cs" /> <Compile Include="RecipeHandlers\ThemeRecipeHandler.cs" />
<Compile Include="Routes.cs" /> <Compile Include="Routes.cs" />
<Compile Include="Services\BuildContext.cs" />
<Compile Include="Services\IRecipeExecutor.cs" />
<Compile Include="Services\RecipeExecutor.cs" />
<Compile Include="Services\IRecipeBuilder.cs" />
<Compile Include="Services\RecipeBuilder.cs" />
<Compile Include="Services\IRecipeBuilderStep.cs" />
<Compile Include="Services\RecipeBuilderStep.cs" />
<Compile Include="Services\RecipeHarvester.cs" /> <Compile Include="Services\RecipeHarvester.cs" />
<Compile Include="Services\RecipeManager.cs" /> <Compile Include="Services\RecipeManager.cs" />
<Compile Include="Services\RecipeParser.cs" /> <Compile Include="Services\RecipeParser.cs" />
@@ -92,6 +108,13 @@
<Compile Include="Services\RecipeScheduler.cs" /> <Compile Include="Services\RecipeScheduler.cs" />
<Compile Include="Services\RecipeStepExecutor.cs" /> <Compile Include="Services\RecipeStepExecutor.cs" />
<Compile Include="Services\RecipeStepQueue.cs" /> <Compile Include="Services\RecipeStepQueue.cs" />
<Compile Include="ViewModels\ContentTypeEntry.cs" />
<Compile Include="ViewModels\CustomStepEntry.cs" />
<Compile Include="ViewModels\DataExportStepViewModel.cs" />
<Compile Include="ViewModels\ImportResultViewModel.cs" />
<Compile Include="ViewModels\ImportViewModel.cs" />
<Compile Include="ViewModels\SetupRecipeStepViewModel.cs" />
<Compile Include="ViewModels\SiteSettingsStepViewModel.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\..\..\Orchard\Orchard.Framework.csproj"> <ProjectReference Include="..\..\..\Orchard\Orchard.Framework.csproj">
@@ -112,7 +135,25 @@
<Name>Orchard.Themes</Name> <Name>Orchard.Themes</Name>
</ProjectReference> </ProjectReference>
</ItemGroup> </ItemGroup>
<ItemGroup /> <ItemGroup>
<Content Include="Scripts\Web.config">
<SubType>Designer</SubType>
</Content>
</ItemGroup>
<ItemGroup>
<Content Include="Styles\Web.config">
<SubType>Designer</SubType>
</Content>
</ItemGroup>
<ItemGroup>
<Content Include="Views\EditorTemplates\ExportSteps\Data.cshtml" />
</ItemGroup>
<ItemGroup>
<Content Include="Views\EditorTemplates\ExportSteps\SetupRecipe.cshtml" />
</ItemGroup>
<ItemGroup>
<Content Include="Views\EditorTemplates\ExportSteps\SiteSettings.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

@@ -4,18 +4,18 @@ using System.Xml.Linq;
using Orchard.ContentManagement; using Orchard.ContentManagement;
using Orchard.ContentManagement.MetaData; using Orchard.ContentManagement.MetaData;
using Orchard.ContentManagement.MetaData.Models; using Orchard.ContentManagement.MetaData.Models;
using Orchard.ImportExport.Models;
using Orchard.ImportExport.Services;
using Orchard.ImportExport.ViewModels;
using Orchard.Localization; using Orchard.Localization;
using Orchard.Recipes.Models;
using Orchard.Recipes.Services;
using Orchard.Recipes.ViewModels;
namespace Orchard.ImportExport.Providers { namespace Orchard.Recipes.RecipeBuilders {
public class DataExportStep : ExportStepProvider { public class DataRecipeBuilderStep : RecipeBuilderStep {
private readonly IContentDefinitionManager _contentDefinitionManager; private readonly IContentDefinitionManager _contentDefinitionManager;
private readonly IOrchardServices _orchardServices; private readonly IOrchardServices _orchardServices;
private readonly IContentDefinitionWriter _contentDefinitionWriter; private readonly IContentDefinitionWriter _contentDefinitionWriter;
public DataExportStep( public DataRecipeBuilderStep(
IContentDefinitionManager contentDefinitionManager, IContentDefinitionManager contentDefinitionManager,
IOrchardServices orchardServices, IOrchardServices orchardServices,
IContentDefinitionWriter contentDefinitionWriter) { IContentDefinitionWriter contentDefinitionWriter) {
@@ -37,7 +37,7 @@ namespace Orchard.ImportExport.Providers {
get { return T("Exports content items and content item definitions."); } get { return T("Exports content items and content item definitions."); }
} }
public override int Position { get { return 10; } } public override int Priority { get { return 10; } }
public IList<string> SchemaContentTypes { get; set; } public IList<string> SchemaContentTypes { get; set; }
public IList<string> DataContentTypes { get; set; } public IList<string> DataContentTypes { get; set; }
@@ -67,7 +67,7 @@ namespace Orchard.ImportExport.Providers {
return shapeFactory.EditorTemplate(TemplateName: "ExportSteps/Data", Model: viewModel, Prefix: Prefix); return shapeFactory.EditorTemplate(TemplateName: "ExportSteps/Data", Model: viewModel, Prefix: Prefix);
} }
public override void Export(ExportContext context) { public override void Build(BuildContext context) {
var dataContentTypes = DataContentTypes; var dataContentTypes = DataContentTypes;
var schemaContentTypes = SchemaContentTypes; var schemaContentTypes = SchemaContentTypes;
var exportVersionOptions = GetContentExportVersionOptions(VersionHistoryOptions); var exportVersionOptions = GetContentExportVersionOptions(VersionHistoryOptions);
@@ -76,10 +76,10 @@ namespace Orchard.ImportExport.Providers {
: Enumerable.Empty<ContentItem>(); : Enumerable.Empty<ContentItem>();
if(schemaContentTypes.Any()) if(schemaContentTypes.Any())
context.Document.Element("Orchard").Add(ExportMetadata(schemaContentTypes)); context.RecipeDocument.Element("Orchard").Add(ExportMetadata(schemaContentTypes));
if(contentItems.Any()) if(contentItems.Any())
context.Document.Element("Orchard").Add(ExportData(dataContentTypes, contentItems, ImportBatchSize)); context.RecipeDocument.Element("Orchard").Add(ExportData(dataContentTypes, contentItems, ImportBatchSize));
} }
private XElement ExportMetadata(IEnumerable<string> contentTypes) { private XElement ExportMetadata(IEnumerable<string> contentTypes) {

View File

@@ -1,12 +1,12 @@
using Orchard.ContentManagement; using Orchard.ContentManagement;
using Orchard.ImportExport.Services;
using Orchard.ImportExport.ViewModels;
using Orchard.Localization; using Orchard.Localization;
using Orchard.Recipes.Services;
using Orchard.Recipes.ViewModels;
namespace Orchard.ImportExport.Providers { namespace Orchard.Recipes.RecipeBuilders {
public class SetupRecipeExportStep : ExportStepProvider { public class SetupRecipeBuilderStep : RecipeBuilderStep {
private readonly IOrchardServices _orchardServices; private readonly IOrchardServices _orchardServices;
public SetupRecipeExportStep(IOrchardServices orchardServices) { public SetupRecipeBuilderStep(IOrchardServices orchardServices) {
_orchardServices = orchardServices; _orchardServices = orchardServices;
} }
@@ -22,7 +22,7 @@ namespace Orchard.ImportExport.Providers {
get { return T("Turns the export file into a Setup recipe."); } get { return T("Turns the export file into a Setup recipe."); }
} }
public override int Position { get { return -10; } } public override int Priority { get { return -10; } }
public string RecipeName { get; set; } public string RecipeName { get; set; }
public string RecipeDescription { get; set; } public string RecipeDescription { get; set; }
@@ -54,8 +54,8 @@ namespace Orchard.ImportExport.Providers {
return shapeFactory.EditorTemplate(TemplateName: "ExportSteps/SetupRecipe", Model: viewModel, Prefix: Prefix); return shapeFactory.EditorTemplate(TemplateName: "ExportSteps/SetupRecipe", Model: viewModel, Prefix: Prefix);
} }
public override void Export(ExportContext context) { public override void Build(BuildContext context) {
var recipeElement = context.Document.Element("Orchard").Element("Recipe"); var recipeElement = context.RecipeDocument.Element("Orchard").Element("Recipe");
recipeElement.SetElementValue("Name", RecipeName); recipeElement.SetElementValue("Name", RecipeName);
recipeElement.SetElementValue("Description", RecipeDescription); recipeElement.SetElementValue("Description", RecipeDescription);

View File

@@ -2,15 +2,15 @@
using System.Linq; using System.Linq;
using System.Xml.Linq; using System.Xml.Linq;
using Orchard.ContentManagement; using Orchard.ContentManagement;
using Orchard.ImportExport.Services;
using Orchard.ImportExport.ViewModels;
using Orchard.Localization; using Orchard.Localization;
using Orchard.Recipes.Services;
using Orchard.Recipes.ViewModels;
namespace Orchard.ImportExport.Providers { namespace Orchard.Recipes.RecipeBuilders {
public class SiteSettingsExportStep : ExportStepProvider { public class SiteSettingsBuilderStep : RecipeBuilderStep {
private readonly IOrchardServices _orchardServices; private readonly IOrchardServices _orchardServices;
public SiteSettingsExportStep(IOrchardServices orchardServices) { public SiteSettingsBuilderStep(IOrchardServices orchardServices) {
_orchardServices = orchardServices; _orchardServices = orchardServices;
} }
@@ -26,7 +26,7 @@ namespace Orchard.ImportExport.Providers {
get { return T("Exports site settings."); } get { return T("Exports site settings."); }
} }
public override int Position { get { return 20; } } public override int Priority { get { return 20; } }
public override dynamic BuildEditor(dynamic shapeFactory) { public override dynamic BuildEditor(dynamic shapeFactory) {
return UpdateEditor(shapeFactory, null); return UpdateEditor(shapeFactory, null);
@@ -37,8 +37,8 @@ namespace Orchard.ImportExport.Providers {
return shapeFactory.EditorTemplate(TemplateName: "ExportSteps/SiteSettings", Model: viewModel, Prefix: Prefix); return shapeFactory.EditorTemplate(TemplateName: "ExportSteps/SiteSettings", Model: viewModel, Prefix: Prefix);
} }
public override void Export(ExportContext context) { public override void Build(BuildContext context) {
context.Document.Element("Orchard").Add(ExportSiteSettings()); context.RecipeDocument.Element("Orchard").Add(ExportSiteSettings());
} }
private XElement ExportSiteSettings() { private XElement ExportSiteSettings() {

View File

@@ -0,0 +1,7 @@
using System.Xml.Linq;
namespace Orchard.Recipes.Services {
public class BuildContext {
public XDocument RecipeDocument { get; set; }
}
}

View File

@@ -0,0 +1,7 @@
using System.Collections.Generic;
namespace Orchard.Recipes.Services {
public interface IRecipeBuilder : IDependency {
string Build(IEnumerable<IRecipeBuilderStep> steps);
}
}

View File

@@ -1,14 +1,14 @@
using Orchard.ContentManagement; using Orchard.ContentManagement;
using Orchard.Localization; using Orchard.Localization;
namespace Orchard.ImportExport.Services { namespace Orchard.Recipes.Services {
public interface IExportStepProvider : IDependency { public interface IRecipeBuilderStep : IDependency {
string Name { get; } string Name { get; }
LocalizedString DisplayName { get; } LocalizedString DisplayName { get; }
LocalizedString Description { get; } LocalizedString Description { get; }
int Position { get; } int Priority { get; }
dynamic BuildEditor(dynamic shapeFactory); dynamic BuildEditor(dynamic shapeFactory);
dynamic UpdateEditor(dynamic shapeFactory, IUpdateModel updater); dynamic UpdateEditor(dynamic shapeFactory, IUpdateModel updater);
void Export(ExportContext context); void Build(BuildContext context);
} }
} }

View File

@@ -0,0 +1,5 @@
namespace Orchard.Recipes.Services {
public interface IRecipeExecutor : IDependency {
string Execute(string recipeText);
}
}

View File

@@ -0,0 +1,31 @@
using System.Collections.Generic;
using System.Xml.Linq;
namespace Orchard.Recipes.Services {
public class RecipeBuilder : Component, IRecipeBuilder {
public string Build(IEnumerable<IRecipeBuilderStep> steps) {
var exportDocument = CreateRecipeRoot();
var context = new BuildContext {
RecipeDocument = CreateRecipeRoot()
};
foreach (var step in steps) {
step.Build(context);
}
return exportDocument.ToString();
}
private XDocument CreateRecipeRoot() {
var recipeRoot = new XDocument(
new XDeclaration("1.0", "", "yes"),
new XComment("Exported from Orchard"),
new XElement("Orchard",
new XElement("Recipe")
)
);
return recipeRoot;
}
}
}

View File

@@ -1,12 +1,12 @@
using Orchard.ContentManagement; using Orchard.ContentManagement;
using Orchard.Localization; using Orchard.Localization;
namespace Orchard.ImportExport.Services { namespace Orchard.Recipes.Services {
public abstract class ExportStepProvider : Component, IExportStepProvider { public abstract class RecipeBuilderStep : Component, IRecipeBuilderStep {
public abstract string Name { get; } public abstract string Name { get; }
public abstract LocalizedString DisplayName { get; } public abstract LocalizedString DisplayName { get; }
public abstract LocalizedString Description { get; } public abstract LocalizedString Description { get; }
public virtual int Position { get { return 0; } } public virtual int Priority { get { return 0; } }
protected virtual string Prefix { protected virtual string Prefix {
get { return GetType().Name; } get { return GetType().Name; }
@@ -20,6 +20,6 @@ namespace Orchard.ImportExport.Services {
return null; return null;
} }
public virtual void Export(ExportContext context) {} public virtual void Build(BuildContext context) {}
} }
} }

View File

@@ -0,0 +1,31 @@
using Orchard.Environment.Descriptor;
namespace Orchard.Recipes.Services {
public class RecipeExecutor : Component, IRecipeExecutor {
private readonly IRecipeParser _recipeParser;
private readonly IRecipeManager _recipeManager;
private readonly IShellDescriptorManager _shellDescriptorManager;
public RecipeExecutor(
IRecipeParser recipeParser,
IRecipeManager recipeManager,
IShellDescriptorManager shellDescriptorManager) {
_recipeParser = recipeParser;
_recipeManager = recipeManager;
_shellDescriptorManager = shellDescriptorManager;
}
public string Execute(string recipeText) {
var recipe = _recipeParser.ParseRecipe(recipeText);
var executionId = _recipeManager.Execute(recipe);
UpdateShell();
return executionId;
}
private void UpdateShell() {
var descriptor = _shellDescriptorManager.GetShellDescriptor();
_shellDescriptorManager.UpdateShellDescriptor(descriptor.SerialNumber, descriptor.Features, descriptor.Parameters);
}
}
}

View File

@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
<staticContent>
<clientCache cacheControlMode="UseMaxAge" cacheControlMaxAge="7.00:00:00" />
</staticContent>
<handlers accessPolicy="Script,Read">
<!--
iis7 - for any request to a file exists on disk, return it via native http module.
accessPolicy 'Script' is to allow for a managed 404 page.
-->
<add name="StaticFile" path="*" verb="*" modules="StaticFileModule" preCondition="integratedMode" resourceType="File" requireAccess="Read" />
</handlers>
</system.webServer>
</configuration>

View File

@@ -0,0 +1,9 @@
fieldset.export-step-data table.items {
width: 500px;
margin: 0;
}
fieldset.export-step-data table.items td,
fieldset.export-step-data table.items thead tr.sub th {
padding: 0 12px;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -0,0 +1,6 @@
.navicon-import-export {
background-image:url(images/menu.importexport.png) !important;
}
.navicon-import-export:hover {
background-position:0 -30px !important;
}

View File

@@ -1,4 +1,4 @@
namespace Orchard.ImportExport.ViewModels { namespace Orchard.Recipes.ViewModels {
public class ContentTypeEntry { public class ContentTypeEntry {
public string Name { get; set; } public string Name { get; set; }
public string DisplayName { get; set; } public string DisplayName { get; set; }

View File

@@ -0,0 +1,6 @@
namespace Orchard.Recipes.ViewModels {
public class CustomStepEntry {
public string CustomStep { get; set; }
public bool IsChecked { get; set; }
}
}

View File

@@ -1,7 +1,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using Orchard.ImportExport.Models; using Orchard.Recipes.Models;
namespace Orchard.ImportExport.ViewModels { namespace Orchard.Recipes.ViewModels {
public class DataExportStepViewModel { public class DataExportStepViewModel {
public DataExportStepViewModel() { public DataExportStepViewModel() {
ContentTypes = new List<ContentTypeEntry>(); ContentTypes = new List<ContentTypeEntry>();

View File

@@ -0,0 +1,7 @@
using Orchard.Recipes.Models;
namespace Orchard.Recipes.ViewModels {
public class ImportResultViewModel {
public RecipeResult Result { get; set; }
}
}

View File

@@ -0,0 +1,4 @@
namespace Orchard.Recipes.ViewModels {
public class ImportViewModel {
}
}

View File

@@ -1,4 +1,4 @@
namespace Orchard.ImportExport.ViewModels { namespace Orchard.Recipes.ViewModels {
public class SetupRecipeStepViewModel { public class SetupRecipeStepViewModel {
public string RecipeName { get; set; } public string RecipeName { get; set; }
public string RecipeDescription { get; set; } public string RecipeDescription { get; set; }

View File

@@ -1,3 +1,3 @@
namespace Orchard.ImportExport.ViewModels { namespace Orchard.Recipes.ViewModels {
public class SiteSettingsStepViewModel {} public class SiteSettingsStepViewModel {}
} }

View File

@@ -1,4 +1,4 @@
@model Orchard.ImportExport.ViewModels.DataExportStepViewModel @model Orchard.Recipes.ViewModels.DataExportStepViewModel
@{ @{
Style.Include("exportstep-data.css"); Style.Include("exportstep-data.css");
Script.Require("jQuery"); Script.Require("jQuery");

View File

@@ -1,4 +1,4 @@
@model Orchard.ImportExport.ViewModels.SetupRecipeStepViewModel @model Orchard.Recipes.ViewModels.SetupRecipeStepViewModel
<div> <div>
@Html.LabelFor(m => m.RecipeName, T("Name")) @Html.LabelFor(m => m.RecipeName, T("Name"))
@Html.TextBoxFor(m => m.RecipeName, new { @class = "text medium" }) @Html.TextBoxFor(m => m.RecipeName, new { @class = "text medium" })

View File

@@ -1,2 +1,2 @@
@model Orchard.ImportExport.ViewModels.SiteSettingsStepViewModel @model Orchard.Recipes.ViewModels.SiteSettingsStepViewModel
@Html.Hint(T("Please verify that you are not exporting confidential information, such as passwords or application keys.")) @Html.Hint(T("Please verify that you are not exporting confidential information, such as passwords or application keys."))