mirror of
https://github.com/OrchardCMS/Orchard.git
synced 2025-09-19 18:27:55 +08:00
Updated command line support for import/export.
- Added export file switch. - Added config file switch for both import and export commands. - Minor refactoring.
This commit is contained in:
@@ -1,14 +1,13 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
using Orchard.Commands;
|
||||
using Orchard.ContentManagement;
|
||||
using Orchard.ContentManagement.MetaData;
|
||||
using Orchard.ImportExport.Recipes.Builders;
|
||||
using Orchard.ImportExport.Models;
|
||||
using Orchard.ImportExport.Services;
|
||||
using Orchard.Recipes.Models;
|
||||
using Orchard.Recipes.Providers.Builders;
|
||||
using Orchard.Recipes.Services;
|
||||
using Orchard.Security;
|
||||
using Orchard.Settings;
|
||||
|
||||
@@ -19,27 +18,26 @@ namespace Orchard.ImportExport.Commands {
|
||||
private readonly ISiteService _siteService;
|
||||
private readonly IMembershipService _membershipService;
|
||||
private readonly IAuthenticationService _authenticationService;
|
||||
private readonly IOrchardServices _orchardServices;
|
||||
|
||||
public ImportExportCommands(
|
||||
IImportExportService importExportService,
|
||||
IContentDefinitionManager contentDefinitionManager,
|
||||
ISiteService siteService,
|
||||
IMembershipService membershipService,
|
||||
IAuthenticationService authenticationService,
|
||||
IOrchardServices orchardServices) {
|
||||
IAuthenticationService authenticationService) {
|
||||
|
||||
_importExportService = importExportService;
|
||||
_contentDefinitionManager = contentDefinitionManager;
|
||||
_siteService = siteService;
|
||||
_membershipService = membershipService;
|
||||
_authenticationService = authenticationService;
|
||||
_orchardServices = orchardServices;
|
||||
}
|
||||
|
||||
[OrchardSwitch]
|
||||
public string Filename { get; set; }
|
||||
[OrchardSwitch]
|
||||
public string ConfigFilename { get; set; }
|
||||
[OrchardSwitch]
|
||||
public string Types { get; set; }
|
||||
[OrchardSwitch]
|
||||
public bool Metadata { get; set; }
|
||||
@@ -53,10 +51,9 @@ namespace Orchard.ImportExport.Commands {
|
||||
public bool SiteSettings { get; set; }
|
||||
|
||||
[CommandName("import file")]
|
||||
[CommandHelp("import file /Filename:<path> \r\n\t" + "Imports the content of a file.")]
|
||||
[OrchardSwitches("Filename")]
|
||||
[CommandHelp("import file /Filename:<path> [/ConfigFilename:<configFilename>]\r\n\t" + "Imports the content of a file.")]
|
||||
[OrchardSwitches("Filename,ConfigFilename")]
|
||||
public void ImportFile() {
|
||||
|
||||
if (String.IsNullOrEmpty(Filename)) {
|
||||
Context.Output.WriteLine(T("Invalid file path"));
|
||||
return;
|
||||
@@ -67,66 +64,113 @@ namespace Orchard.ImportExport.Commands {
|
||||
return;
|
||||
}
|
||||
|
||||
// Impersonate the Site owner.
|
||||
ImpersonateSuperUser();
|
||||
|
||||
// Read config file if specified.
|
||||
var configurationDocument = ReadImportConfigurationFile(ConfigFilename);
|
||||
|
||||
// Configure any steps based on the configuration.
|
||||
_importExportService.ConfigureImportActions(new ConfigureImportActionsContext(configurationDocument));
|
||||
|
||||
// Import the file.
|
||||
_importExportService.Import(File.ReadAllText(Filename));
|
||||
|
||||
Context.Output.WriteLine(T("Import running..."));
|
||||
}
|
||||
|
||||
[CommandName("export file")]
|
||||
[CommandHelp("export file [/Types:<type-name-1>, ... ,<type-name-n>] [/Metadata:true|false] [/Data:true|false] [/Version:Published|Draft|Latest] [/SiteSettings:true|false] [/Steps:<custom-step-1>, ... ,<custom-step-n>]\r\n\t" + "Create an export file according to the specified options.")]
|
||||
[OrchardSwitches("Types,Metadata,Data,Version,SiteSettings,Steps")]
|
||||
[CommandHelp("export file [/Filename:<path>] [/ConfigFilename:<path>] [/Types:<type-name-1>, ... ,<type-name-n>] [/Metadata:true|false] [/Data:true|false] [/Version:Published|Draft|Latest] [/SiteSettings:true|false] [/Steps:<custom-step-1>, ... ,<custom-step-n>]\r\n\t" + "Create an export file according to the specified options.")]
|
||||
[OrchardSwitches("Filename,ConfigFilename,Types,Metadata,Data,Version,SiteSettings,Steps")]
|
||||
public void ExportFile() {
|
||||
// Impersonate the Site owner.
|
||||
var superUser = _siteService.GetSiteSettings().SuperUser;
|
||||
var owner = _membershipService.GetUser(superUser);
|
||||
_authenticationService.SetAuthenticatedUserForRequest(owner);
|
||||
ImpersonateSuperUser();
|
||||
|
||||
var versionOption = VersionHistoryOptions.Published;
|
||||
// Read config file if specified.
|
||||
var configurationDocument = UpdateExportConfiguration(ReadExportConfigurationFile(ConfigFilename), Types, Metadata, Data, Version, SiteSettings, Steps);
|
||||
|
||||
if (!String.IsNullOrEmpty(Version) && !Enum.TryParse(Version, out versionOption)) {
|
||||
Context.Output.WriteLine(T("Invalid version option"));
|
||||
return;
|
||||
}
|
||||
|
||||
var enteredTypes = (Types ?? String.Empty).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
|
||||
var exportTypes = _contentDefinitionManager
|
||||
.ListTypeDefinitions()
|
||||
.Where(contentType => enteredTypes.Contains(contentType.Name))
|
||||
.Select(contentType => contentType.Name)
|
||||
.ToList();
|
||||
|
||||
var enteredSteps = (Steps ?? String.Empty).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
var recipeBuilderSteps = new List<IRecipeBuilderStep>();
|
||||
|
||||
if (Metadata || Data) {
|
||||
var dataStep = _orchardServices.WorkContext.Resolve<ContentStep>();
|
||||
|
||||
if(Data)
|
||||
dataStep.DataContentTypes = exportTypes;
|
||||
|
||||
if(Metadata)
|
||||
dataStep.SchemaContentTypes = exportTypes;
|
||||
|
||||
dataStep.VersionHistoryOptions = versionOption;
|
||||
recipeBuilderSteps.Add(dataStep);
|
||||
}
|
||||
|
||||
if (SiteSettings) {
|
||||
var siteSettingsStep = _orchardServices.WorkContext.Resolve<SettingsStep>();
|
||||
recipeBuilderSteps.Add(siteSettingsStep);
|
||||
}
|
||||
|
||||
if (enteredSteps.Any()) {
|
||||
var customStepsStep = _orchardServices.WorkContext.Resolve<CustomStepsStep>();
|
||||
recipeBuilderSteps.Add(customStepsStep);
|
||||
}
|
||||
// Get all the steps based on the configuration.
|
||||
var actions = _importExportService.ParseExportActions(configurationDocument);
|
||||
|
||||
Context.Output.WriteLine(T("Export starting..."));
|
||||
var exportContext = new ExportActionContext();
|
||||
_importExportService.Export(exportContext, actions);
|
||||
var exportFilePath = _importExportService.WriteExportFile(exportContext.RecipeDocument);
|
||||
|
||||
var exportFilePath = _importExportService.Export(recipeBuilderSteps);
|
||||
if (!String.IsNullOrEmpty(Filename)) {
|
||||
var directory = Path.GetDirectoryName(Filename);
|
||||
if (!Directory.Exists(directory))
|
||||
Directory.CreateDirectory(directory);
|
||||
File.Copy(exportFilePath, Filename, overwrite: true);
|
||||
exportFilePath = Filename;
|
||||
}
|
||||
|
||||
Context.Output.WriteLine(T("Export completed at {0}", exportFilePath));
|
||||
}
|
||||
|
||||
private XDocument UpdateExportConfiguration(XDocument configurationDocument, string types, bool metadata, bool data, string version, bool siteSettings, string customSteps) {
|
||||
var buildRecipeElement = GetOrCreateElement(configurationDocument.Root, "BuildRecipe");
|
||||
var stepsElement = GetOrCreateElement(buildRecipeElement, "Steps");
|
||||
|
||||
if (metadata || data) {
|
||||
var contentStepElement = GetOrCreateElement(stepsElement, "Content");
|
||||
var enteredTypes = (types ?? String.Empty).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
|
||||
var exportTypes = _contentDefinitionManager
|
||||
.ListTypeDefinitions()
|
||||
.Where(contentType => enteredTypes.Contains(contentType.Name))
|
||||
.Select(contentType => contentType.Name)
|
||||
.ToList();
|
||||
|
||||
if (data)
|
||||
contentStepElement.Attr("DataContentTypes", String.Join(",", exportTypes));
|
||||
|
||||
if (metadata)
|
||||
contentStepElement.Attr("SchemaContentTypes", String.Join(",", exportTypes));
|
||||
|
||||
if (!String.IsNullOrEmpty(version)) {
|
||||
VersionHistoryOptions versionHistoryOptions;
|
||||
if (Enum.TryParse(version, true, out versionHistoryOptions)) {
|
||||
contentStepElement.Attr("VersionHistoryOptions", versionHistoryOptions);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (siteSettings) {
|
||||
GetOrCreateElement(stepsElement, "Settings");
|
||||
}
|
||||
|
||||
if (!String.IsNullOrEmpty(customSteps)) {
|
||||
var customStepsElement = GetOrCreateElement(stepsElement, "CustomSteps");
|
||||
customStepsElement.Attr("Steps", customSteps);
|
||||
}
|
||||
|
||||
return configurationDocument;
|
||||
}
|
||||
|
||||
private void ImpersonateSuperUser() {
|
||||
var superUser = _siteService.GetSiteSettings().SuperUser;
|
||||
var owner = _membershipService.GetUser(superUser);
|
||||
_authenticationService.SetAuthenticatedUserForRequest(owner);
|
||||
}
|
||||
|
||||
private XDocument ReadExportConfigurationFile(string filePath) {
|
||||
return !String.IsNullOrEmpty(filePath) && File.Exists(filePath) ? XDocument.Load(filePath) : new XDocument(new XElement("Export"));
|
||||
}
|
||||
|
||||
private XDocument ReadImportConfigurationFile(string filePath) {
|
||||
return !String.IsNullOrEmpty(filePath) && File.Exists(filePath) ? XDocument.Load(filePath) : new XDocument(new XElement("Import"));
|
||||
}
|
||||
|
||||
private XElement GetOrCreateElement(XElement element, string childElementName) {
|
||||
var childElement = element.Element(childElementName);
|
||||
|
||||
if (childElement == null) {
|
||||
childElement = new XElement(childElementName);
|
||||
element.Add(childElement);
|
||||
}
|
||||
|
||||
return childElement;
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,4 +1,5 @@
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Web.Mvc;
|
||||
using Orchard.ContentManagement;
|
||||
@@ -64,12 +65,12 @@ namespace Orchard.ImportExport.Controllers {
|
||||
return View(viewModel);
|
||||
}
|
||||
|
||||
var context = new ImportActionContext { ActionResult = RedirectToAction("Import") };
|
||||
foreach(var action in actions) {
|
||||
action.Execute(context);
|
||||
}
|
||||
var context = new ImportActionContext();
|
||||
var executionId = _importExportService.Import(context, actions);
|
||||
|
||||
return context.ActionResult;
|
||||
return !String.IsNullOrEmpty(executionId)
|
||||
? RedirectToAction("ImportResult", new { executionId = context.ExecutionId })
|
||||
: RedirectToAction("Import");
|
||||
}
|
||||
|
||||
public ActionResult ImportResult(string executionId) {
|
||||
@@ -105,15 +106,15 @@ namespace Orchard.ImportExport.Controllers {
|
||||
action.UpdateEditor(Services.New, this);
|
||||
}
|
||||
|
||||
var exportActionContext = new ExportActionContext {
|
||||
ActionResult = RedirectToAction("Export")
|
||||
};
|
||||
var exportActionContext = new ExportActionContext();
|
||||
_importExportService.Export(exportActionContext, actions);
|
||||
|
||||
foreach (var action in actions) {
|
||||
action.Execute(exportActionContext);
|
||||
}
|
||||
var recipeDocument = exportActionContext.RecipeDocument;
|
||||
var exportFilePath = _importExportService.WriteExportFile(recipeDocument);
|
||||
var recipe = _recipeParser.ParseRecipe(recipeDocument);
|
||||
var exportFileName = recipe.GetExportFileName();
|
||||
|
||||
return exportActionContext.ActionResult;
|
||||
return File(exportFilePath, "text/xml", exportFileName);
|
||||
}
|
||||
|
||||
bool IUpdateModel.TryUpdateModel<TModel>(TModel model, string prefix, string[] includeProperties, string[] excludeProperties) {
|
||||
|
@@ -0,0 +1,12 @@
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Orchard.ImportExport.Models {
|
||||
public class ConfigureImportActionsContext {
|
||||
|
||||
public ConfigureImportActionsContext(XDocument configurationDocument) {
|
||||
ConfigurationDocument = configurationDocument;
|
||||
}
|
||||
|
||||
public XDocument ConfigurationDocument { get; set; }
|
||||
}
|
||||
}
|
@@ -1,7 +1,10 @@
|
||||
using System.Web.Mvc;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Orchard.ImportExport.Services {
|
||||
namespace Orchard.ImportExport.Models {
|
||||
public class ExportActionContext {
|
||||
public ActionResult ActionResult { get; set; }
|
||||
public ExportActionContext() {
|
||||
RecipeDocument = new XDocument();
|
||||
}
|
||||
public XDocument RecipeDocument { get; set; }
|
||||
}
|
||||
}
|
@@ -1,7 +1,6 @@
|
||||
using System.Xml.Linq;
|
||||
using Orchard.ImportExport.Models;
|
||||
|
||||
namespace Orchard.ImportExport.Services {
|
||||
namespace Orchard.ImportExport.Models {
|
||||
public class ExportContext {
|
||||
public XDocument Document { get; set; }
|
||||
public ExportOptions ExportOptions { get; set; }
|
@@ -3,7 +3,7 @@ using Orchard.Recipes.Models;
|
||||
|
||||
namespace Orchard.ImportExport.Models {
|
||||
public class ImportActionConfigurationContext : ConfigurationContext {
|
||||
protected ImportActionConfigurationContext(XElement configurationElement) : base(configurationElement) {
|
||||
public ImportActionConfigurationContext(XElement configurationElement) : base(configurationElement) {
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,7 +1,8 @@
|
||||
using System.Web.Mvc;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Orchard.ImportExport.Models {
|
||||
public class ImportActionContext {
|
||||
public ActionResult ActionResult { get; set; }
|
||||
public XDocument RecipeDocument { get; set; }
|
||||
public string ExecutionId { get; set; }
|
||||
}
|
||||
}
|
@@ -1,7 +1,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Orchard.ImportExport.Services {
|
||||
namespace Orchard.ImportExport.Models {
|
||||
public class SetupContext {
|
||||
public string SiteName { get; set; }
|
||||
public string AdminUsername { get; set; }
|
@@ -78,6 +78,7 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="AdminMenu.cs" />
|
||||
<Compile Include="Models\ConfigureImportActionsContext.cs" />
|
||||
<Compile Include="Commands\ImportExportCommands.cs" />
|
||||
<Compile Include="Controllers\AdminController.cs" />
|
||||
<Compile Include="Models\ExportOptions.cs" />
|
||||
@@ -88,16 +89,16 @@
|
||||
<Compile Include="Models\ImportActionConfigurationContext.cs" />
|
||||
<Compile Include="ViewModels\RecipeExecutionStepViewModel.cs" />
|
||||
<Compile Include="Services\ISetupService.cs" />
|
||||
<Compile Include="Services\SetupContext.cs" />
|
||||
<Compile Include="Models\SetupContext.cs" />
|
||||
<Compile Include="Services\SetupService.cs" />
|
||||
<Compile Include="ViewModels\UploadRecipeViewModel.cs" />
|
||||
<Compile Include="Providers\ImportActions\UploadRecipeAction.cs" />
|
||||
<Compile Include="Providers\ImportActions\ExecuteRecipeAction.cs" />
|
||||
<Compile Include="Recipes\Builders\CustomStepsStep.cs" />
|
||||
<Compile Include="Services\ImportAction.cs" />
|
||||
<Compile Include="Services\ExportAction.cs" />
|
||||
<Compile Include="Models\ImportActionContext.cs" />
|
||||
<Compile Include="Models\ExportActionContext.cs" />
|
||||
<Compile Include="Services\ExportContext.cs" />
|
||||
<Compile Include="Models\ExportContext.cs" />
|
||||
<Compile Include="Services\IImportAction.cs" />
|
||||
<Compile Include="Services\IExportAction.cs" />
|
||||
<Compile Include="ViewModels\CustomStepEntry.cs" />
|
||||
@@ -158,7 +159,7 @@
|
||||
<Content Include="Views\Admin\ImportResult.cshtml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="Views\EditorTemplates\ImportActions\UploadRecipe.cshtml" />
|
||||
<Content Include="Views\EditorTemplates\ImportActions\ExecuteRecipe.cshtml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="Views\EditorTemplates\BuilderSteps\CustomSteps.cshtml" />
|
||||
|
@@ -1,7 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Web.Mvc;
|
||||
using Orchard.ContentManagement;
|
||||
using Orchard.ImportExport.Models;
|
||||
using Orchard.ImportExport.Services;
|
||||
@@ -9,18 +8,15 @@ 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 BuildRecipeAction : ExportAction {
|
||||
private readonly IEnumerable<IRecipeBuilderStep> _recipeBuilderSteps;
|
||||
private readonly IImportExportService _importExportService;
|
||||
private readonly IRecipeParser _recipeParser;
|
||||
private readonly IRecipeBuilder _recipeBuilder;
|
||||
|
||||
public BuildRecipeAction(IEnumerable<IRecipeBuilderStep> recipeBuilderSteps, IImportExportService importExportService, IRecipeParser recipeParser) {
|
||||
public BuildRecipeAction(IEnumerable<IRecipeBuilderStep> recipeBuilderSteps, IRecipeBuilder recipeBuilder) {
|
||||
_recipeBuilderSteps = recipeBuilderSteps;
|
||||
_importExportService = importExportService;
|
||||
_recipeParser = recipeParser;
|
||||
_recipeBuilder = recipeBuilder;
|
||||
|
||||
RecipeBuilderSteps = new List<IRecipeBuilderStep>();
|
||||
}
|
||||
@@ -67,44 +63,25 @@ namespace Orchard.ImportExport.Providers.ExportActions {
|
||||
}
|
||||
|
||||
public override void Configure(ExportActionConfigurationContext context) {
|
||||
RecipeBuilderSteps.Clear();
|
||||
|
||||
var recipeBuilderStepsElement = context.ConfigurationElement.Element("Steps");
|
||||
if (recipeBuilderStepsElement == null)
|
||||
return;
|
||||
|
||||
foreach (var step in _recipeBuilderSteps) {
|
||||
var stepConfigurationElement = recipeBuilderStepsElement.Element(step.Name);
|
||||
foreach (var stepElement in recipeBuilderStepsElement.Elements()) {
|
||||
var step = _recipeBuilderSteps.SingleOrDefault(x => x.Name == stepElement.Name.LocalName);
|
||||
|
||||
if (stepConfigurationElement != null) {
|
||||
var stepContext = new RecipeBuilderStepConfigurationContext(stepConfigurationElement);
|
||||
if (step != null) {
|
||||
var stepContext = new RecipeBuilderStepConfigurationContext(stepElement);
|
||||
step.Configure(stepContext);
|
||||
RecipeBuilderSteps.Add(step);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void Execute(ExportActionContext context) {
|
||||
var recipeDocument = _importExportService.Export(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) {
|
||||
string format;
|
||||
|
||||
if (String.IsNullOrWhiteSpace(recipe.Name) && String.IsNullOrWhiteSpace(recipe.Version))
|
||||
format = "export.xml";
|
||||
else if (String.IsNullOrWhiteSpace(recipe.Version))
|
||||
format = "{0}.recipe.xml";
|
||||
else if (String.IsNullOrWhiteSpace(recipe.Name))
|
||||
format = "export-{1}.recipe.xml";
|
||||
else
|
||||
format = "{0}-{1}.recipe.xml";
|
||||
|
||||
return String.Format(format, recipe.Name.HtmlClassify(), recipe.Version);
|
||||
context.RecipeDocument = _recipeBuilder.Build(RecipeBuilderSteps);
|
||||
}
|
||||
}
|
||||
}
|
@@ -2,8 +2,6 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Web.Mvc;
|
||||
using System.Web.Routing;
|
||||
using System.Xml.Linq;
|
||||
using Orchard.ContentManagement;
|
||||
using Orchard.Environment.Configuration;
|
||||
@@ -17,31 +15,34 @@ using Orchard.Recipes.Services;
|
||||
using Orchard.UI.Notify;
|
||||
|
||||
namespace Orchard.ImportExport.Providers.ImportActions {
|
||||
public class UploadRecipeAction : ImportAction {
|
||||
public class ExecuteRecipeAction : ImportAction {
|
||||
private readonly IOrchardServices _orchardServices;
|
||||
private readonly IImportExportService _importExportService;
|
||||
private readonly ISetupService _setupService;
|
||||
private readonly ShellSettings _shellSettings;
|
||||
private readonly IFeatureManager _featureManager;
|
||||
private readonly IEnumerable<IRecipeExecutionStep> _recipeExecutionSteps;
|
||||
private readonly IRecipeParser _recipeParser;
|
||||
private readonly IRecipeExecutor _recipeExecutor;
|
||||
|
||||
public UploadRecipeAction(
|
||||
public ExecuteRecipeAction(
|
||||
IOrchardServices orchardServices,
|
||||
IImportExportService importExportService,
|
||||
ISetupService setupService,
|
||||
ShellSettings shellSettings,
|
||||
IFeatureManager featureManager,
|
||||
IEnumerable<IRecipeExecutionStep> recipeExecutionSteps) {
|
||||
IEnumerable<IRecipeExecutionStep> recipeExecutionSteps,
|
||||
IRecipeParser recipeParser,
|
||||
IRecipeExecutor recipeExecutor) {
|
||||
|
||||
_orchardServices = orchardServices;
|
||||
_importExportService = importExportService;
|
||||
_setupService = setupService;
|
||||
_shellSettings = shellSettings;
|
||||
_featureManager = featureManager;
|
||||
_recipeExecutionSteps = recipeExecutionSteps;
|
||||
_recipeParser = recipeParser;
|
||||
_recipeExecutor = recipeExecutor;
|
||||
}
|
||||
|
||||
public override string Name { get { return "UploadRecipe"; } }
|
||||
public override string Name { get { return "ExecuteRecipe"; } }
|
||||
|
||||
public XDocument RecipeDocument { get; set; }
|
||||
public bool ResetSite { get; set; }
|
||||
@@ -104,31 +105,11 @@ namespace Orchard.ImportExport.Providers.ImportActions {
|
||||
if (isValid) {
|
||||
// Read recipe file.
|
||||
RecipeDocument = XDocument.Parse(new StreamReader(file.InputStream).ReadToEnd());
|
||||
var orchardElement = RecipeDocument.Element("Orchard");
|
||||
|
||||
// Update execution steps.
|
||||
var executionStepNames = viewModel.RecipeExecutionSteps.Select(x => x.Name);
|
||||
var executionStepsQuery =
|
||||
from name in executionStepNames
|
||||
where orchardElement.Element(name) != null
|
||||
let provider = _recipeExecutionSteps.SingleOrDefault(x => x.Name == name)
|
||||
where provider != null
|
||||
select provider;
|
||||
var executionSteps = executionStepsQuery.ToArray();
|
||||
foreach (var executionStep in executionSteps) {
|
||||
var context = new UpdateRecipeExecutionStepContext {
|
||||
RecipeDocument = RecipeDocument,
|
||||
Step = orchardElement.Element(executionStep.Name)
|
||||
};
|
||||
|
||||
// Give the execution step a chance to augment the recipe step before it will be scheduled.
|
||||
executionStep.UpdateStep(context);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return shapeFactory.EditorTemplate(TemplateName: "ImportActions/UploadRecipe", Model: viewModel, Prefix: Prefix);
|
||||
return shapeFactory.EditorTemplate(TemplateName: "ImportActions/ExecuteRecipe", Model: viewModel, Prefix: Prefix);
|
||||
}
|
||||
|
||||
public override void Configure(ImportActionConfigurationContext context) {
|
||||
@@ -139,37 +120,42 @@ namespace Orchard.ImportExport.Providers.ImportActions {
|
||||
if (executionStepsElement == null)
|
||||
return;
|
||||
|
||||
foreach (var step in _recipeExecutionSteps) {
|
||||
var stepConfigurationElement = executionStepsElement.Element(step.Name);
|
||||
foreach (var stepElement in executionStepsElement.Elements()) {
|
||||
var step = _recipeExecutionSteps.SingleOrDefault(x => x.Name == stepElement.Name.LocalName);
|
||||
|
||||
if (stepConfigurationElement != null) {
|
||||
var stepContext = new RecipeExecutionStepConfigurationContext(stepConfigurationElement);
|
||||
if (step != null) {
|
||||
var stepContext = new RecipeExecutionStepConfigurationContext(stepElement);
|
||||
step.Configure(stepContext);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void Execute(ImportActionContext context) {
|
||||
if (RecipeDocument == null)
|
||||
var recipeDocument = context.RecipeDocument ?? RecipeDocument;
|
||||
if (recipeDocument == null)
|
||||
return;
|
||||
|
||||
// Give each execution step a chance to augment the recipe step before it will be scheduled.
|
||||
PrepareRecipe(recipeDocument);
|
||||
|
||||
// Sets the request timeout to 10 minutes to give enough time to execute custom recipes.
|
||||
_orchardServices.WorkContext.HttpContext.Server.ScriptTimeout = 600;
|
||||
|
||||
var executionId = ResetSite ? Setup() : ExecuteRecipe();
|
||||
var executionId = ResetSite ? Setup(recipeDocument) : ExecuteRecipe(recipeDocument);
|
||||
|
||||
if(executionId == null) {
|
||||
_orchardServices.Notifier.Warning(T("The recipe contained no steps. No work was scheduled."));
|
||||
return;
|
||||
}
|
||||
|
||||
context.ActionResult = new RedirectToRouteResult(new RouteValueDictionary(new { action = "ImportResult", controller = "Admin", area = "Orchard.ImportExport", executionId = executionId }));
|
||||
context.ExecutionId = executionId;
|
||||
context.RecipeDocument = recipeDocument;
|
||||
}
|
||||
|
||||
private string Setup() {
|
||||
private string Setup(XDocument recipeDocument) {
|
||||
var setupContext = new SetupContext {
|
||||
DropExistingTables = true,
|
||||
RecipeDocument = RecipeDocument,
|
||||
RecipeDocument = recipeDocument,
|
||||
AdminPassword = SuperUserPassword,
|
||||
AdminUsername = _orchardServices.WorkContext.CurrentSite.SuperUser,
|
||||
DatabaseConnectionString = _shellSettings.DataConnectionString,
|
||||
@@ -181,8 +167,22 @@ namespace Orchard.ImportExport.Providers.ImportActions {
|
||||
return _setupService.Setup(setupContext);
|
||||
}
|
||||
|
||||
private string ExecuteRecipe() {
|
||||
return _importExportService.Import(RecipeDocument);
|
||||
private string ExecuteRecipe(XDocument recipeDocument) {
|
||||
var recipe = _recipeParser.ParseRecipe(recipeDocument);
|
||||
return _recipeExecutor.Execute(recipe);
|
||||
}
|
||||
|
||||
private void PrepareRecipe(XDocument recipeDocument) {
|
||||
var query =
|
||||
from stepElement in recipeDocument.Element("Orchard").Elements()
|
||||
let step = _recipeExecutionSteps.SingleOrDefault(x => x.Name == stepElement.Name.LocalName)
|
||||
where step != null
|
||||
select new { Step = step, StepElement = stepElement };
|
||||
|
||||
foreach (var step in query) {
|
||||
var context = new UpdateRecipeExecutionStepContext { Step = step.StepElement };
|
||||
step.Step.UpdateStep(context);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using Orchard.Events;
|
||||
using Orchard.ImportExport.Models;
|
||||
|
||||
namespace Orchard.ImportExport.Services {
|
||||
[Obsolete("Implement IRecipeExecutionStep instead.")]
|
||||
|
@@ -1,18 +1,42 @@
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Xml.Linq;
|
||||
using Orchard.Recipes.Services;
|
||||
using Orchard.ImportExport.Models;
|
||||
using Orchard.Recipes.Models;
|
||||
using Orchard.Utility.Extensions;
|
||||
|
||||
namespace Orchard.ImportExport.Services {
|
||||
public interface IImportExportService : IDependency {
|
||||
string Import(XDocument recipeDocument);
|
||||
XDocument Export(IEnumerable<IRecipeBuilderStep> steps);
|
||||
string Import(ImportActionContext context, IEnumerable<IImportAction> actions = null);
|
||||
void Export(ExportActionContext context, IEnumerable<IExportAction> actions = null);
|
||||
string WriteExportFile(XDocument recipeDocument);
|
||||
IEnumerable<IExportAction> ParseExportActions(XDocument configurationDocument);
|
||||
void ConfigureImportActions(ConfigureImportActionsContext context);
|
||||
}
|
||||
|
||||
public static class ImportExportServiceExtensions {
|
||||
|
||||
public static string Import(this IImportExportService service, string recipeText) {
|
||||
var recipeDocument = XDocument.Parse(recipeText, LoadOptions.PreserveWhitespace);
|
||||
return service.Import(recipeDocument);
|
||||
var context = new ImportActionContext {
|
||||
RecipeDocument = XDocument.Parse(recipeText, LoadOptions.PreserveWhitespace)
|
||||
};
|
||||
service.Import(context);
|
||||
return context.ExecutionId;
|
||||
}
|
||||
|
||||
public static string GetExportFileName(this Recipe recipe) {
|
||||
string format;
|
||||
|
||||
if (String.IsNullOrWhiteSpace(recipe.Name) && String.IsNullOrWhiteSpace(recipe.Version))
|
||||
format = "export.xml";
|
||||
else if (String.IsNullOrWhiteSpace(recipe.Version))
|
||||
format = "{0}.recipe.xml";
|
||||
else if (String.IsNullOrWhiteSpace(recipe.Name))
|
||||
format = "export-{1}.recipe.xml";
|
||||
else
|
||||
format = "{0}-{1}.recipe.xml";
|
||||
|
||||
return String.Format(format, recipe.Name.HtmlClassify(), recipe.Version);
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,4 +1,6 @@
|
||||
namespace Orchard.ImportExport.Services {
|
||||
using Orchard.ImportExport.Models;
|
||||
|
||||
namespace Orchard.ImportExport.Services {
|
||||
public interface ISetupService : IDependency {
|
||||
string Setup(SetupContext context);
|
||||
}
|
||||
|
@@ -1,44 +1,46 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
using Orchard.FileSystems.AppData;
|
||||
using Orchard.Recipes.Services;
|
||||
using Orchard.ImportExport.Models;
|
||||
using Orchard.Logging;
|
||||
using Orchard.Services;
|
||||
|
||||
namespace Orchard.ImportExport.Services {
|
||||
public class ImportExportService : Component, IImportExportService {
|
||||
private readonly IOrchardServices _orchardServices;
|
||||
private readonly IAppDataFolder _appDataFolder;
|
||||
private readonly IRecipeBuilder _recipeBuilder;
|
||||
private readonly IRecipeParser _recipeParser;
|
||||
private readonly IRecipeExecutor _recipeExecutor;
|
||||
private readonly IClock _clock;
|
||||
private readonly IEnumerable<IExportAction> _exportActions;
|
||||
private readonly IEnumerable<IImportAction> _importActions;
|
||||
private const string ExportsDirectory = "Exports";
|
||||
|
||||
public ImportExportService(
|
||||
IOrchardServices orchardServices,
|
||||
IAppDataFolder appDataFolder,
|
||||
IRecipeBuilder recipeBuilder,
|
||||
IRecipeParser recipeParser,
|
||||
IRecipeExecutor recipeExecutor,
|
||||
IClock clock) {
|
||||
IClock clock,
|
||||
IEnumerable<IExportAction> exportActions,
|
||||
IEnumerable<IImportAction> importActions) {
|
||||
|
||||
_orchardServices = orchardServices;
|
||||
_appDataFolder = appDataFolder;
|
||||
_recipeBuilder = recipeBuilder;
|
||||
_recipeParser = recipeParser;
|
||||
_recipeExecutor = recipeExecutor;
|
||||
_clock = clock;
|
||||
_exportActions = exportActions;
|
||||
_importActions = importActions;
|
||||
}
|
||||
|
||||
public string Import(XDocument recipeDocument) {
|
||||
var recipe = _recipeParser.ParseRecipe(recipeDocument);
|
||||
return _recipeExecutor.Execute(recipe);
|
||||
public string Import(ImportActionContext context, IEnumerable<IImportAction> actions = null) {
|
||||
foreach (var action in actions ?? _importActions) {
|
||||
action.Execute(context);
|
||||
}
|
||||
return context.ExecutionId;
|
||||
}
|
||||
|
||||
public XDocument Export(IEnumerable<IRecipeBuilderStep> steps) {
|
||||
var recipe = _recipeBuilder.Build(steps);
|
||||
return recipe;
|
||||
public void Export(ExportActionContext context, IEnumerable<IExportAction> actions = null) {
|
||||
foreach (var action in actions ?? _exportActions) {
|
||||
action.Execute(context);
|
||||
}
|
||||
}
|
||||
|
||||
public string WriteExportFile(XDocument recipeDocument) {
|
||||
@@ -53,5 +55,49 @@ namespace Orchard.ImportExport.Services {
|
||||
|
||||
return _appDataFolder.MapPath(path);
|
||||
}
|
||||
|
||||
public IEnumerable<IExportAction> ParseExportActions(XDocument configurationDocument) {
|
||||
var actionElements = configurationDocument.Root.Elements();
|
||||
|
||||
foreach (var actionElement in actionElements) {
|
||||
var action = _exportActions.SingleOrDefault(x => x.Name == actionElement.Name.LocalName);
|
||||
|
||||
if (action == null) {
|
||||
Logger.Warning("The export action '{0}' could not be found. Did you forget to enable a feature?", actionElement.Name.LocalName);
|
||||
continue;
|
||||
}
|
||||
|
||||
action.Configure(new ExportActionConfigurationContext(actionElement));
|
||||
yield return action;
|
||||
}
|
||||
}
|
||||
|
||||
public void ConfigureImportActions(ConfigureImportActionsContext context) {
|
||||
var actionConfigElements = context.ConfigurationDocument.Root;
|
||||
|
||||
foreach (var action in _importActions) {
|
||||
var actionConfigElement = actionConfigElements.Element(action.Name);
|
||||
|
||||
if (actionConfigElement != null) {
|
||||
action.Configure(new ImportActionConfigurationContext(actionConfigElement));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<IImportAction> ParseImportActions(XDocument configurationDocument) {
|
||||
var actionElements = configurationDocument.Root.Elements();
|
||||
|
||||
foreach (var actionElement in actionElements) {
|
||||
var action = _importActions.SingleOrDefault(x => x.Name == actionElement.Name.LocalName);
|
||||
|
||||
if (action == null) {
|
||||
Logger.Warning("The import action '{0}' could not be found. Did you forget to enable a feature?", actionElement.Name.LocalName);
|
||||
continue;
|
||||
}
|
||||
|
||||
action.Configure(new ImportActionConfigurationContext(actionElement));
|
||||
yield return action;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -14,6 +14,7 @@ using Orchard.Environment.Descriptor;
|
||||
using Orchard.Environment.Descriptor.Models;
|
||||
using Orchard.Environment.ShellBuilders;
|
||||
using Orchard.Environment.State;
|
||||
using Orchard.ImportExport.Models;
|
||||
using Orchard.Localization.Services;
|
||||
using Orchard.Logging;
|
||||
using Orchard.Recipes.Services;
|
||||
|
@@ -72,16 +72,15 @@ namespace Orchard.Recipes.Providers.Builders {
|
||||
public override void Configure(RecipeBuilderStepConfigurationContext context) {
|
||||
var schemaContentTypeNames = context.ConfigurationElement.Attr("SchemaContentTypes");
|
||||
var dataContentTypeNames = context.ConfigurationElement.Attr("DataContentTypes");
|
||||
var versionHistoryOptions = context.ConfigurationElement.Attr<VersionHistoryOptions?>("VersionHistoryOptions");
|
||||
var versionHistoryOptions = context.ConfigurationElement.Attr<VersionHistoryOptions>("VersionHistoryOptions");
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(schemaContentTypeNames))
|
||||
if (!String.IsNullOrWhiteSpace(schemaContentTypeNames))
|
||||
SchemaContentTypes = schemaContentTypeNames.Split(new[] {','}, StringSplitOptions.RemoveEmptyEntries).ToList();
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(dataContentTypeNames))
|
||||
if (!String.IsNullOrWhiteSpace(dataContentTypeNames))
|
||||
DataContentTypes = dataContentTypeNames.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).ToList();
|
||||
|
||||
if(versionHistoryOptions != null)
|
||||
VersionHistoryOptions = versionHistoryOptions.Value;
|
||||
VersionHistoryOptions = versionHistoryOptions;
|
||||
}
|
||||
|
||||
public override void Build(BuildContext context) {
|
||||
|
@@ -128,6 +128,10 @@ namespace Orchard.Mvc {
|
||||
get { return HttpRuntime.Cache; }
|
||||
}
|
||||
|
||||
public override HttpServerUtilityBase Server {
|
||||
get { return new HttpServerUtilityPlaceholder(); }
|
||||
}
|
||||
|
||||
public override object GetService(Type serviceType) {
|
||||
return null;
|
||||
}
|
||||
@@ -265,5 +269,9 @@ namespace Orchard.Mvc {
|
||||
public override bool Cookies { get { return true; } }
|
||||
public override ArrayList Browsers { get { return new ArrayList(); } }
|
||||
}
|
||||
|
||||
public class HttpServerUtilityPlaceholder : HttpServerUtilityBase {
|
||||
public override int ScriptTimeout { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user