Refactored ImportExport to support extensible, configurable export steps.

This commit is contained in:
Sipke Schoorstra
2015-07-14 15:39:32 +01:00
parent a926e7b8fa
commit 04c193afd1
24 changed files with 575 additions and 357 deletions

View File

@@ -1,9 +1,11 @@
using System; using System;
using System.Collections.Generic;
using System.IO; 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.Models;
using Orchard.ImportExport.Providers;
using Orchard.ImportExport.Services; using Orchard.ImportExport.Services;
using Orchard.Security; using Orchard.Security;
using Orchard.Settings; using Orchard.Settings;
@@ -15,18 +17,22 @@ namespace Orchard.ImportExport.Commands {
private readonly ISiteService _siteService; private readonly ISiteService _siteService;
private readonly IMembershipService _membershipService; private readonly IMembershipService _membershipService;
private readonly IAuthenticationService _authenticationService; private readonly IAuthenticationService _authenticationService;
private readonly IOrchardServices _orchardServices;
public ImportExportCommands( public ImportExportCommands(
IImportExportService importExportService, IImportExportService importExportService,
IContentDefinitionManager contentDefinitionManager, IContentDefinitionManager contentDefinitionManager,
ISiteService siteService, ISiteService siteService,
IMembershipService membershipService, IMembershipService membershipService,
IAuthenticationService authenticationService) { IAuthenticationService authenticationService,
IOrchardServices orchardServices) {
_importExportService = importExportService; _importExportService = importExportService;
_contentDefinitionManager = contentDefinitionManager; _contentDefinitionManager = contentDefinitionManager;
_siteService = siteService; _siteService = siteService;
_membershipService = membershipService; _membershipService = membershipService;
_authenticationService = authenticationService; _authenticationService = authenticationService;
_orchardServices = orchardServices;
} }
[OrchardSwitch] [OrchardSwitch]
@@ -65,10 +71,10 @@ namespace Orchard.ImportExport.Commands {
} }
[CommandName("export file")] [CommandName("export file")]
[CommandHelp("export file [/Types:<type-name-1>, ... ,<type-name-n>] [/Metadata:true|false] [/Data:true|false] [/Version:Published|Draft] [/SiteSettings:true|false] [/Steps:<custom-step-1>, ... ,<custom-step-n>]\r\n\t" + "Create an export file according to the specified options.")] [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")] [OrchardSwitches("Types,Metadata,Data,Version,SiteSettings,Steps")]
public void ExportFile() { public void ExportFile() {
// impersonate the Site owner // Impersonate the Site owner.
var superUser = _siteService.GetSiteSettings().SuperUser; var superUser = _siteService.GetSiteSettings().SuperUser;
var owner = _membershipService.GetUser(superUser); var owner = _membershipService.GetUser(superUser);
_authenticationService.SetAuthenticatedUserForRequest(owner); _authenticationService.SetAuthenticatedUserForRequest(owner);
@@ -82,23 +88,39 @@ namespace Orchard.ImportExport.Commands {
var enteredTypes = (Types ?? String.Empty).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries); var enteredTypes = (Types ?? String.Empty).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
var exportTypes = _contentDefinitionManager.ListTypeDefinitions() var exportTypes = _contentDefinitionManager
.Where(contentType => enteredTypes.Contains(contentType.Name)) .ListTypeDefinitions()
.Select(contentType => contentType.Name); .Where(contentType => enteredTypes.Contains(contentType.Name))
.Select(contentType => contentType.Name)
.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 exportOptions = new ExportOptions { var exportOptions = new ExportOptions {
ExportMetadata = Metadata,
ExportData = Data,
VersionHistoryOptions = versionOption,
ExportSiteSettings = SiteSettings,
CustomSteps = enteredSteps CustomSteps = enteredSteps
}; };
if (Metadata || Data) {
var dataStep = _orchardServices.WorkContext.Resolve<DataExportStep>();
if(Data)
dataStep.DataContentTypes = exportTypes;
if(Metadata)
dataStep.SchemaContentTypes = exportTypes;
dataStep.VersionHistoryOptions = versionOption;
exportSteps.Add(dataStep);
}
if (SiteSettings) {
var siteSettingsStep = _orchardServices.WorkContext.Resolve<SiteSettingsExportStep>();
exportSteps.Add(siteSettingsStep);
}
Context.Output.WriteLine(T("Export starting...")); Context.Output.WriteLine(T("Export starting..."));
var exportFilePath = _importExportService.Export(exportTypes, exportOptions); var exportFilePath = _importExportService.Export(exportSteps, exportOptions);
Context.Output.WriteLine(T("Export completed at {0}", exportFilePath)); Context.Output.WriteLine(T("Export completed at {0}", exportFilePath));
} }

View File

@@ -3,18 +3,17 @@ using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Web.Mvc; using System.Web.Mvc;
using Orchard.ContentManagement;
using Orchard.ContentManagement.MetaData; using Orchard.ContentManagement.MetaData;
using Orchard.DisplayManagement; 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;
using Orchard.Recipes.Services; using Orchard.Recipes.Services;
using Orchard.UI.Notify; using Orchard.UI.Notify;
using Orchard.ImportExport.Models;
using Orchard.Utility.Extensions;
namespace Orchard.ImportExport.Controllers { namespace Orchard.ImportExport.Controllers {
public class AdminController : Controller { public class AdminController : Controller, IUpdateModel {
private readonly IImportExportService _importExportService; private readonly IImportExportService _importExportService;
private readonly IContentDefinitionManager _contentDefinitionManager; private readonly IContentDefinitionManager _contentDefinitionManager;
private readonly ICustomExportStep _customExportStep; private readonly ICustomExportStep _customExportStep;
@@ -79,25 +78,18 @@ namespace Orchard.ImportExport.Controllers {
var customSteps = new List<string>(); var customSteps = new List<string>();
_customExportStep.Register(customSteps); _customExportStep.Register(customSteps);
var exportSteps = _exportStepProviders.Select(x => { var exportSteps = _exportStepProviders.OrderBy(x => x.Position).Select(x => new ExportStepViewModel {
var editor = x.BuildEditor(Services.New); Name = x.Name,
editor.Provider = x; DisplayName = x.DisplayName,
editor.Name = x.Name; Description = x.Description,
editor.DisplayName = x.DisplayName; Editor = x.BuildEditor(Services.New)
return editor;
}).Where(x => x != null); }).Where(x => x != null);
var viewModel = new ExportViewModel { var viewModel = new ExportViewModel {
RecipeVersion = "1.0",
ContentTypes = new List<ContentTypeEntry>(),
CustomSteps = customSteps.Select(x => new CustomStepEntry { CustomStep = x }).ToList(), CustomSteps = customSteps.Select(x => new CustomStepEntry { CustomStep = x }).ToList(),
ExportSteps = exportSteps.ToList() ExportSteps = exportSteps.ToList()
}; };
foreach (var contentType in _contentDefinitionManager.ListTypeDefinitions().OrderBy(c => c.Name)) {
viewModel.ContentTypes.Add(new ContentTypeEntry { ContentTypeName = contentType.Name });
}
return View(viewModel); return View(viewModel);
} }
@@ -107,37 +99,39 @@ namespace Orchard.ImportExport.Controllers {
return new HttpUnauthorizedResult(); return new HttpUnauthorizedResult();
var viewModel = new ExportViewModel { var viewModel = new ExportViewModel {
ContentTypes = new List<ContentTypeEntry>(), CustomSteps = new List<CustomStepEntry>(),
CustomSteps = new List<CustomStepEntry>() ExportSteps = new List<ExportStepViewModel>()
}; };
UpdateModel(viewModel); UpdateModel(viewModel);
var contentTypesToExport = viewModel.ContentTypes.Where(c => c.IsChecked).Select(c => c.ContentTypeName).ToList(); var exportStepNames = viewModel.ExportSteps.Where(x => x.IsSelected).Select(x => x.Name);
var exportStepsQuery = from name in exportStepNames
let provider = _exportStepProviders.SingleOrDefault(x => x.Name == name)
where provider != null
select provider;
var exportSteps = exportStepsQuery.ToArray();
var customSteps = viewModel.CustomSteps.Where(c => c.IsChecked).Select(c => c.CustomStep); var customSteps = viewModel.CustomSteps.Where(c => c.IsChecked).Select(c => c.CustomStep);
var exportOptions = new ExportOptions { var exportOptions = new ExportOptions {
ExportMetadata = viewModel.Metadata,
ExportSiteSettings = viewModel.SiteSettings,
SetupRecipe = viewModel.SetupRecipe,
RecipeName = viewModel.RecipeName,
RecipeDescription = viewModel.RecipeDescription,
RecipeWebsite = viewModel.RecipeWebsite,
RecipeTags = viewModel.RecipeTags,
RecipeVersion = viewModel.RecipeVersion,
CustomSteps = customSteps CustomSteps = customSteps
}; };
if (viewModel.Data) { foreach (var exportStep in exportSteps) {
exportOptions.ExportData = true; exportStep.UpdateEditor(Services.New, this);
exportOptions.VersionHistoryOptions = (VersionHistoryOptions)Enum.Parse(typeof(VersionHistoryOptions), viewModel.DataImportChoice, true);
exportOptions.ImportBatchSize = viewModel.ImportBatchSize;
} }
var exportFilePath = _importExportService.Export(contentTypesToExport, exportOptions);
var exportFileName = exportOptions.SetupRecipe && !String.IsNullOrWhiteSpace(exportOptions.RecipeName) var exportFilePath = _importExportService.Export(exportSteps, exportOptions);
? String.Format("{0}.recipe.xml", exportOptions.RecipeName.HtmlClassify()) var exportFileName = "export.xml";
: "export.xml";
return File(exportFilePath, "text/xml", exportFileName); return File(exportFilePath, "text/xml", exportFileName);
} }
bool IUpdateModel.TryUpdateModel<TModel>(TModel model, string prefix, string[] includeProperties, string[] excludeProperties) {
return TryUpdateModel(model, prefix, includeProperties, excludeProperties);
}
void IUpdateModel.AddModelError(string key, LocalizedString errorMessage) {
ModelState.AddModelError(key, errorMessage.ToString());
}
} }
} }

View File

@@ -2,22 +2,12 @@
namespace Orchard.ImportExport.Models { namespace Orchard.ImportExport.Models {
public class ExportOptions { public class ExportOptions {
public bool ExportMetadata { get; set; }
public bool ExportData { get; set; }
public int? ImportBatchSize { get; set; }
public VersionHistoryOptions VersionHistoryOptions { get; set; }
public bool ExportSiteSettings { get; set; }
public IEnumerable<string> CustomSteps { get; set; } public IEnumerable<string> CustomSteps { get; set; }
public bool SetupRecipe { get; set; }
public string RecipeName { get; set; }
public string RecipeDescription { get; set; }
public string RecipeWebsite { get; set; }
public string RecipeTags { get; set; }
public string RecipeVersion { get; set; }
} }
public enum VersionHistoryOptions { public enum VersionHistoryOptions {
Published, Published,
Draft, Draft,
Latest
} }
} }

View File

@@ -71,7 +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="Providers\SiteSettingsExportStep.cs" />
<Compile Include="Providers\DataExportStep.cs" /> <Compile Include="Providers\DataExportStep.cs" />
<Compile Include="ViewModels\ContentTypeEntry.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" />
@@ -101,6 +109,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Content Include="Styles\images\menu.importexport.png" /> <Content Include="Styles\images\menu.importexport.png" />
<Content Include="Styles\exportstep-data.css" />
<Content Include="Styles\menu.importexport-admin.css" /> <Content Include="Styles\menu.importexport-admin.css" />
<Content Include="Web.config" /> <Content Include="Web.config" />
</ItemGroup> </ItemGroup>
@@ -121,6 +130,12 @@
<ItemGroup> <ItemGroup>
<Content Include="Views\EditorTemplates\ExportSteps\Data.cshtml" /> <Content Include="Views\EditorTemplates\ExportSteps\Data.cshtml" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<Content Include="Views\EditorTemplates\ExportSteps\SiteSettings.cshtml" />
</ItemGroup>
<ItemGroup>
<Content Include="Views\EditorTemplates\ExportSteps\SetupRecipe.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

@@ -1,27 +1,153 @@
using Orchard.ContentManagement; using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
using Orchard.ContentManagement;
using Orchard.ContentManagement.MetaData;
using Orchard.ContentManagement.MetaData.Models;
using Orchard.ImportExport.Models;
using Orchard.ImportExport.Services; using Orchard.ImportExport.Services;
using Orchard.ImportExport.ViewModels;
using Orchard.Localization; using Orchard.Localization;
namespace Orchard.ImportExport.Providers { namespace Orchard.ImportExport.Providers {
public class DataExportStep : ExportStepProvider { public class DataExportStep : ExportStepProvider {
private readonly IContentDefinitionManager _contentDefinitionManager;
private readonly IOrchardServices _orchardServices;
private readonly IContentDefinitionWriter _contentDefinitionWriter;
public DataExportStep(
IContentDefinitionManager contentDefinitionManager,
IOrchardServices orchardServices,
IContentDefinitionWriter contentDefinitionWriter) {
_contentDefinitionManager = contentDefinitionManager;
_orchardServices = orchardServices;
_contentDefinitionWriter = contentDefinitionWriter;
}
public override string Name { public override string Name {
get { return "Data"; } get { return "Data"; }
} }
public override LocalizedString DisplayName { public override LocalizedString DisplayName {
get { return T("Data"); } get { return T("Content Items and Definitions"); }
} }
public override LocalizedString Description {
get { return T("Exports content items and content item definitions."); }
}
public override int Position { get { return 10; } }
public IList<string> SchemaContentTypes { get; set; }
public IList<string> DataContentTypes { get; set; }
public int? ImportBatchSize { get; set; }
public VersionHistoryOptions VersionHistoryOptions { get; set; }
public override dynamic BuildEditor(dynamic shapeFactory) { public override dynamic BuildEditor(dynamic shapeFactory) {
return UpdateEditor(shapeFactory, null); return UpdateEditor(shapeFactory, null);
} }
public override dynamic UpdateEditor(dynamic shapeFactory, IUpdateModel updater) { public override dynamic UpdateEditor(dynamic shapeFactory, IUpdateModel updater) {
if (updater != null) { var contentTypeViewModels = _contentDefinitionManager.ListTypeDefinitions()
.OrderBy(x => x.Name)
.Select(x => new ContentTypeEntry { Name = x.Name, DisplayName = x.DisplayName })
.ToList();
var viewModel = new DataExportStepViewModel {
ContentTypes = contentTypeViewModels
};
if (updater != null && updater.TryUpdateModel(viewModel, Prefix, null, null)) {
DataContentTypes = viewModel.ContentTypes.Where(x => x.ExportData).Select(x => x.Name).ToList();
SchemaContentTypes = viewModel.ContentTypes.Where(x => x.ExportSchema).Select(x => x.Name).ToList();
VersionHistoryOptions = viewModel.VersionHistoryOptions;
} }
return shapeFactory.EditorTemplate(TemplateName: "ExportSteps/Data"); return shapeFactory.EditorTemplate(TemplateName: "ExportSteps/Data", Model: viewModel, Prefix: Prefix);
}
public override void Export(ExportContext context) {
var dataContentTypes = DataContentTypes;
var schemaContentTypes = SchemaContentTypes;
var exportVersionOptions = GetContentExportVersionOptions(VersionHistoryOptions);
var contentItems = dataContentTypes.Any()
? _orchardServices.ContentManager.Query(exportVersionOptions, dataContentTypes.ToArray()).List().ToArray()
: Enumerable.Empty<ContentItem>();
if(schemaContentTypes.Any())
context.Document.Element("Orchard").Add(ExportMetadata(schemaContentTypes));
if(contentItems.Any())
context.Document.Element("Orchard").Add(ExportData(dataContentTypes, contentItems, ImportBatchSize));
}
private XElement ExportMetadata(IEnumerable<string> contentTypes) {
var typesElement = new XElement("Types");
var partsElement = new XElement("Parts");
var typesToExport = _contentDefinitionManager.ListTypeDefinitions()
.Where(typeDefinition => contentTypes.Contains(typeDefinition.Name))
.ToList();
var partsToExport = new Dictionary<string, ContentPartDefinition>();
foreach (var contentTypeDefinition in typesToExport.OrderBy(x => x.Name)) {
foreach (var contentPartDefinition in contentTypeDefinition.Parts) {
if (partsToExport.ContainsKey(contentPartDefinition.PartDefinition.Name)) {
continue;
}
partsToExport.Add(contentPartDefinition.PartDefinition.Name, contentPartDefinition.PartDefinition);
}
typesElement.Add(_contentDefinitionWriter.Export(contentTypeDefinition));
}
foreach (var part in partsToExport.Values.OrderBy(x => x.Name)) {
partsElement.Add(_contentDefinitionWriter.Export(part));
}
return new XElement("Metadata", typesElement, partsElement);
}
private XElement ExportData(IEnumerable<string> contentTypes, IEnumerable<ContentItem> contentItems, int? batchSize) {
var data = new XElement("Data");
if (batchSize.HasValue && batchSize.Value > 0)
data.SetAttributeValue("BatchSize", batchSize);
var orderedContentItemsQuery =
from contentItem in contentItems
let identity = _orchardServices.ContentManager.GetItemMetadata(contentItem).Identity.ToString()
orderby identity
select contentItem;
var orderedContentItems = orderedContentItemsQuery.ToList();
foreach (var contentType in contentTypes.OrderBy(x => x)) {
var type = contentType;
var items = orderedContentItems.Where(i => i.ContentType == type);
foreach (var contentItem in items) {
var contentItemElement = ExportContentItem(contentItem);
if (contentItemElement != null)
data.Add(contentItemElement);
}
}
return data;
}
private VersionOptions GetContentExportVersionOptions(VersionHistoryOptions versionHistoryOptions) {
switch (versionHistoryOptions) {
case VersionHistoryOptions.Draft:
return VersionOptions.Draft;
case VersionHistoryOptions.Latest:
return VersionOptions.Latest;
case VersionHistoryOptions.Published:
default:
return VersionOptions.Published;
}
}
private XElement ExportContentItem(ContentItem contentItem) {
return _orchardServices.ContentManager.Export(contentItem);
} }
} }
} }

View File

@@ -0,0 +1,69 @@
using Orchard.ContentManagement;
using Orchard.ImportExport.Services;
using Orchard.ImportExport.ViewModels;
using Orchard.Localization;
namespace Orchard.ImportExport.Providers {
public class SetupRecipeExportStep : ExportStepProvider {
private readonly IOrchardServices _orchardServices;
public SetupRecipeExportStep(IOrchardServices orchardServices) {
_orchardServices = orchardServices;
}
public override string Name {
get { return "SetupRecipe"; }
}
public override LocalizedString DisplayName {
get { return T("Setup Recipe"); }
}
public override LocalizedString Description {
get { return T("Turns the export file into a Setup recipe."); }
}
public override int Position { get { return -10; } }
public string RecipeName { get; set; }
public string RecipeDescription { get; set; }
public string RecipeAuthor { get; set; }
public string RecipeWebsite { get; set; }
public string RecipeTags { get; set; }
public string RecipeVersion { get; set; }
public bool IsSetupRecipe { get; set; }
public override dynamic BuildEditor(dynamic shapeFactory) {
return UpdateEditor(shapeFactory, null);
}
public override dynamic UpdateEditor(dynamic shapeFactory, IUpdateModel updater) {
var viewModel = new SetupRecipeStepViewModel {
RecipeAuthor = _orchardServices.WorkContext.CurrentUser.UserName
};
if (updater != null && updater.TryUpdateModel(viewModel, Prefix, null, null)) {
RecipeName = viewModel.RecipeName;
RecipeDescription = viewModel.RecipeDescription;
RecipeAuthor = viewModel.RecipeAuthor;
RecipeWebsite = viewModel.RecipeWebsite;
RecipeTags = viewModel.RecipeTags;
RecipeVersion = viewModel.RecipeVersion;
IsSetupRecipe = true;
}
return shapeFactory.EditorTemplate(TemplateName: "ExportSteps/SetupRecipe", Model: viewModel, Prefix: Prefix);
}
public override void Export(ExportContext context) {
var recipeElement = context.Document.Element("Orchard").Element("Recipe");
recipeElement.SetElementValue("Name", RecipeName);
recipeElement.SetElementValue("Description", RecipeDescription);
recipeElement.SetElementValue("Author", RecipeAuthor);
recipeElement.SetElementValue("WebSite", RecipeWebsite);
recipeElement.SetElementValue("Tags", RecipeTags);
recipeElement.SetElementValue("Version", RecipeVersion);
recipeElement.SetElementValue("IsSetupRecipe", IsSetupRecipe);
}
}
}

View File

@@ -0,0 +1,95 @@
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
using Orchard.ContentManagement;
using Orchard.ImportExport.Services;
using Orchard.ImportExport.ViewModels;
using Orchard.Localization;
namespace Orchard.ImportExport.Providers {
public class SiteSettingsExportStep : ExportStepProvider {
private readonly IOrchardServices _orchardServices;
public SiteSettingsExportStep(IOrchardServices orchardServices) {
_orchardServices = orchardServices;
}
public override string Name {
get { return "SiteSettings"; }
}
public override LocalizedString DisplayName {
get { return T("Site Settings"); }
}
public override LocalizedString Description {
get { return T("Exports site settings."); }
}
public override int Position { get { return 20; } }
public override dynamic BuildEditor(dynamic shapeFactory) {
return UpdateEditor(shapeFactory, null);
}
public override dynamic UpdateEditor(dynamic shapeFactory, IUpdateModel updater) {
var viewModel = new SiteSettingsStepViewModel();
return shapeFactory.EditorTemplate(TemplateName: "ExportSteps/SiteSettings", Model: viewModel, Prefix: Prefix);
}
public override void Export(ExportContext context) {
context.Document.Element("Orchard").Add(ExportSiteSettings());
}
private XElement ExportSiteSettings() {
var siteContentItem = _orchardServices.WorkContext.CurrentSite.ContentItem;
var exportedElements = ExportContentItem(siteContentItem).Elements().ToList();
foreach (var contentPart in siteContentItem.Parts.OrderBy(x => x.PartDefinition.Name)) {
var exportedElement = exportedElements.FirstOrDefault(element => element.Name == contentPart.PartDefinition.Name);
// Get all simple attributes if exported element is null.
// Get exclude the simple attributes that already exist if element is not null.
var simpleAttributes =
ExportSettingsPartAttributes(contentPart)
.Where(attribute => exportedElement == null || exportedElement.Attributes().All(xAttribute => xAttribute.Name != attribute.Name))
.OrderBy(x => x.Name.LocalName)
.ToList();
if (simpleAttributes.Any()) {
if (exportedElement == null) {
exportedElement = new XElement(contentPart.PartDefinition.Name);
exportedElements.Add(exportedElement);
}
exportedElement.Add(simpleAttributes);
}
}
exportedElements = exportedElements.OrderBy(x => x.Name.LocalName).ToList();
return new XElement("Settings", exportedElements);
}
private XElement ExportContentItem(ContentItem contentItem) {
return _orchardServices.ContentManager.Export(contentItem);
}
private IEnumerable<XAttribute> ExportSettingsPartAttributes(ContentPart sitePart) {
foreach (var property in sitePart.GetType().GetProperties().OrderBy(x => x.Name)) {
var propertyType = property.PropertyType;
// Supported types (we also know they are not indexed properties).
if (propertyType == typeof(string) || propertyType == typeof(bool) || propertyType == typeof(int)) {
// Exclude read-only properties.
if (property.GetSetMethod() != null) {
var value = property.GetValue(sitePart, null);
if (value == null)
continue;
yield return new XAttribute(property.Name, value);
}
}
}
}
}
}

View File

@@ -5,6 +5,8 @@ namespace Orchard.ImportExport.Services {
public abstract class ExportStepProvider : Component, IExportStepProvider { public abstract class ExportStepProvider : Component, IExportStepProvider {
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 virtual int Position { get { return 0; } }
protected virtual string Prefix { protected virtual string Prefix {
get { return GetType().Name; } get { return GetType().Name; }
@@ -17,5 +19,7 @@ namespace Orchard.ImportExport.Services {
public virtual dynamic UpdateEditor(dynamic shapeFactory, IUpdateModel updater) { public virtual dynamic UpdateEditor(dynamic shapeFactory, IUpdateModel updater) {
return null; return null;
} }
public virtual void Export(ExportContext context) {}
} }
} }

View File

@@ -1,12 +1,10 @@
using System.Collections.Generic; using System.Xml.Linq;
using System.Xml.Linq;
using Orchard.Events; using Orchard.Events;
using Orchard.ImportExport.Models; using Orchard.ImportExport.Models;
namespace Orchard.ImportExport.Services { namespace Orchard.ImportExport.Services {
public class ExportContext { public class ExportContext {
public XDocument Document { get; set; } public XDocument Document { get; set; }
public IEnumerable<string> ContentTypes { get; set; }
public ExportOptions ExportOptions { get; set; } public ExportOptions ExportOptions { get; set; }
} }

View File

@@ -5,7 +5,10 @@ namespace Orchard.ImportExport.Services {
public interface IExportStepProvider : IDependency { public interface IExportStepProvider : IDependency {
string Name { get; } string Name { get; }
LocalizedString DisplayName { get; } LocalizedString DisplayName { get; }
LocalizedString Description { get; }
int Position { 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);
} }
} }

View File

@@ -1,12 +1,10 @@
using System.Collections.Generic; using System.Collections.Generic;
using Orchard.ContentManagement;
using Orchard.ImportExport.Models; using Orchard.ImportExport.Models;
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<string> contentTypes, IEnumerable<ContentItem> contentItems, ExportOptions exportOptions); string Export(IEnumerable<IExportStepProvider> steps, ExportOptions exportOptions);
string Export(IEnumerable<string> contentTypes, ExportOptions exportOptions);
} }
} }

View File

@@ -1,11 +1,8 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Xml; using System.Xml;
using System.Xml.Linq; using System.Xml.Linq;
using Orchard.ContentManagement; using Orchard.ContentManagement;
using Orchard.ContentManagement.MetaData;
using Orchard.ContentManagement.MetaData.Models;
using Orchard.Environment.Descriptor; using Orchard.Environment.Descriptor;
using Orchard.FileSystems.AppData; using Orchard.FileSystems.AppData;
using Orchard.ImportExport.Models; using Orchard.ImportExport.Models;
@@ -17,8 +14,6 @@ using Orchard.Services;
namespace Orchard.ImportExport.Services { namespace Orchard.ImportExport.Services {
public class ImportExportService : IImportExportService { public class ImportExportService : IImportExportService {
private readonly IOrchardServices _orchardServices; private readonly IOrchardServices _orchardServices;
private readonly IContentDefinitionManager _contentDefinitionManager;
private readonly IContentDefinitionWriter _contentDefinitionWriter;
private readonly IAppDataFolder _appDataFolder; private readonly IAppDataFolder _appDataFolder;
private readonly IRecipeParser _recipeParser; private readonly IRecipeParser _recipeParser;
private readonly IRecipeManager _recipeManager; private readonly IRecipeManager _recipeManager;
@@ -29,8 +24,6 @@ namespace Orchard.ImportExport.Services {
public ImportExportService( public ImportExportService(
IOrchardServices orchardServices, IOrchardServices orchardServices,
IContentDefinitionManager contentDefinitionManager,
IContentDefinitionWriter contentDefinitionWriter,
IAppDataFolder appDataFolder, IAppDataFolder appDataFolder,
IRecipeParser recipeParser, IRecipeParser recipeParser,
IRecipeManager recipeManager, IRecipeManager recipeManager,
@@ -39,8 +32,6 @@ namespace Orchard.ImportExport.Services {
IEnumerable<IExportEventHandler> exportEventHandlers) { IEnumerable<IExportEventHandler> exportEventHandlers) {
_orchardServices = orchardServices; _orchardServices = orchardServices;
_contentDefinitionManager = contentDefinitionManager;
_contentDefinitionWriter = contentDefinitionWriter;
_appDataFolder = appDataFolder; _appDataFolder = appDataFolder;
_recipeParser = recipeParser; _recipeParser = recipeParser;
_recipeManager = recipeManager; _recipeManager = recipeManager;
@@ -61,37 +52,18 @@ namespace Orchard.ImportExport.Services {
return executionId; return executionId;
} }
public string Export(IEnumerable<string> contentTypes, ExportOptions exportOptions) { public string Export(IEnumerable<IExportStepProvider> steps, ExportOptions exportOptions) {
//items need to be retrieved var exportDocument = CreateExportRoot();
IEnumerable<ContentItem> contentItems = null;
if (exportOptions.ExportData) {
contentItems = _orchardServices.ContentManager.Query(GetContentExportVersionOptions(exportOptions.VersionHistoryOptions), contentTypes.ToArray()).List().ToArray();
}
return Export(contentTypes, contentItems, exportOptions);
}
public string Export(IEnumerable<string> contentTypes, IEnumerable<ContentItem> contentItems, ExportOptions exportOptions) {
var exportDocument = CreateExportRoot(exportOptions);
var context = new ExportContext { var context = new ExportContext {
Document = exportDocument, Document = exportDocument,
ContentTypes = contentTypes,
ExportOptions = exportOptions ExportOptions = exportOptions
}; };
_exportEventHandlers.Invoke(x => x.Exporting(context), Logger); _exportEventHandlers.Invoke(x => x.Exporting(context), Logger);
if (exportOptions.ExportMetadata && (!exportOptions.ExportData || contentItems.Any())) { foreach (var step in steps) {
exportDocument.Element("Orchard").Add(ExportMetadata(contentTypes)); step.Export(context);
}
if (exportOptions.ExportSiteSettings) {
exportDocument.Element("Orchard").Add(ExportSiteSettings());
}
if (exportOptions.ExportData && contentItems.Any()) {
exportDocument.Element("Orchard").Add(ExportData(contentTypes, contentItems, exportOptions.ImportBatchSize));
} }
_exportEventHandlers.Invoke(x => x.Exported(context), Logger); _exportEventHandlers.Invoke(x => x.Exported(context), Logger);
@@ -99,143 +71,21 @@ namespace Orchard.ImportExport.Services {
return WriteExportFile(exportDocument.ToString()); return WriteExportFile(exportDocument.ToString());
} }
private XDocument CreateExportRoot(ExportOptions exportOptions) { private XDocument CreateExportRoot() {
var recipeName = !String.IsNullOrWhiteSpace(exportOptions.RecipeName)
? exportOptions.RecipeName
: T("Generated by Orchard.ImportExport").ToString();
var exportRoot = new XDocument( var exportRoot = new XDocument(
new XDeclaration("1.0", "", "yes"), new XDeclaration("1.0", "", "yes"),
new XComment("Exported from Orchard"), new XComment("Exported from Orchard"),
new XElement("Orchard", new XElement("Orchard",
new XElement("Recipe", new XElement("Recipe",
new XElement("Name", recipeName),
new XElement("Description", exportOptions.RecipeDescription),
new XElement("Author", _orchardServices.WorkContext.CurrentUser.UserName),
new XElement("WebSite", exportOptions.RecipeWebsite),
new XElement("Tags", exportOptions.RecipeTags),
new XElement("Version", exportOptions.RecipeVersion),
new XElement("IsSetupRecipe", exportOptions.SetupRecipe),
new XElement("ExportUtc", XmlConvert.ToString(_clock.UtcNow, XmlDateTimeSerializationMode.Utc)) new XElement("ExportUtc", XmlConvert.ToString(_clock.UtcNow, XmlDateTimeSerializationMode.Utc))
) )
) )
); );
return exportRoot; return exportRoot;
} }
private XElement ExportMetadata(IEnumerable<string> contentTypes) {
var typesElement = new XElement("Types");
var partsElement = new XElement("Parts");
var typesToExport = _contentDefinitionManager.ListTypeDefinitions()
.Where(typeDefinition => contentTypes.Contains(typeDefinition.Name))
.ToList();
var partsToExport = new Dictionary<string, ContentPartDefinition>();
foreach (var contentTypeDefinition in typesToExport.OrderBy(x => x.Name)) {
foreach (var contentPartDefinition in contentTypeDefinition.Parts) {
if (partsToExport.ContainsKey(contentPartDefinition.PartDefinition.Name)) {
continue;
}
partsToExport.Add(contentPartDefinition.PartDefinition.Name, contentPartDefinition.PartDefinition);
}
typesElement.Add(_contentDefinitionWriter.Export(contentTypeDefinition));
}
foreach (var part in partsToExport.Values.OrderBy(x => x.Name)) {
partsElement.Add(_contentDefinitionWriter.Export(part));
}
return new XElement("Metadata", typesElement, partsElement);
}
private XElement ExportSiteSettings() {
var siteContentItem = _orchardServices.WorkContext.CurrentSite.ContentItem;
var exportedElements = ExportContentItem(siteContentItem).Elements().ToList();
foreach (var contentPart in siteContentItem.Parts.OrderBy(x => x.PartDefinition.Name)) {
var exportedElement = exportedElements.FirstOrDefault(element => element.Name == contentPart.PartDefinition.Name);
//Get all simple attributes if exported element is null
//Get exclude the simple attributes that already exist if element is not null
var simpleAttributes =
ExportSettingsPartAttributes(contentPart)
.Where(attribute => exportedElement == null || exportedElement.Attributes().All(xAttribute => xAttribute.Name != attribute.Name))
.OrderBy(x => x.Name.LocalName)
.ToList();
if (simpleAttributes.Any()) {
if (exportedElement == null) {
exportedElement = new XElement(contentPart.PartDefinition.Name);
exportedElements.Add(exportedElement);
}
exportedElement.Add(simpleAttributes);
}
}
exportedElements = exportedElements.OrderBy(x => x.Name.LocalName).ToList();
return new XElement("Settings", exportedElements);
}
private IEnumerable<XAttribute> ExportSettingsPartAttributes(ContentPart sitePart) {
foreach (var property in sitePart.GetType().GetProperties().OrderBy(x => x.Name)) {
var propertyType = property.PropertyType;
// Supported types (we also know they are not indexed properties).
if (propertyType == typeof(string) || propertyType == typeof(bool) || propertyType == typeof(int)) {
// Exclude read-only properties.
if (property.GetSetMethod() != null) {
var value = property.GetValue(sitePart, null);
if (value == null)
continue;
yield return new XAttribute(property.Name, value);
}
}
}
}
private XElement ExportData(IEnumerable<string> contentTypes, IEnumerable<ContentItem> contentItems, int? batchSize) {
var data = new XElement("Data");
if (batchSize.HasValue && batchSize.Value > 0)
data.SetAttributeValue("BatchSize", batchSize);
var orderedContentItemsQuery =
from contentItem in contentItems
let identity = _orchardServices.ContentManager.GetItemMetadata(contentItem).Identity.ToString()
orderby identity
select contentItem;
var orderedContentItems = orderedContentItemsQuery.ToList();
foreach (var contentType in contentTypes.OrderBy(x => x)) {
var type = contentType;
var items = orderedContentItems.Where(i => i.ContentType == type);
foreach (var contentItem in items) {
var contentItemElement = ExportContentItem(contentItem);
if (contentItemElement != null)
data.Add(contentItemElement);
}
}
return data;
}
private XElement ExportContentItem(ContentItem contentItem) {
// Call export handler for the item.
return _orchardServices.ContentManager.Export(contentItem);
}
private static VersionOptions GetContentExportVersionOptions(VersionHistoryOptions versionHistoryOptions) {
if (versionHistoryOptions.HasFlag(VersionHistoryOptions.Draft)) {
return VersionOptions.Draft;
}
return VersionOptions.Published;
}
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, DateTime.UtcNow.Ticks);
if (!_appDataFolder.DirectoryExists(ExportsDirectory)) { if (!_appDataFolder.DirectoryExists(ExportsDirectory)) {
_appDataFolder.CreateDirectory(ExportsDirectory); _appDataFolder.CreateDirectory(ExportsDirectory);
} }

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;
}

View File

@@ -0,0 +1,8 @@
namespace Orchard.ImportExport.ViewModels {
public class ContentTypeEntry {
public string Name { get; set; }
public string DisplayName { get; set; }
public bool ExportSchema { get; set; }
public bool ExportData { get; set; }
}
}

View File

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

View File

@@ -0,0 +1,14 @@
using System.Collections.Generic;
using Orchard.ImportExport.Models;
namespace Orchard.ImportExport.ViewModels {
public class DataExportStepViewModel {
public DataExportStepViewModel() {
ContentTypes = new List<ContentTypeEntry>();
}
public IList<ContentTypeEntry> ContentTypes { get; set; }
public VersionHistoryOptions VersionHistoryOptions { get; set; }
public int? ImportBatchSize { get; set; }
}
}

View File

@@ -0,0 +1,11 @@
using Orchard.Localization;
namespace Orchard.ImportExport.ViewModels {
public class ExportStepViewModel {
public string Name { get; set; }
public LocalizedString DisplayName { get; set; }
public LocalizedString Description { get; set; }
public bool IsSelected { get; set; }
public dynamic Editor { get; set; }
}
}

View File

@@ -2,29 +2,7 @@
namespace Orchard.ImportExport.ViewModels { namespace Orchard.ImportExport.ViewModels {
public class ExportViewModel { public class ExportViewModel {
public IList<ContentTypeEntry> ContentTypes { get; set; }
public IList<CustomStepEntry> CustomSteps { get; set; } public IList<CustomStepEntry> CustomSteps { get; set; }
public IList<dynamic> ExportSteps { get; set; } public IList<ExportStepViewModel> ExportSteps { get; set; }
public bool Metadata { get; set; }
public bool Data { get; set; }
public int? ImportBatchSize { get; set; }
public string DataImportChoice { get; set; }
public bool SiteSettings { get; set; }
public bool SetupRecipe { get; set; }
public string RecipeName { get; set; }
public string RecipeDescription { get; set; }
public string RecipeWebsite { get; set; }
public string RecipeTags { get; set; }
public string RecipeVersion { get; set; }
}
public class ContentTypeEntry {
public string ContentTypeName { get; set; }
public bool IsChecked { get; set; }
}
public class CustomStepEntry {
public string CustomStep { get; set; }
public bool IsChecked { get; set; }
} }
} }

View File

@@ -0,0 +1,10 @@
namespace Orchard.ImportExport.ViewModels {
public class SetupRecipeStepViewModel {
public string RecipeName { get; set; }
public string RecipeDescription { get; set; }
public string RecipeAuthor { get; set; }
public string RecipeWebsite { get; set; }
public string RecipeTags { get; set; }
public string RecipeVersion { get; set; }
}
}

View File

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

View File

@@ -1,114 +1,44 @@
@using Orchard.Localization @using Orchard.Utility.Extensions
@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) { foreach (var exportStep in Model.ExportSteps) {
var displayName = (LocalizedString)exportStep.DisplayName; var stepName = Html.NameFor(m => m.ExportSteps[exportStepIndex].IsSelected).ToString();
var stepId = String.Format("step-{0}", displayName.ToString().HtmlClassify()); var stepId = stepName.HtmlClassify();
<fieldset>
<legend><label><input type="checkbox" id="@stepId" />@displayName</label></legend> <fieldset class="export-step export-step-@exportStep.Name.HtmlClassify()">
<div data-controllerid="@stepId"> <legend>
@Display(exportStep) <input type="hidden" name="@Html.NameFor(m => m.ExportSteps[exportStepIndex].Name)" value="@Model.ExportSteps[exportStepIndex].Name"/>
</div> <input type="checkbox" id="@stepId" name="@stepName" value="true"/>
</fieldset> <label for="@stepId" class="forcheckbox">@exportStep.DisplayName</label>
} </legend>
<fieldset> @Html.Hint(@exportStep.Description)
<legend>@T("Choose the types to include in the export file:")</legend> <div data-controllerid="@stepId">
<label><input type="checkbox" class="check-all" />@T("Select all")</label> @Display(exportStep.Editor)
<ol>
@for (var contentTypeIndex = 0; contentTypeIndex < Model.ContentTypes.Count; contentTypeIndex++) {
<li>
<input type="hidden" value="@Model.ContentTypes[contentTypeIndex].ContentTypeName" name="@Html.NameOf(m => m.ContentTypes[contentTypeIndex].ContentTypeName)"/>
<input type="checkbox" value="true" name="@Html.NameOf(m => m.ContentTypes[contentTypeIndex].IsChecked)" id="@Html.NameOf(m => m.ContentTypes[contentTypeIndex].IsChecked)" />
<label class="forcheckbox" for="@Html.NameOf(m => m.ContentTypes[contentTypeIndex].IsChecked)">@Model.ContentTypes[contentTypeIndex].ContentTypeName.CamelFriendly()</label>
</li>
}
</ol>
</fieldset>
<hr />
<fieldset>
<legend>@T("Choose what to save for these types:")</legend>
<div>
@Html.EditorFor(m => m.Metadata)
@Html.LabelFor(m => m.Metadata, T("Metadata").ToString(), new { @class = "forcheckbox" })
@Html.Hint(T("Metadata is the definition of your content types: what parts and fields they have, with what settings."))
</div>
<div>
@Html.EditorFor(m => m.Data)
@Html.LabelFor(m => m.Data, T("Data").ToString(), new { @class = "forcheckbox" })
@Html.Hint(T("Data is the actual content of your site."))
</div>
<div>
@Html.LabelFor(m => m.ImportBatchSize, T("Batch Size"))
@Html.TextBoxFor(m => m.ImportBatchSize, new {@class = "text small"})
@Html.Hint(T("The batch size to use when importing the data. Leave empty to disable batched imports."))
</div>
<div>
<p>@T("Version History")</p>
@Html.RadioButtonFor(m => m.DataImportChoice, "Published", new {id = "Published", Checked = "Checked"})
<label for="Published" class="forcheckbox">@T("Only Published Versions")</label>
<br/>
@Html.RadioButtonFor(m => m.DataImportChoice, "Draft", new {id = "Draft"})
<label for="Draft" class="forcheckbox">@T("Only Drafts")</label>
</div>
<div>
@Html.EditorFor(m => m.SiteSettings)
<label class="forcheckbox" for="@Html.FieldIdFor(m => m.SiteSettings)">@T("Site Settings")</label><br/>
@Html.Hint(T("Please verify that you are not exporting confidential information, such as passwords or application keys."))
</div>
</fieldset>
<fieldset>
<legend>@T("Setup")</legend>
<div>
@Html.CheckBoxFor(m => m.SetupRecipe)
@Html.LabelFor(m => m.SetupRecipe, T("Setup Recipe").ToString(), new {@class = "forcheckbox"})
@Html.Hint(T("Check this option if you want to use the generated recipe as a setup recipe."))
</div>
<div data-controllerid="@Html.FieldIdFor(m => m.SetupRecipe)">
<div>
@Html.LabelFor(m => m.RecipeName, T("Name"))
@Html.TextBoxFor(m => m.RecipeName, new { @class = "text medium" })
@Html.Hint(T("Optionally provide a name for the setup recipe."))
</div> </div>
<div> </fieldset>
@Html.LabelFor(m => m.RecipeDescription, T("Description")) exportStepIndex++;
@Html.TextBoxFor(m => m.RecipeDescription, new {@class = "text large"}) if (exportStepIndex < Model.ExportSteps.Count) {
@Html.Hint(T("Optionally provide a description for the setup recipe.")) <hr />
</div> }
<div> }
@Html.LabelFor(m => m.RecipeWebsite, T("Website"))
@Html.TextBoxFor(m => m.RecipeWebsite, new {@class = "text large"})
@Html.Hint(T("Optionally provide a website URL for the setup recipe."))
</div>
<div>
@Html.LabelFor(m => m.RecipeTags, T("Tags"))
@Html.TextBoxFor(m => m.RecipeTags, new {@class = "text large"})
@Html.Hint(T("Optionally provide tags for the setup recipe."))
</div>
<div>
@Html.LabelFor(m => m.RecipeVersion, T("Version"))
@Html.TextBoxFor(m => m.RecipeVersion, new {@class = "text small"})
@Html.Hint(T("Optionally provide a version for the setup recipe."))
</div>
</div>
</fieldset>
if (Model.CustomSteps.Any()) { if (Model.CustomSteps.Any()) {
<fieldset> <fieldset>
<legend>@T("Choose the custom steps to execute in the export file:")</legend> <legend>@T("Choose the custom steps to execute in the export file:")</legend>
<ol> <ol>
@for (var customStepIndex = 0; customStepIndex < Model.CustomSteps.Count; customStepIndex++) { @for (var customStepIndex = 0; customStepIndex < Model.CustomSteps.Count; customStepIndex++) {
<li> <li>
<input type="hidden" value="@Model.CustomSteps[customStepIndex].CustomStep" name="@Html.NameOf(m => m.CustomSteps[customStepIndex].CustomStep)"/> <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)" /> <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> <label class="forcheckbox" for="@Html.NameOf(m => m.CustomSteps[customStepIndex].IsChecked)">@Model.CustomSteps[customStepIndex].CustomStep.CamelFriendly()</label>
</li> </li>
} }
</ol> </ol>
</fieldset> </fieldset>
} }
<button type="submit" class="primaryAction">@T("Export")</button> <button type="submit" class="primaryAction">@T("Export")</button>
} }

View File

@@ -1,5 +1,57 @@
<table> @model Orchard.ImportExport.ViewModels.DataExportStepViewModel
<thead> @{
Style.Include("exportstep-data.css");
</thead> }
</table> <div>
<table class="items">
<thead>
<tr>
<th>@T("Content Type")</th>
<th>@T("Schema")</th>
<th>@T("Data")</th>
<th>@T("Both")</th>
</tr>
<tr class="sub">
<th>&nbsp;</th>
<th><input type="checkbox"/></th>
<th><input type="checkbox"/></th>
<th><input type="checkbox"/></th>
</tr>
</thead>
<tbody>
@{ var contentTypeIndex = 0;}
@foreach (var contentType in Model.ContentTypes) {
<tr>
<td>@contentType.DisplayName</td>
<td>
<input type="hidden" name="@Html.NameFor(m => m.ContentTypes[contentTypeIndex].Name)" value="@Model.ContentTypes[contentTypeIndex].Name"/>
<input type="checkbox" name="@Html.NameFor(m => m.ContentTypes[contentTypeIndex].ExportSchema)" value="true"/>
</td>
<td>
<input type="checkbox" name="@Html.NameFor(m => m.ContentTypes[contentTypeIndex].ExportData)" value="true"/>
</td>
<td><input type="checkbox"/></td>
</tr>
contentTypeIndex++;
}
</tbody>
</table>
@Html.Hint(T("Choose the types to include in the export file"))
</div>
<div>
@Html.LabelFor(m => m.ImportBatchSize, T("Batch Size"))
@Html.TextBoxFor(m => m.ImportBatchSize, new { @class = "text small" })
@Html.Hint(T("The batch size to use when importing the data. Leave empty to disable batched imports."))
</div>
<div>
<p>@T("Version History")</p>
@Html.RadioButtonFor(m => m.VersionHistoryOptions, "Published", new { id = "Published", Checked = "Checked" })
<label for="Published" class="forcheckbox">@T("Only Published Versions")</label>
<br />
@Html.RadioButtonFor(m => m.VersionHistoryOptions, "Draft", new { id = "Draft" })
<label for="Draft" class="forcheckbox">@T("Only Drafts")</label>
<br />
@Html.RadioButtonFor(m => m.VersionHistoryOptions, "Latest", new { id = "Latest" })
<label for="Latest" class="forcheckbox">@T("Latest Versions")</label>
</div>

View File

@@ -0,0 +1,31 @@
@model Orchard.ImportExport.ViewModels.SetupRecipeStepViewModel
<div>
@Html.LabelFor(m => m.RecipeName, T("Name"))
@Html.TextBoxFor(m => m.RecipeName, new { @class = "text medium" })
@Html.Hint(T("Optionally provide a name for the setup recipe."))
</div>
<div>
@Html.LabelFor(m => m.RecipeDescription, T("Description"))
@Html.TextBoxFor(m => m.RecipeDescription, new {@class = "text large"})
@Html.Hint(T("Optionally provide a description for the setup recipe."))
</div>
<div>
@Html.LabelFor(m => m.RecipeAuthor, T("Author"))
@Html.TextBoxFor(m => m.RecipeAuthor, new { @class = "text large" })
@Html.Hint(T("Optionally provide the name of the author for the setup recipe."))
</div>
<div>
@Html.LabelFor(m => m.RecipeWebsite, T("Website"))
@Html.TextBoxFor(m => m.RecipeWebsite, new { @class = "text large" })
@Html.Hint(T("Optionally provide a website URL for the setup recipe."))
</div>
<div>
@Html.LabelFor(m => m.RecipeTags, T("Tags"))
@Html.TextBoxFor(m => m.RecipeTags, new { @class = "text large" })
@Html.Hint(T("Optionally provide tags for the setup recipe."))
</div>
<div>
@Html.LabelFor(m => m.RecipeVersion, T("Version"))
@Html.TextBoxFor(m => m.RecipeVersion, new { @class = "text small" })
@Html.Hint(T("Optionally provide a version for the setup recipe."))
</div>

View File

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