mirror of
https://github.com/OrchardCMS/Orchard.git
synced 2025-10-15 19:54:57 +08:00
Merge
--HG-- branch : dev
This commit is contained in:
@@ -16,7 +16,6 @@ using Orchard.ContentManagement.Records;
|
||||
using Orchard.Localization;
|
||||
using Orchard.Security;
|
||||
using Orchard.Tests.Modules;
|
||||
using Orchard.Mvc.ViewModels;
|
||||
using Orchard.Core.Common.ViewModels;
|
||||
using System.Web.Mvc;
|
||||
|
||||
|
@@ -1,7 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
using NUnit.Framework;
|
||||
using Orchard.ContentManagement.MetaData;
|
||||
|
@@ -1,11 +1,10 @@
|
||||
using System.Collections.Generic;
|
||||
using Orchard.ContentManagement;
|
||||
using Orchard.ContentManagement;
|
||||
using Orchard.ContentManagement.MetaData.Models;
|
||||
|
||||
namespace Orchard.Tests.ContentManagement.Models {
|
||||
public class Phi : ContentField {
|
||||
public Phi() {
|
||||
PartFieldDefinition = new ContentPartDefinition.Field(new ContentFieldDefinition("Phi"), "Phi", new Dictionary<string, string>());
|
||||
PartFieldDefinition = new ContentPartDefinition.Field(new ContentFieldDefinition("Phi"), "Phi", new SettingsDictionary());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
276
src/Orchard.Tests/DataMigration/DataMigrationTests.cs
Normal file
276
src/Orchard.Tests/DataMigration/DataMigrationTests.cs
Normal file
@@ -0,0 +1,276 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Autofac;
|
||||
using NHibernate;
|
||||
using NUnit.Framework;
|
||||
using Orchard.ContentManagement.Records;
|
||||
using Orchard.Data;
|
||||
using Orchard.Environment.Extensions;
|
||||
using Orchard.Environment.Extensions.Folders;
|
||||
using Orchard.Environment.Extensions.Loaders;
|
||||
using Orchard.Environment.Extensions.Models;
|
||||
using Orchard.Tests.ContentManagement;
|
||||
using Orchard.DataMigration;
|
||||
|
||||
namespace Orchard.Tests.DataMigration {
|
||||
[TestFixture]
|
||||
public class DataMigrationTests {
|
||||
private IContainer _container;
|
||||
private IExtensionManager _manager;
|
||||
private StubFolders _folders;
|
||||
private IDataMigrationManager _dataMigrationManager;
|
||||
private IRepository<DataMigrationRecord> _repository;
|
||||
|
||||
private ISessionFactory _sessionFactory;
|
||||
private ISession _session;
|
||||
|
||||
[SetUp]
|
||||
public void Init() {
|
||||
Init(Enumerable.Empty<Type>());
|
||||
}
|
||||
|
||||
public void Init(IEnumerable<Type> dataMigrations) {
|
||||
|
||||
var databaseFileName = System.IO.Path.GetTempFileName();
|
||||
_sessionFactory = DataUtility.CreateSessionFactory(
|
||||
databaseFileName,
|
||||
typeof(DataMigrationRecord),
|
||||
typeof(ContentItemVersionRecord),
|
||||
typeof(ContentItemRecord),
|
||||
typeof(ContentTypeRecord));
|
||||
|
||||
var builder = new ContainerBuilder();
|
||||
_folders = new StubFolders();
|
||||
builder.RegisterInstance(_folders).As<IExtensionFolders>();
|
||||
builder.RegisterType<ExtensionManager>().As<IExtensionManager>();
|
||||
builder.RegisterType<DataMigrationManager>().As<IDataMigrationManager>();
|
||||
builder.RegisterType<DefaultDataMigrationGenerator>().As<IDataMigrationGenerator>();
|
||||
builder.RegisterGeneric(typeof(Repository<>)).As(typeof(IRepository<>));
|
||||
_session = _sessionFactory.OpenSession();
|
||||
builder.RegisterInstance(new DefaultContentManagerTests.TestSessionLocator(_session)).As<ISessionLocator>();
|
||||
foreach(var type in dataMigrations) {
|
||||
builder.RegisterType(type).As<IDataMigration>();
|
||||
}
|
||||
_container = builder.Build();
|
||||
_manager = _container.Resolve<IExtensionManager>();
|
||||
_dataMigrationManager = _container.Resolve<IDataMigrationManager>();
|
||||
_repository = _container.Resolve<IRepository<DataMigrationRecord>>();
|
||||
|
||||
}
|
||||
|
||||
public class StubFolders : IExtensionFolders {
|
||||
public StubFolders() {
|
||||
Manifests = new Dictionary<string, string>();
|
||||
}
|
||||
|
||||
public IDictionary<string, string> Manifests { get; set; }
|
||||
|
||||
public IEnumerable<ExtensionDescriptor> AvailableExtensions() {
|
||||
foreach (var e in Manifests) {
|
||||
string name = e.Key;
|
||||
var parseResult = ExtensionFolders.ParseManifest(Manifests[name]);
|
||||
yield return ExtensionFolders.GetDescriptorForExtension("~/", name, "Module", parseResult);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class DataMigrationEmpty : IDataMigration {
|
||||
public string Feature {
|
||||
get { return "Feature1"; }
|
||||
}
|
||||
}
|
||||
|
||||
public class DataMigration11 : IDataMigration {
|
||||
public string Feature {
|
||||
get { return "Feature1"; }
|
||||
}
|
||||
}
|
||||
|
||||
public class DataMigration11Create : IDataMigration {
|
||||
public string Feature {
|
||||
get { return "Feature1"; }
|
||||
}
|
||||
|
||||
public int Create() {
|
||||
return 999;
|
||||
}
|
||||
}
|
||||
|
||||
public class DataMigrationCreateCanBeFollowedByUpdates : IDataMigration {
|
||||
public string Feature {
|
||||
get { return "Feature1"; }
|
||||
}
|
||||
|
||||
public int Create() {
|
||||
return 42;
|
||||
}
|
||||
|
||||
public int UpdateFrom42() {
|
||||
return 666;
|
||||
}
|
||||
}
|
||||
|
||||
public class DataMigrationSameMigrationClassCanEvolve : IDataMigration {
|
||||
public string Feature {
|
||||
get { return "Feature1"; }
|
||||
}
|
||||
|
||||
public int Create() {
|
||||
return 999;
|
||||
}
|
||||
|
||||
public int UpdateFrom42() {
|
||||
return 666;
|
||||
}
|
||||
|
||||
public int UpdateFrom666() {
|
||||
return 999;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class DataMigrationDependenciesModule1 : IDataMigration {
|
||||
public string Feature {
|
||||
get { return "Feature1"; }
|
||||
}
|
||||
|
||||
public int Create() {
|
||||
return 999;
|
||||
}
|
||||
}
|
||||
public class DataMigrationDependenciesModule2 : IDataMigration {
|
||||
public string Feature {
|
||||
get { return "Feature2"; }
|
||||
}
|
||||
|
||||
public int Create() {
|
||||
return 999;
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DataMigrationShouldDoNothingIfNoDataMigrationIsProvidedForFeature() {
|
||||
Init(new Type[] {typeof (DataMigrationEmpty)});
|
||||
|
||||
_folders.Manifests.Add("Module2", @"
|
||||
name: Module2
|
||||
version: 0.1
|
||||
orchardversion: 1
|
||||
features:
|
||||
Feature1:
|
||||
Description: Feature
|
||||
");
|
||||
|
||||
_dataMigrationManager.Upgrade("Feature1");
|
||||
Assert.That(_repository.Table.Count(), Is.EqualTo(0));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DataMigrationShouldDoNothingIfNoUpgradeOrCreateMethodWasFound() {
|
||||
Init(new Type[] { typeof(DataMigration11) });
|
||||
|
||||
_folders.Manifests.Add("Module1", @"
|
||||
name: Module1
|
||||
version: 0.1
|
||||
orchardversion: 1
|
||||
features:
|
||||
Feature1:
|
||||
Description: Feature
|
||||
");
|
||||
|
||||
_dataMigrationManager.Upgrade("Feature1");
|
||||
Assert.That(_repository.Table.Count(), Is.EqualTo(0));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CreateShouldReturnVersionNumber() {
|
||||
Init(new Type[] { typeof(DataMigration11Create) });
|
||||
|
||||
_folders.Manifests.Add("Module1", @"
|
||||
name: Module1
|
||||
version: 0.1
|
||||
orchardversion: 1
|
||||
features:
|
||||
Feature1:
|
||||
Description: Feature
|
||||
");
|
||||
|
||||
_dataMigrationManager.Upgrade("Feature1");
|
||||
Assert.That(_repository.Table.Count(), Is.EqualTo(1));
|
||||
Assert.That(_repository.Table.First().Current, Is.EqualTo(999));
|
||||
Assert.That(_repository.Table.First().DataMigrationClass, Is.EqualTo("Orchard.Tests.DataMigration.DataMigrationTests+DataMigration11Create"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CreateCanBeFollowedByUpdates() {
|
||||
Init(new Type[] {typeof (DataMigrationCreateCanBeFollowedByUpdates)});
|
||||
|
||||
_folders.Manifests.Add("Module1", @"
|
||||
name: Module1
|
||||
version: 0.1
|
||||
orchardversion: 1
|
||||
features:
|
||||
Feature1:
|
||||
Description: Feature
|
||||
");
|
||||
|
||||
_dataMigrationManager.Upgrade("Feature1");
|
||||
Assert.That(_repository.Table.Count(), Is.EqualTo(1));
|
||||
Assert.That(_repository.Table.First().Current, Is.EqualTo(666));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SameMigrationClassCanEvolve() {
|
||||
Init(new Type[] { typeof(DataMigrationSameMigrationClassCanEvolve) });
|
||||
|
||||
_folders.Manifests.Add("Module1", @"
|
||||
name: Module1
|
||||
version: 0.1
|
||||
orchardversion: 1
|
||||
features:
|
||||
Feature1:
|
||||
Description: Feature
|
||||
");
|
||||
_repository.Create(new DataMigrationRecord() {
|
||||
Current = 42,
|
||||
DataMigrationClass = "Orchard.Tests.DataMigration.DataMigrationTests+DataMigrationSameMigrationClassCanEvolve"
|
||||
});
|
||||
|
||||
_dataMigrationManager.Upgrade("Feature1");
|
||||
Assert.That(_repository.Table.Count(), Is.EqualTo(1));
|
||||
Assert.That(_repository.Table.First().Current, Is.EqualTo(999));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DependenciesShouldBeUpgradedFirst() {
|
||||
|
||||
Init(new Type[] { typeof(DataMigrationDependenciesModule1), typeof(DataMigrationDependenciesModule2) });
|
||||
|
||||
_folders.Manifests.Add("Module1", @"
|
||||
name: Module1
|
||||
version: 0.1
|
||||
orchardversion: 1
|
||||
features:
|
||||
Feature1:
|
||||
Description: Feature
|
||||
Dependencies: Feature2
|
||||
");
|
||||
|
||||
_folders.Manifests.Add("Module2", @"
|
||||
name: Module2
|
||||
version: 0.1
|
||||
orchardversion: 1
|
||||
features:
|
||||
Feature2:
|
||||
Description: Feature
|
||||
");
|
||||
_dataMigrationManager.Upgrade("Feature1");
|
||||
Assert.That(_repository.Table.Count(), Is.EqualTo(2));
|
||||
Assert.That(_repository.Fetch(d => d.Current == 999).Count(), Is.EqualTo(2));
|
||||
Assert.That(_repository.Fetch(d => d.DataMigrationClass == "Orchard.Tests.DataMigration.DataMigrationTests+DataMigrationDependenciesModule1").Count(), Is.EqualTo(1));
|
||||
Assert.That(_repository.Fetch(d => d.DataMigrationClass == "Orchard.Tests.DataMigration.DataMigrationTests+DataMigrationDependenciesModule2").Count(), Is.EqualTo(1));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@@ -180,6 +180,7 @@
|
||||
<Compile Include="ContentManagement\Records\GammaRecord.cs">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Include="DataMigration\DataMigrationTests.cs" />
|
||||
<Compile Include="DataUtility.cs" />
|
||||
<Compile Include="Data\Builders\SessionFactoryBuilderTests.cs" />
|
||||
<Compile Include="Data\RepositoryTests.cs" />
|
||||
|
@@ -1,8 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
using Orchard.ContentManagement;
|
||||
using Orchard.ContentManagement;
|
||||
using Orchard.ContentManagement.Drivers;
|
||||
using Orchard.Core.Common.Models;
|
||||
using Orchard.Core.Common.ViewModels;
|
||||
|
@@ -1,10 +0,0 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace Orchard.Core.Contents {
|
||||
public class ContentTypeDefinitionStub {
|
||||
[StringLength(128)]
|
||||
public string Name { get; set; }
|
||||
[Required, StringLength(1024)]
|
||||
public string DisplayName { get; set; }
|
||||
}
|
||||
}
|
@@ -3,12 +3,13 @@ using System.Linq;
|
||||
using System.Web.Mvc;
|
||||
using System.Web.Routing;
|
||||
using Orchard.ContentManagement;
|
||||
using Orchard.ContentManagement.MetaData;
|
||||
using Orchard.ContentManagement.MetaData.Models;
|
||||
using Orchard.Core.Contents.Services;
|
||||
using Orchard.Core.Contents.ViewModels;
|
||||
using Orchard.Data;
|
||||
using Orchard.Localization;
|
||||
using Orchard.Logging;
|
||||
using Orchard.Mvc.Results;
|
||||
using Orchard.Mvc.ViewModels;
|
||||
using Orchard.UI.Notify;
|
||||
|
||||
@@ -51,19 +52,19 @@ namespace Orchard.Core.Contents.Controllers {
|
||||
});
|
||||
}
|
||||
|
||||
public ActionResult CreateType(CreateTypeViewModel viewModel) {
|
||||
if (!Services.Authorizer.Authorize(Permissions.CreateContentType, T("Not allowed to create a content type.")))
|
||||
public ActionResult CreateType() {
|
||||
if (!Services.Authorizer.Authorize(Permissions.CreateContentTypes, T("Not allowed to create a content type.")))
|
||||
return new HttpUnauthorizedResult();
|
||||
|
||||
return View(viewModel);
|
||||
return View(new CreateTypeViewModel());
|
||||
}
|
||||
|
||||
[HttpPost, ActionName("CreateType")]
|
||||
public ActionResult CreateTypePOST(CreateTypeViewModel viewModel) {
|
||||
if (!Services.Authorizer.Authorize(Permissions.CreateContentType, T("Not allowed to create a content type.")))
|
||||
if (!Services.Authorizer.Authorize(Permissions.CreateContentTypes, T("Not allowed to create a content type.")))
|
||||
return new HttpUnauthorizedResult();
|
||||
|
||||
var model = new ContentTypeDefinitionStub();
|
||||
var model = new ContentTypeDefinition("");
|
||||
TryUpdateModel(model);
|
||||
|
||||
if (!ModelState.IsValid) {
|
||||
@@ -76,9 +77,69 @@ namespace Orchard.Core.Contents.Controllers {
|
||||
return RedirectToAction("Index");
|
||||
}
|
||||
|
||||
public ActionResult EditType(string id) {
|
||||
if (!Services.Authorizer.Authorize(Permissions.CreateContentTypes, T("Not allowed to edit a content type.")))
|
||||
return new HttpUnauthorizedResult();
|
||||
|
||||
var contentTypeDefinition = _contentDefinitionService.GetTypeDefinition(id);
|
||||
|
||||
if (contentTypeDefinition == null)
|
||||
return new NotFoundResult();
|
||||
|
||||
return View(new EditTypeViewModel(contentTypeDefinition));
|
||||
}
|
||||
|
||||
[HttpPost, ActionName("EditType")]
|
||||
public ActionResult EditTypePOST(string id) {
|
||||
if (!Services.Authorizer.Authorize(Permissions.CreateContentTypes, T("Not allowed to edit a content type.")))
|
||||
return new HttpUnauthorizedResult();
|
||||
|
||||
var contentTypeDefinition = _contentDefinitionService.GetTypeDefinition(id);
|
||||
|
||||
if (contentTypeDefinition == null)
|
||||
return new NotFoundResult();
|
||||
|
||||
var viewModel = new EditTypeViewModel();
|
||||
TryUpdateModel(viewModel);
|
||||
|
||||
if (!ModelState.IsValid) {
|
||||
return EditType(id);
|
||||
}
|
||||
|
||||
//todo: apply the changes along the lines of but definately not resembling
|
||||
// for now this _might_ just get a little messy ->
|
||||
_contentDefinitionService.AlterTypeDefinition(
|
||||
new ContentTypeDefinition(
|
||||
viewModel.Name,
|
||||
viewModel.DisplayName,
|
||||
viewModel.Parts.Select(
|
||||
p => new ContentTypeDefinition.Part(
|
||||
new ContentPartDefinition(
|
||||
p.PartDefinition.Name,
|
||||
p.PartDefinition.Fields.Select(
|
||||
f => new ContentPartDefinition.Field(
|
||||
new ContentFieldDefinition(f.FieldDefinition.Name),
|
||||
f.Name,
|
||||
f.Settings
|
||||
)
|
||||
),
|
||||
p.PartDefinition.Settings
|
||||
),
|
||||
p.Settings
|
||||
)
|
||||
),
|
||||
viewModel.Settings
|
||||
)
|
||||
);
|
||||
// little == lot
|
||||
|
||||
return RedirectToAction("Index");
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Content
|
||||
|
||||
#endregion
|
||||
|
||||
public ActionResult List(ListContentsViewModel model) {
|
||||
|
@@ -3,15 +3,17 @@ using Orchard.Security.Permissions;
|
||||
|
||||
namespace Orchard.Core.Contents {
|
||||
public class Permissions : IPermissionProvider {
|
||||
public static readonly Permission CreateContentType = new Permission { Name = "CreateContentType", Description = "Create custom content type." };
|
||||
public static readonly Permission CreateContentTypes = new Permission { Name = "CreateContentTypes", Description = "Create custom content types." };
|
||||
public static readonly Permission EditContentTypes = new Permission { Name = "EditContentTypes", Description = "Edit content types." };
|
||||
|
||||
public string ModuleName {
|
||||
get { return "Contents"; }
|
||||
}
|
||||
|
||||
public IEnumerable<Permission> GetPermissions() {
|
||||
return new Permission[] {
|
||||
CreateContentType,
|
||||
return new [] {
|
||||
CreateContentTypes,
|
||||
EditContentTypes,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -19,7 +21,7 @@ namespace Orchard.Core.Contents {
|
||||
return new[] {
|
||||
new PermissionStereotype {
|
||||
Name = "Administrator",
|
||||
Permissions = new[] {CreateContentType}
|
||||
Permissions = GetPermissions()
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@@ -25,25 +25,30 @@ namespace Orchard.Core.Contents.Services {
|
||||
}
|
||||
|
||||
public ContentTypeDefinition GetTypeDefinition(string name) {
|
||||
throw new NotImplementedException();
|
||||
return _contentDefinitionManager.GetTypeDefinition(name);
|
||||
}
|
||||
|
||||
public void AddTypeDefinition(ContentTypeDefinitionStub definitionStub) {
|
||||
if (string.IsNullOrWhiteSpace(definitionStub.Name))
|
||||
definitionStub.Name = GenerateTypeName(definitionStub.DisplayName);
|
||||
public void AddTypeDefinition(ContentTypeDefinition contentTypeDefinition) {
|
||||
var typeName = string.IsNullOrWhiteSpace(contentTypeDefinition.Name)
|
||||
? GenerateTypeName(contentTypeDefinition.DisplayName)
|
||||
: contentTypeDefinition.Name;
|
||||
|
||||
while (_contentDefinitionManager.GetTypeDefinition(definitionStub.Name) != null)
|
||||
definitionStub.Name = VersionTypeName(definitionStub.Name);
|
||||
while (_contentDefinitionManager.GetTypeDefinition(typeName) != null)
|
||||
typeName = VersionTypeName(typeName);
|
||||
|
||||
//just giving the new type some default parts for now
|
||||
_contentDefinitionManager.AlterTypeDefinition(
|
||||
definitionStub.Name,
|
||||
cfg => cfg.Named(definitionStub.Name, definitionStub.DisplayName)
|
||||
typeName,
|
||||
cfg => cfg.Named(typeName, contentTypeDefinition.DisplayName)
|
||||
.WithPart("CommonAspect")
|
||||
//.WithPart("RoutableAspect") //need to go the new routable route
|
||||
.WithPart("BodyAspect"));
|
||||
|
||||
Services.Notifier.Information(T("Created content type: {0}", definitionStub.DisplayName));
|
||||
Services.Notifier.Information(T("Created content type: {0}", contentTypeDefinition.DisplayName));
|
||||
}
|
||||
|
||||
public void AlterTypeDefinition(ContentTypeDefinition contentTypeDefinition) {
|
||||
_contentDefinitionManager.StoreTypeDefinition(contentTypeDefinition);
|
||||
}
|
||||
|
||||
public void RemoveTypeDefinition(string name) {
|
||||
@@ -69,7 +74,7 @@ namespace Orchard.Core.Contents.Services {
|
||||
}
|
||||
|
||||
private static string VersionTypeName(string name) {
|
||||
var version = 2;
|
||||
int version;
|
||||
var nameParts = name.Split(new[] { '-' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
|
||||
if (nameParts.Length > 1 && int.TryParse(nameParts.Last(), out version)) {
|
||||
@@ -77,6 +82,9 @@ namespace Orchard.Core.Contents.Services {
|
||||
//this could unintentionally chomp something that looks like a version
|
||||
name = string.Join("-", nameParts.Take(nameParts.Length - 1));
|
||||
}
|
||||
else {
|
||||
version = 2;
|
||||
}
|
||||
|
||||
return string.Format("{0}-{1}", name, version);
|
||||
}
|
||||
|
@@ -5,7 +5,8 @@ namespace Orchard.Core.Contents.Services {
|
||||
public interface IContentDefinitionService : IDependency {
|
||||
IEnumerable<ContentTypeDefinition> GetTypeDefinitions();
|
||||
ContentTypeDefinition GetTypeDefinition(string name);
|
||||
void AddTypeDefinition(ContentTypeDefinitionStub contentTypeDefinition);
|
||||
void AddTypeDefinition(ContentTypeDefinition contentTypeDefinition);
|
||||
void AlterTypeDefinition(ContentTypeDefinition contentTypeDefinition);
|
||||
void RemoveTypeDefinition(string name);
|
||||
}
|
||||
}
|
6
src/Orchard.Web/Core/Contents/Styles/admin.css
Normal file
6
src/Orchard.Web/Core/Contents/Styles/admin.css
Normal file
@@ -0,0 +1,6 @@
|
||||
.contents #main h2 {
|
||||
margin:1.5em 0 .5em;
|
||||
}
|
||||
.manage.add-to-type {
|
||||
margin-top:-4em;
|
||||
}
|
@@ -0,0 +1,77 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Orchard.ContentManagement.MetaData.Models;
|
||||
using Orchard.Mvc.ViewModels;
|
||||
|
||||
namespace Orchard.Core.Contents.ViewModels {
|
||||
public class EditTypeViewModel : BaseViewModel {
|
||||
public EditTypeViewModel() {
|
||||
Settings = new SettingsDictionary();
|
||||
Parts = new List<EditTypePartViewModel>();
|
||||
}
|
||||
public EditTypeViewModel(ContentTypeDefinition contentTypeDefinition) {
|
||||
Name = contentTypeDefinition.Name;
|
||||
DisplayName = contentTypeDefinition.DisplayName;
|
||||
Settings = contentTypeDefinition.Settings;
|
||||
Parts = contentTypeDefinition.Parts.Select(p => new EditTypePartViewModel(p));
|
||||
}
|
||||
|
||||
public string Name { get; set; }
|
||||
public string DisplayName { get; set; }
|
||||
public SettingsDictionary Settings { get; set; }
|
||||
public IEnumerable<EditTypePartViewModel> Parts { get; set; }
|
||||
}
|
||||
|
||||
public class EditTypePartViewModel {
|
||||
public EditTypePartViewModel() {
|
||||
Settings = new SettingsDictionary();
|
||||
}
|
||||
public EditTypePartViewModel(ContentTypeDefinition.Part part) {
|
||||
PartDefinition = new EditPartViewModel(part.PartDefinition);
|
||||
Settings = part.Settings;
|
||||
}
|
||||
|
||||
public EditPartViewModel PartDefinition { get; set; }
|
||||
public SettingsDictionary Settings { get; set; }
|
||||
}
|
||||
|
||||
public class EditPartViewModel {
|
||||
public EditPartViewModel() {
|
||||
Fields = new List<EditPartFieldViewModel>();
|
||||
Settings = new SettingsDictionary();
|
||||
}
|
||||
public EditPartViewModel(ContentPartDefinition contentPartDefinition) {
|
||||
Name = contentPartDefinition.Name;
|
||||
Fields = contentPartDefinition.Fields.Select(f => new EditPartFieldViewModel(f));
|
||||
Settings = contentPartDefinition.Settings;
|
||||
}
|
||||
|
||||
public string Name { get; set; }
|
||||
public IEnumerable<EditPartFieldViewModel> Fields { get; set; }
|
||||
public SettingsDictionary Settings { get; set; }
|
||||
}
|
||||
|
||||
public class EditPartFieldViewModel {
|
||||
public EditPartFieldViewModel() {
|
||||
Settings = new SettingsDictionary();
|
||||
}
|
||||
public EditPartFieldViewModel(ContentPartDefinition.Field field) {
|
||||
Name = field.Name;
|
||||
FieldDefinition = new EditFieldViewModel(field.FieldDefinition);
|
||||
Settings = field.Settings;
|
||||
}
|
||||
|
||||
public string Name { get; set; }
|
||||
public EditFieldViewModel FieldDefinition { get; set; }
|
||||
public SettingsDictionary Settings { get; set; }
|
||||
}
|
||||
|
||||
public class EditFieldViewModel {
|
||||
public EditFieldViewModel() { }
|
||||
public EditFieldViewModel(ContentFieldDefinition contentFieldDefinition) {
|
||||
Name = Name;
|
||||
}
|
||||
|
||||
public string Name { get; set; }
|
||||
}
|
||||
}
|
23
src/Orchard.Web/Core/Contents/Views/Admin/EditType.ascx
Normal file
23
src/Orchard.Web/Core/Contents/Views/Admin/EditType.ascx
Normal file
@@ -0,0 +1,23 @@
|
||||
<%@ Control Language="C#" Inherits="Orchard.Mvc.ViewUserControl<EditTypeViewModel>" %>
|
||||
<%@ Import Namespace="Orchard.Core.Contents.ViewModels" %><%
|
||||
Html.RegisterStyle("admin.css"); %>
|
||||
<h1><%:Html.TitleForPage(T("Edit Content Type").ToString())%></h1><%
|
||||
using (Html.BeginFormAntiForgeryPost()) { %>
|
||||
<%:Html.ValidationSummary() %>
|
||||
<fieldset>
|
||||
<label for="DisplayName"><%:T("Display Name") %></label>
|
||||
<%:Html.TextBoxFor(m => m.DisplayName, new {@class = "textMedium"}) %>
|
||||
<label for="Name"><%:T("Name") %></label>
|
||||
<%:Html.TextBoxFor(m => m.Name, new {@class = "textMedium"}) %>
|
||||
</fieldset>
|
||||
<%:Html.EditorFor(m => m.Settings) %>
|
||||
<h2><%:T("Parts") %></h2>
|
||||
<div class="manage add-to-type"><%: Html.ActionLink(T("Add").Text, "AddPart", new { }, new { @class = "button" })%></div>
|
||||
<%:Html.EditorFor(m => m.Parts, "Parts", "") %>
|
||||
<h2><%:T("Fields") %></h2>
|
||||
<div class="manage add-to-type"><%: Html.ActionLink(T("Add").Text, "AddField", new { }, new { @class = "button" })%></div>
|
||||
<%--<%:Html.EditorFor(m => m.Fields, "ContentTypeFields")%>--%>
|
||||
<fieldset>
|
||||
<button class="primaryAction" type="submit"><%:T("Save") %></button>
|
||||
</fieldset><%
|
||||
} %>
|
@@ -6,7 +6,7 @@
|
||||
</div>
|
||||
<div class="related">
|
||||
<%:Html.ActionLink(T("List Items").ToString(), "List", new {area = "Contents", id = Model.Name})%><%:T(" | ")%>
|
||||
<%:Html.ActionLink(T("[Edit]").ToString(), "EditType", new {area = "Contents", id = Model.Name})%><%:T(" | ") %>
|
||||
<%:Html.ActionLink(T("Edit").ToString(), "EditType", new {area = "Contents", id = Model.Name})%><%:T(" | ") %>
|
||||
<% using (Html.BeginFormAntiForgeryPost(Url.Action("RemoveType", new {area = "Contents", id = Model.Name}), FormMethod.Post, new { @class = "inline link" })) { %>
|
||||
<button type="submit" class="linkButton" title="<%:T("Delete") %>"><%:T("[Delete]")%></button><%
|
||||
} %>
|
||||
|
@@ -0,0 +1,13 @@
|
||||
<%@ Control Language="C#" Inherits="Orchard.Mvc.ViewUserControl<ContentTypeDefinition.Part>" %>
|
||||
<%@ Import Namespace="Orchard.ContentManagement.MetaData.Models" %>
|
||||
<fieldset>
|
||||
<h3><%:Model.PartDefinition.Name %></h3>
|
||||
<div class="manage add-to-type">
|
||||
<%--// these inline forms can't be here. should probably have some JavaScript in here to build up the forms and add the "remove" link.
|
||||
// get the antiforgery token from the edit type form and mark up the part in a semantic way so I can get some info from the DOM --%>
|
||||
<% using (Html.BeginFormAntiForgeryPost(Url.Action("RemovePart", new { area = "Contents" }), FormMethod.Post, new {@class = "inline link"})) { %>
|
||||
<%=Html.Hidden("name", Model.PartDefinition.Name, new { id = "" }) %>
|
||||
<button type="submit" title="<%:T("Remove") %>"><%:T("Remove") %></button>
|
||||
<% } %>
|
||||
</div>
|
||||
</fieldset>
|
@@ -0,0 +1,14 @@
|
||||
<%@ Control Language="C#" Inherits="Orchard.Mvc.ViewUserControl<ContentPartDefinition.Field>" %>
|
||||
<%@ Import Namespace="Orchard.ContentManagement.MetaData.Models" %>
|
||||
<fieldset>
|
||||
<h3><%:Model.FieldDefinition.Name %></h3>
|
||||
<div class="manage add-to-type">
|
||||
<%--// these inline forms can't be here. should probably have some JavaScript in here to build up the forms and add the "remove" link.
|
||||
// get the antiforgery token from the edit type form and mark up the part in a semantic way so I can get some info from the DOM --%>
|
||||
<%:Html.Link("[remove]", "#forshowonlyandnotintendedtowork!") %>
|
||||
<%-- <% using (Html.BeginFormAntiForgeryPost(Url.Action("RemovePart", new { area = "Contents" }), FormMethod.Post, new {@class = "inline link"})) { %>
|
||||
<%=Html.Hidden("name", Model.PartDefinition.Name, new { id = "" }) %>
|
||||
<button type="submit" title="<%:T("Remove") %>"><%:T("Remove") %></button>
|
||||
<% } %> --%>
|
||||
</div>
|
||||
</fieldset>
|
@@ -0,0 +1,10 @@
|
||||
<%@ Control Language="C#" Inherits="Orchard.Mvc.ViewUserControl<IEnumerable<EditPartFieldViewModel>>" %>
|
||||
<%@ Import Namespace="Orchard.Core.Contents.ViewModels" %><%
|
||||
if (Model.Any()) { %>
|
||||
<fieldset><%
|
||||
foreach (var field in Model) {
|
||||
var f = field; %>
|
||||
<%:Html.EditorFor(m => f, "FieldOnPart") %><%
|
||||
} %>
|
||||
</fieldset><%
|
||||
} %>
|
@@ -0,0 +1,21 @@
|
||||
<%@ Control Language="C#" Inherits="Orchard.Mvc.ViewUserControl<EditTypePartViewModel>" %>
|
||||
<%@ Import Namespace="Orchard.Core.Contents.ViewModels" %>
|
||||
<fieldset>
|
||||
<h3><%:Model.PartDefinition.Name %></h3>
|
||||
<div class="manage add-to-type">
|
||||
<%--// these inline forms can't be here. should probably have some JavaScript in here to build up the forms and add the "remove" link.
|
||||
// get the antiforgery token from the edit type form and mark up the part in a semantic way so I can get some info from the DOM --%>
|
||||
<%:Html.Link("[remove]", "#forshowonlyandnotintendedtowork") %>
|
||||
<%-- <% using (Html.BeginFormAntiForgeryPost(Url.Action("RemovePart", new { area = "Contents" }), FormMethod.Post, new {@class = "inline link"})) { %>
|
||||
<%:Html.Hidden("name", Model.PartDefinition.Name, new { id = "" }) %>
|
||||
<button type="submit" title="<%:T("Remove") %>"><%:T("Remove") %></button>
|
||||
<% } %> --%>
|
||||
</div>
|
||||
<%--
|
||||
what is this settings for?
|
||||
<%:Html.EditorFor(m => m.PartDefinition.Settings, "Settings") %>--%>
|
||||
<%:Html.EditorFor(m => m.Settings, "Settings", "") %>
|
||||
<%:Html.EditorFor(m => m.PartDefinition.Fields, "FieldsOnPart") %>
|
||||
<%:Html.Hidden("PartDefinition.Name", Model.PartDefinition.Name) %>
|
||||
<%:Html.Hidden("PartDefinition.Name", Model.PartDefinition.Name) %>
|
||||
</fieldset>
|
@@ -0,0 +1,12 @@
|
||||
<%@ Control Language="C#" Inherits="Orchard.Mvc.ViewUserControl<IEnumerable<EditTypePartViewModel>>" %>
|
||||
<%@ Import Namespace="Orchard.Core.Contents.ViewModels" %><%
|
||||
if (Model.Any()) { %>
|
||||
<fieldset><%
|
||||
var pi = 0;
|
||||
foreach (var part in Model) {
|
||||
var p = part;
|
||||
var htmlFieldName = string.Format("Parts[{0}]", pi++); %>
|
||||
<%:Html.EditorFor(m => p, "Part", htmlFieldName) %><%
|
||||
} %>
|
||||
</fieldset><%
|
||||
} %>
|
@@ -0,0 +1,14 @@
|
||||
<%@ Control Language="C#" Inherits="Orchard.Mvc.ViewUserControl<Orchard.ContentManagement.MetaData.Models.SettingsDictionary>" %><%
|
||||
if (Model.Any()) { %>
|
||||
<fieldset><%
|
||||
var si = 0;
|
||||
foreach (var setting in Model) {
|
||||
var s = setting;
|
||||
var htmlFieldName = string.Format("Settings[{0}]", si++); %>
|
||||
<%--// doesn't gen a similarly sanitized id as the other inputs...--%>
|
||||
<label for="<%:ViewData.TemplateInfo.GetFullHtmlFieldId(htmlFieldName + ".Value") %>"><%:s.Key %></label>
|
||||
<%:Html.Hidden(htmlFieldName + ".Key", s.Key) %>
|
||||
<%:Html.TextBox(htmlFieldName + ".Value", s.Value)%><%
|
||||
} %>
|
||||
</fieldset><%
|
||||
} %>
|
@@ -72,12 +72,12 @@
|
||||
<Compile Include="Common\ViewModels\ContainerEditorViewModel.cs" />
|
||||
<Compile Include="Common\ViewModels\TextContentFieldDisplayViewModel.cs" />
|
||||
<Compile Include="Common\ViewModels\TextContentFieldEditorViewModel.cs" />
|
||||
<Compile Include="Contents\ContentTypeDefinitionStub.cs" />
|
||||
<Compile Include="Contents\Controllers\ItemController.cs" />
|
||||
<Compile Include="Contents\Handlers\ContentsModuleHandler.cs" />
|
||||
<Compile Include="Contents\Permissions.cs" />
|
||||
<Compile Include="Contents\Services\ContentDefinitionService.cs" />
|
||||
<Compile Include="Contents\Services\IContentDefinitionService.cs" />
|
||||
<Compile Include="Contents\ViewModels\EditTypeViewModel.cs" />
|
||||
<Compile Include="Contents\ViewModels\CreateTypeViewModel.cs" />
|
||||
<Compile Include="Contents\ViewModels\ListContentsViewModel.cs" />
|
||||
<Compile Include="Contents\ViewModels\ListContentTypesViewModel.cs" />
|
||||
@@ -207,6 +207,8 @@
|
||||
<Content Include="Common\Views\EditorTemplates\Parts\Common.Container.ascx" />
|
||||
<Content Include="Common\Views\EditorTemplates\Parts\Common.TextContentField.ascx" />
|
||||
<Content Include="Contents\Module.txt" />
|
||||
<Content Include="Contents\Styles\admin.css" />
|
||||
<Content Include="Contents\Views\Admin\EditType.ascx" />
|
||||
<Content Include="Contents\Views\Admin\CreateType.ascx" />
|
||||
<Content Include="Contents\Views\Admin\Types.ascx" />
|
||||
<Content Include="Contents\Views\Admin\List.aspx" />
|
||||
@@ -215,6 +217,11 @@
|
||||
<Content Include="Contents\Views\Admin\Create.aspx" />
|
||||
<Content Include="Contents\Views\DisplayTemplates\ContentTypeDefinition.ascx" />
|
||||
<Content Include="Contents\Views\DisplayTemplates\Items\Contents.Item.ascx" />
|
||||
<Content Include="Contents\Views\EditorTemplates\Settings.ascx" />
|
||||
<Content Include="Contents\Views\EditorTemplates\FieldsOnPart.ascx" />
|
||||
<Content Include="Contents\Views\EditorTemplates\FieldOnPart.ascx" />
|
||||
<Content Include="Contents\Views\EditorTemplates\Parts.ascx" />
|
||||
<Content Include="Contents\Views\EditorTemplates\Part.ascx" />
|
||||
<Content Include="Contents\Views\EditorTemplates\Items\Contents.Item.ascx" />
|
||||
<Content Include="Contents\Views\Item\Preview.aspx" />
|
||||
<Content Include="Contents\Views\Item\Display.aspx" />
|
||||
|
@@ -13,16 +13,19 @@ namespace Orchard.Core.Settings.Metadata {
|
||||
public class ContentDefinitionManager : Component, IContentDefinitionManager {
|
||||
private readonly IRepository<ContentTypeDefinitionRecord> _typeDefinitionRepository;
|
||||
private readonly IRepository<ContentPartDefinitionRecord> _partDefinitionRepository;
|
||||
private readonly IMapper<XElement, IDictionary<string, string>> _settingsReader;
|
||||
private readonly IMapper<IDictionary<string, string>, XElement> _settingsWriter;
|
||||
private readonly IRepository<ContentFieldDefinitionRecord> _fieldDefinitionRepository;
|
||||
private readonly IMapper<XElement, SettingsDictionary> _settingsReader;
|
||||
private readonly IMapper<SettingsDictionary, XElement> _settingsWriter;
|
||||
|
||||
public ContentDefinitionManager(
|
||||
IRepository<ContentTypeDefinitionRecord> typeDefinitionRepository,
|
||||
IRepository<ContentPartDefinitionRecord> partDefinitionRepository,
|
||||
IMapper<XElement, IDictionary<string, string>> settingsReader,
|
||||
IMapper<IDictionary<string, string>, XElement> settingsWriter) {
|
||||
IRepository<ContentFieldDefinitionRecord> fieldDefinitionRepository,
|
||||
IMapper<XElement, SettingsDictionary> settingsReader,
|
||||
IMapper<SettingsDictionary, XElement> settingsWriter) {
|
||||
_typeDefinitionRepository = typeDefinitionRepository;
|
||||
_partDefinitionRepository = partDefinitionRepository;
|
||||
_fieldDefinitionRepository = fieldDefinitionRepository;
|
||||
_settingsReader = settingsReader;
|
||||
_settingsWriter = settingsWriter;
|
||||
}
|
||||
@@ -48,7 +51,7 @@ namespace Orchard.Core.Settings.Metadata {
|
||||
}
|
||||
|
||||
public void StorePartDefinition(ContentPartDefinition contentPartDefinition) {
|
||||
throw new NotImplementedException();
|
||||
Apply(contentPartDefinition, Acquire(contentPartDefinition));
|
||||
}
|
||||
|
||||
private ContentTypeDefinitionRecord Acquire(ContentTypeDefinition contentTypeDefinition) {
|
||||
@@ -69,6 +72,15 @@ namespace Orchard.Core.Settings.Metadata {
|
||||
return result;
|
||||
}
|
||||
|
||||
private ContentFieldDefinitionRecord Acquire(ContentFieldDefinition contentFieldDefinition) {
|
||||
var result = _fieldDefinitionRepository.Fetch(x => x.Name == contentFieldDefinition.Name).SingleOrDefault();
|
||||
if (result == null) {
|
||||
result = new ContentFieldDefinitionRecord { Name = contentFieldDefinition.Name };
|
||||
_fieldDefinitionRepository.Create(result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private void Apply(ContentTypeDefinition model, ContentTypeDefinitionRecord record) {
|
||||
record.Settings = _settingsWriter.Map(model.Settings).ToString();
|
||||
|
||||
@@ -95,7 +107,34 @@ namespace Orchard.Core.Settings.Metadata {
|
||||
record.Settings = Compose(_settingsWriter.Map(model.Settings));
|
||||
}
|
||||
|
||||
private void Apply(ContentPartDefinition model, ContentPartDefinitionRecord record) {
|
||||
record.Settings = _settingsWriter.Map(model.Settings).ToString();
|
||||
|
||||
var toRemove = record.ContentPartFieldDefinitionRecords
|
||||
.Where(fieldDefinitionRecord => !model.Fields.Any(field => fieldDefinitionRecord.ContentFieldDefinitionRecord.Name == field.FieldDefinition.Name))
|
||||
.ToList();
|
||||
|
||||
foreach (var remove in toRemove) {
|
||||
record.ContentPartFieldDefinitionRecords.Remove(remove);
|
||||
}
|
||||
|
||||
foreach (var field in model.Fields) {
|
||||
var fieldName = field.FieldDefinition.Name;
|
||||
var partFieldRecord = record.ContentPartFieldDefinitionRecords.SingleOrDefault(r => r.ContentFieldDefinitionRecord.Name == fieldName);
|
||||
if (partFieldRecord == null) {
|
||||
partFieldRecord = new ContentPartFieldDefinitionRecord {
|
||||
ContentFieldDefinitionRecord = Acquire(field.FieldDefinition),
|
||||
Name = field.Name
|
||||
};
|
||||
record.ContentPartFieldDefinitionRecords.Add(partFieldRecord);
|
||||
}
|
||||
Apply(field, partFieldRecord);
|
||||
}
|
||||
}
|
||||
|
||||
private void Apply(ContentPartDefinition.Field model, ContentPartFieldDefinitionRecord record) {
|
||||
record.Settings = Compose(_settingsWriter.Map(model.Settings));
|
||||
}
|
||||
|
||||
ContentTypeDefinition Build(ContentTypeDefinitionRecord source) {
|
||||
return new ContentTypeDefinition(
|
||||
|
@@ -1,8 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
using System.IO;
|
||||
using System.Web.Mvc;
|
||||
using System.Xml;
|
||||
using System.Xml.Linq;
|
||||
@@ -59,6 +55,11 @@ namespace Orchard.DevTools.Controllers {
|
||||
var typeName = XmlConvert.DecodeName(element.Name.LocalName);
|
||||
_contentDefinitionManager.AlterTypeDefinition(typeName, alteration => _contentDefinitionReader.Merge(typeElement, alteration));
|
||||
}
|
||||
foreach (var element in root.Elements("Parts").Elements()) {
|
||||
var partElement = element;
|
||||
var partName = XmlConvert.DecodeName(element.Name.LocalName);
|
||||
_contentDefinitionManager.AlterPartDefinition(partName, alteration => _contentDefinitionReader.Merge(partElement, alteration));
|
||||
}
|
||||
return RedirectToAction("Index");
|
||||
}
|
||||
}
|
||||
|
@@ -105,9 +105,8 @@
|
||||
<IISUrl>
|
||||
</IISUrl>
|
||||
<NTLMAuthentication>False</NTLMAuthentication>
|
||||
<UseCustomServer>False</UseCustomServer>
|
||||
<CustomServerUrl>
|
||||
</CustomServerUrl>
|
||||
<UseCustomServer>True</UseCustomServer>
|
||||
<CustomServerUrl>http://orchard.codeplex.com</CustomServerUrl>
|
||||
<SaveServerSettingsInUserFile>False</SaveServerSettingsInUserFile>
|
||||
</WebProjectProperties>
|
||||
</FlavorProperties>
|
||||
|
@@ -1,5 +1,4 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Linq;
|
||||
using Orchard.ContentManagement.MetaData.Models;
|
||||
|
||||
namespace Orchard.ContentManagement.Handlers {
|
||||
@@ -26,7 +25,7 @@ namespace Orchard.ContentManagement.Handlers {
|
||||
if (typePartDefinition == null) {
|
||||
typePartDefinition = new ContentTypeDefinition.Part(
|
||||
new ContentPartDefinition(partName),
|
||||
new Dictionary<string, string>());
|
||||
new SettingsDictionary());
|
||||
}
|
||||
|
||||
var part = new TPart {
|
||||
|
@@ -1,12 +1,13 @@
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Orchard.ContentManagement.MetaData.Models;
|
||||
|
||||
namespace Orchard.ContentManagement.MetaData.Builders {
|
||||
public class ContentPartDefinitionBuilder {
|
||||
private readonly string _name;
|
||||
private string _name;
|
||||
private readonly IList<ContentPartDefinition.Field> _fields;
|
||||
private readonly IDictionary<string, string> _settings;
|
||||
private readonly SettingsDictionary _settings;
|
||||
|
||||
public ContentPartDefinitionBuilder()
|
||||
: this(new ContentPartDefinition(null)) {
|
||||
@@ -15,12 +16,12 @@ namespace Orchard.ContentManagement.MetaData.Builders {
|
||||
public ContentPartDefinitionBuilder(ContentPartDefinition existing) {
|
||||
if (existing == null) {
|
||||
_fields = new List<ContentPartDefinition.Field>();
|
||||
_settings = new Dictionary<string, string>();
|
||||
_settings = new SettingsDictionary();
|
||||
}
|
||||
else {
|
||||
_name = existing.Name;
|
||||
_fields = existing.Fields.ToList();
|
||||
_settings = existing.Settings.ToDictionary(kv => kv.Key, kv => kv.Value);
|
||||
_settings = new SettingsDictionary(existing.Settings.ToDictionary(kv => kv.Key, kv => kv.Value));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,10 +29,83 @@ namespace Orchard.ContentManagement.MetaData.Builders {
|
||||
return new ContentPartDefinition(_name, _fields, _settings);
|
||||
}
|
||||
|
||||
public ContentPartDefinitionBuilder Named(string name) {
|
||||
_name = name;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ContentPartDefinitionBuilder RemoveField(string fieldName) {
|
||||
var existingField = _fields.SingleOrDefault(x => x.FieldDefinition.Name == fieldName);
|
||||
if (existingField != null) {
|
||||
_fields.Remove(existingField);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public ContentPartDefinitionBuilder WithSetting(string name, string value) {
|
||||
_settings[name] = value;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ContentPartDefinitionBuilder WithField(string fieldName) {
|
||||
return WithField(fieldName, configuration => { });
|
||||
}
|
||||
|
||||
public ContentPartDefinitionBuilder WithField(string fieldName, Action<FieldConfigurer> configuration) {
|
||||
var fieldDefinition = new ContentFieldDefinition(fieldName);
|
||||
var existingField = _fields.SingleOrDefault(x => x.FieldDefinition.Name == fieldDefinition.Name);
|
||||
if (existingField != null) {
|
||||
_fields.Remove(existingField);
|
||||
}
|
||||
else {
|
||||
existingField = new ContentPartDefinition.Field(fieldDefinition, fieldName, new SettingsDictionary());
|
||||
}
|
||||
var configurer = new FieldConfigurerImpl(existingField);
|
||||
configuration(configurer);
|
||||
_fields.Add(configurer.Build());
|
||||
return this;
|
||||
}
|
||||
|
||||
public abstract class FieldConfigurer {
|
||||
protected readonly SettingsDictionary _settings;
|
||||
|
||||
protected FieldConfigurer(ContentPartDefinition.Field field) {
|
||||
_settings = new SettingsDictionary(field.Settings.ToDictionary(kv => kv.Key, kv => kv.Value));
|
||||
}
|
||||
|
||||
public FieldConfigurer WithSetting(string name, string value) {
|
||||
_settings[name] = value;
|
||||
return this;
|
||||
}
|
||||
|
||||
public abstract FieldConfigurer OfType(ContentFieldDefinition fieldDefinition);
|
||||
public abstract FieldConfigurer OfType(string fieldType);
|
||||
}
|
||||
|
||||
class FieldConfigurerImpl : FieldConfigurer {
|
||||
private ContentFieldDefinition _fieldDefinition;
|
||||
private string _fieldName;
|
||||
|
||||
public FieldConfigurerImpl(ContentPartDefinition.Field field)
|
||||
: base(field) {
|
||||
_fieldDefinition = field.FieldDefinition;
|
||||
_fieldName = field.Name;
|
||||
}
|
||||
|
||||
public ContentPartDefinition.Field Build() {
|
||||
return new ContentPartDefinition.Field(_fieldDefinition, _fieldName, _settings);
|
||||
}
|
||||
|
||||
public override FieldConfigurer OfType(ContentFieldDefinition fieldDefinition) {
|
||||
_fieldDefinition = fieldDefinition;
|
||||
return this;
|
||||
}
|
||||
|
||||
public override FieldConfigurer OfType(string fieldType) {
|
||||
_fieldDefinition = new ContentFieldDefinition(fieldType);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@@ -8,7 +8,7 @@ namespace Orchard.ContentManagement.MetaData.Builders {
|
||||
private string _name;
|
||||
private string _displayName;
|
||||
private readonly IList<ContentTypeDefinition.Part> _parts;
|
||||
private readonly IDictionary<string, string> _settings;
|
||||
private readonly SettingsDictionary _settings;
|
||||
|
||||
public ContentTypeDefinitionBuilder()
|
||||
: this(new ContentTypeDefinition(null)) {
|
||||
@@ -17,13 +17,13 @@ namespace Orchard.ContentManagement.MetaData.Builders {
|
||||
public ContentTypeDefinitionBuilder(ContentTypeDefinition existing) {
|
||||
if (existing == null) {
|
||||
_parts = new List<ContentTypeDefinition.Part>();
|
||||
_settings = new Dictionary<string, string>();
|
||||
_settings = new SettingsDictionary();
|
||||
}
|
||||
else {
|
||||
_name = existing.Name;
|
||||
_displayName = existing.DisplayName;
|
||||
_parts = existing.Parts.ToList();
|
||||
_settings = existing.Settings.ToDictionary(kv => kv.Key, kv => kv.Value);
|
||||
_settings = new SettingsDictionary(existing.Settings.ToDictionary(kv => kv.Key, kv => kv.Value));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,7 +68,7 @@ namespace Orchard.ContentManagement.MetaData.Builders {
|
||||
_parts.Remove(existingPart);
|
||||
}
|
||||
else {
|
||||
existingPart = new ContentTypeDefinition.Part(partDefinition, new Dictionary<string, string>());
|
||||
existingPart = new ContentTypeDefinition.Part(partDefinition, new SettingsDictionary());
|
||||
}
|
||||
var configurer = new PartConfigurerImpl(existingPart);
|
||||
configuration(configurer);
|
||||
@@ -77,10 +77,10 @@ namespace Orchard.ContentManagement.MetaData.Builders {
|
||||
}
|
||||
|
||||
public abstract class PartConfigurer {
|
||||
protected readonly IDictionary<string, string> _settings;
|
||||
protected readonly SettingsDictionary _settings;
|
||||
|
||||
protected PartConfigurer(ContentTypeDefinition.Part part) {
|
||||
_settings = part.Settings.ToDictionary(kv => kv.Key, kv => kv.Value);
|
||||
_settings = new SettingsDictionary(part.Settings.ToDictionary(kv => kv.Key, kv => kv.Value));
|
||||
}
|
||||
|
||||
public PartConfigurer WithSetting(string name, string value) {
|
||||
|
@@ -5,6 +5,7 @@ using Orchard.ContentManagement.MetaData.Models;
|
||||
namespace Orchard.ContentManagement.MetaData {
|
||||
public interface IContentDefinitionReader : IDependency {
|
||||
void Merge(XElement source, ContentTypeDefinitionBuilder builder);
|
||||
void Merge(XElement source, ContentPartDefinitionBuilder builder);
|
||||
}
|
||||
|
||||
public static class ContentDefinitionReaderExtensions {
|
||||
|
@@ -4,7 +4,7 @@ using Orchard.Utility.Extensions;
|
||||
|
||||
namespace Orchard.ContentManagement.MetaData.Models {
|
||||
public class ContentPartDefinition {
|
||||
public ContentPartDefinition(string name, IEnumerable<Field> fields, IDictionary<string, string> settings) {
|
||||
public ContentPartDefinition(string name, IEnumerable<Field> fields, SettingsDictionary settings) {
|
||||
Name = name;
|
||||
Fields = fields.ToReadOnlyCollection();
|
||||
Settings = settings;
|
||||
@@ -13,15 +13,15 @@ namespace Orchard.ContentManagement.MetaData.Models {
|
||||
public ContentPartDefinition(string name) {
|
||||
Name = name;
|
||||
Fields = Enumerable.Empty<Field>();
|
||||
Settings = new Dictionary<string, string>();
|
||||
Settings = new SettingsDictionary();
|
||||
}
|
||||
|
||||
public string Name { get; private set; }
|
||||
public IEnumerable<Field> Fields { get; private set; }
|
||||
public IDictionary<string, string> Settings { get; private set; }
|
||||
public SettingsDictionary Settings { get; private set; }
|
||||
|
||||
public class Field {
|
||||
public Field(ContentFieldDefinition contentFieldDefinition, string name, IDictionary<string, string> settings) {
|
||||
public Field(ContentFieldDefinition contentFieldDefinition, string name, SettingsDictionary settings) {
|
||||
FieldDefinition = contentFieldDefinition;
|
||||
Name = name;
|
||||
Settings = settings;
|
||||
@@ -29,7 +29,7 @@ namespace Orchard.ContentManagement.MetaData.Models {
|
||||
|
||||
public string Name { get; private set; }
|
||||
public ContentFieldDefinition FieldDefinition { get; private set; }
|
||||
public IDictionary<string, string> Settings { get; private set; }
|
||||
public SettingsDictionary Settings { get; private set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,9 +1,10 @@
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Linq;
|
||||
|
||||
namespace Orchard.ContentManagement.MetaData.Models {
|
||||
public class ContentTypeDefinition {
|
||||
public ContentTypeDefinition(string name, string displayName, IEnumerable<Part> parts, IDictionary<string, string> settings) {
|
||||
public ContentTypeDefinition(string name, string displayName, IEnumerable<Part> parts, SettingsDictionary settings) {
|
||||
Name = name;
|
||||
DisplayName = displayName;
|
||||
Parts = parts;
|
||||
@@ -13,22 +14,29 @@ namespace Orchard.ContentManagement.MetaData.Models {
|
||||
public ContentTypeDefinition(string name) {
|
||||
Name = name;
|
||||
Parts = Enumerable.Empty<Part>();
|
||||
Settings = new Dictionary<string, string>();
|
||||
Settings = new SettingsDictionary();
|
||||
}
|
||||
|
||||
[StringLength(128)]
|
||||
public string Name { get; private set; }
|
||||
[Required, StringLength(1024)]
|
||||
public string DisplayName { get; set; }
|
||||
public IEnumerable<Part> Parts { get; private set; }
|
||||
public IDictionary<string, string> Settings { get; private set; }
|
||||
public SettingsDictionary Settings { get; private set; }
|
||||
|
||||
public class Part {
|
||||
public Part(ContentPartDefinition contentPartDefinition, IDictionary<string, string> settings) {
|
||||
|
||||
public Part(ContentPartDefinition contentPartDefinition, SettingsDictionary settings) {
|
||||
PartDefinition = contentPartDefinition;
|
||||
Settings = settings;
|
||||
}
|
||||
|
||||
public Part() {
|
||||
Settings = new SettingsDictionary();
|
||||
}
|
||||
|
||||
public ContentPartDefinition PartDefinition { get; private set; }
|
||||
public IDictionary<string, string> Settings { get; private set; }
|
||||
public SettingsDictionary Settings { get; private set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,24 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Web.Mvc;
|
||||
|
||||
namespace Orchard.ContentManagement.MetaData.Models {
|
||||
public class SettingsDictionary : Dictionary<string, string> {
|
||||
public SettingsDictionary() {}
|
||||
public SettingsDictionary(IDictionary<string, string> dictionary) : base(dictionary) {}
|
||||
|
||||
public T GetModel<T>() {
|
||||
return GetModel<T>(null);
|
||||
}
|
||||
|
||||
public T GetModel<T>(string key) {
|
||||
var binder = new DefaultModelBinder();
|
||||
var controllerContext = new ControllerContext();
|
||||
var context = new ModelBindingContext {
|
||||
ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(null, typeof (T)),
|
||||
ModelName = key,
|
||||
ValueProvider = new DictionaryValueProvider<string>(this, null)
|
||||
};
|
||||
return (T) binder.BindModel(controllerContext, context);
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,14 +1,13 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Xml;
|
||||
using System.Xml;
|
||||
using System.Xml.Linq;
|
||||
using Orchard.ContentManagement.MetaData.Builders;
|
||||
using Orchard.ContentManagement.MetaData.Models;
|
||||
|
||||
namespace Orchard.ContentManagement.MetaData.Services {
|
||||
public class ContentDefinitionReader : IContentDefinitionReader {
|
||||
private readonly IMapper<XElement, IDictionary<string, string>> _settingsReader;
|
||||
private readonly IMapper<XElement, SettingsDictionary> _settingsReader;
|
||||
|
||||
public ContentDefinitionReader(IMapper<XElement, IDictionary<string, string>> settingsReader) {
|
||||
public ContentDefinitionReader(IMapper<XElement, SettingsDictionary> settingsReader) {
|
||||
_settingsReader = settingsReader;
|
||||
}
|
||||
|
||||
@@ -28,5 +27,25 @@ namespace Orchard.ContentManagement.MetaData.Services {
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public void Merge(XElement source, ContentPartDefinitionBuilder builder) {
|
||||
builder.Named(XmlConvert.DecodeName(source.Name.LocalName));
|
||||
foreach (var setting in _settingsReader.Map(source)) {
|
||||
builder.WithSetting(setting.Key, setting.Value);
|
||||
}
|
||||
|
||||
foreach (var iter in source.Elements()) {
|
||||
var fieldElement = iter;
|
||||
string[] fieldParameters = fieldElement.Name.LocalName.Split('.');
|
||||
builder.WithField(
|
||||
XmlConvert.DecodeName(fieldParameters[0]),
|
||||
fieldBuilder => {
|
||||
foreach (var setting in _settingsReader.Map(fieldElement)) {
|
||||
fieldBuilder.WithSetting(setting.Key, setting.Value);
|
||||
}
|
||||
fieldBuilder.OfType(fieldParameters[1]);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,14 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Xml;
|
||||
using System.Xml;
|
||||
using System.Xml.Linq;
|
||||
using Orchard.ContentManagement.MetaData.Models;
|
||||
|
||||
namespace Orchard.ContentManagement.MetaData.Services {
|
||||
public class ContentDefinitionWriter : IContentDefinitionWriter {
|
||||
private readonly IMapper<IDictionary<string, string>, XElement> _settingsWriter;
|
||||
private readonly IMapper<SettingsDictionary, XElement> _settingsWriter;
|
||||
|
||||
public ContentDefinitionWriter(IMapper<IDictionary<string, string>, XElement> settingsWriter) {
|
||||
public ContentDefinitionWriter(IMapper<SettingsDictionary, XElement> settingsWriter) {
|
||||
_settingsWriter = settingsWriter;
|
||||
}
|
||||
|
||||
@@ -24,14 +22,14 @@ namespace Orchard.ContentManagement.MetaData.Services {
|
||||
public XElement Export(ContentPartDefinition partDefinition) {
|
||||
var partElement = NewElement(partDefinition.Name, partDefinition.Settings);
|
||||
foreach(var partField in partDefinition.Fields) {
|
||||
var partFieldElement = NewElement(partField.Name, partField.Settings);
|
||||
partFieldElement.SetAttributeValue("FieldType", partField.FieldDefinition.Name);
|
||||
var attributeName = partField.Name + "." + partField.FieldDefinition.Name;
|
||||
var partFieldElement = NewElement(attributeName, partField.Settings);
|
||||
partElement.Add(partFieldElement);
|
||||
}
|
||||
return partElement;
|
||||
}
|
||||
|
||||
private XElement NewElement(string name, IDictionary<string, string> settings) {
|
||||
private XElement NewElement(string name, SettingsDictionary settings) {
|
||||
var element = new XElement(XmlConvert.EncodeLocalName(name));
|
||||
foreach(var settingAttribute in _settingsWriter.Map(settings).Attributes()) {
|
||||
element.Add(settingAttribute);
|
||||
|
@@ -1,21 +1,21 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Linq;
|
||||
using System.Xml;
|
||||
using System.Xml.Linq;
|
||||
using Orchard.ContentManagement.MetaData.Models;
|
||||
|
||||
namespace Orchard.ContentManagement.MetaData.Services {
|
||||
public class SettingsFormatter :
|
||||
IMapper<XElement, IDictionary<string, string>>,
|
||||
IMapper<IDictionary<string, string>, XElement> {
|
||||
IMapper<XElement, SettingsDictionary>,
|
||||
IMapper<SettingsDictionary, XElement> {
|
||||
|
||||
public IDictionary<string, string> Map(XElement source) {
|
||||
public SettingsDictionary Map(XElement source) {
|
||||
if (source == null)
|
||||
return new Dictionary<string, string>();
|
||||
return new SettingsDictionary();
|
||||
|
||||
return source.Attributes().ToDictionary(attr => XmlConvert.DecodeName(attr.Name.LocalName), attr => attr.Value);
|
||||
return new SettingsDictionary(source.Attributes().ToDictionary(attr => XmlConvert.DecodeName(attr.Name.LocalName), attr => attr.Value));
|
||||
}
|
||||
|
||||
public XElement Map(IDictionary<string, string> source) {
|
||||
public XElement Map(SettingsDictionary source) {
|
||||
if (source == null)
|
||||
return new XElement("settings");
|
||||
|
||||
|
31
src/Orchard/DataMigration/Commands/DataMigrationCommands.cs
Normal file
31
src/Orchard/DataMigration/Commands/DataMigrationCommands.cs
Normal file
@@ -0,0 +1,31 @@
|
||||
using System;
|
||||
using Orchard.Commands;
|
||||
|
||||
namespace Orchard.DataMigration.Commands {
|
||||
public class DataMigrationCommands : DefaultOrchardCommandHandler {
|
||||
private readonly IDataMigrationManager _dataMigrationManager;
|
||||
|
||||
public DataMigrationCommands(
|
||||
IDataMigrationManager dataMigrationManager) {
|
||||
_dataMigrationManager = dataMigrationManager;
|
||||
}
|
||||
|
||||
[OrchardSwitch]
|
||||
public string Feature { get; set; }
|
||||
|
||||
[CommandName("upgrade database")]
|
||||
[CommandHelp("upgrade database /Feature:<feature> \r\n\t" + "Upgrades or create the database tables for the named <feature>")]
|
||||
[OrchardSwitches("Feature")]
|
||||
public string UpgradeDatabase() {
|
||||
try {
|
||||
_dataMigrationManager.Upgrade(Feature);
|
||||
}
|
||||
catch ( Exception ex ) {
|
||||
Context.Output.WriteLine(T("An error occured while upgrading the database: " + ex.Message));
|
||||
return "Upgrade terminated.";
|
||||
}
|
||||
|
||||
return "Database upgraded";
|
||||
}
|
||||
}
|
||||
}
|
5
src/Orchard/DataMigration/DataMigration.cs
Normal file
5
src/Orchard/DataMigration/DataMigration.cs
Normal file
@@ -0,0 +1,5 @@
|
||||
namespace Orchard.DataMigration {
|
||||
public abstract class DataMigration : IDataMigration {
|
||||
public abstract string Feature { get; }
|
||||
}
|
||||
}
|
124
src/Orchard/DataMigration/DataMigrationManager.cs
Normal file
124
src/Orchard/DataMigration/DataMigrationManager.cs
Normal file
@@ -0,0 +1,124 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text.RegularExpressions;
|
||||
using Orchard.Data;
|
||||
using Orchard.Environment.Extensions;
|
||||
using Orchard.Environment.Extensions.Models;
|
||||
using Orchard.Logging;
|
||||
|
||||
namespace Orchard.DataMigration {
|
||||
/// <summary>
|
||||
/// Reponsible for maintaining the knowledge of data migration in a per tenant table
|
||||
/// </summary>
|
||||
public class DataMigrationManager : IDataMigrationManager {
|
||||
private readonly IEnumerable<IDataMigration> _dataMigrations;
|
||||
private readonly IRepository<DataMigrationRecord> _dataMigrationRepository;
|
||||
private readonly IDataMigrationGenerator _dataMigrationGenerator;
|
||||
private readonly IExtensionManager _extensionManager;
|
||||
|
||||
public DataMigrationManager(
|
||||
IEnumerable<IDataMigration> dataMigrations,
|
||||
IRepository<DataMigrationRecord> dataMigrationRepository,
|
||||
IDataMigrationGenerator dataMigrationGenerator,
|
||||
IExtensionManager extensionManager) {
|
||||
_dataMigrations = dataMigrations;
|
||||
_dataMigrationRepository = dataMigrationRepository;
|
||||
_dataMigrationGenerator = dataMigrationGenerator;
|
||||
_extensionManager = extensionManager;
|
||||
Logger = NullLogger.Instance;
|
||||
}
|
||||
|
||||
public ILogger Logger { get; set; }
|
||||
|
||||
public void Upgrade(string feature) {
|
||||
|
||||
// proceed with dependent features first, whatever the module it's in
|
||||
var dependencies = _extensionManager
|
||||
.AvailableExtensions()
|
||||
.SelectMany(e => e.Features)
|
||||
.Where(f => String.Equals(f.Name, feature, StringComparison.OrdinalIgnoreCase))
|
||||
.Where(f => f.Dependencies != null)
|
||||
.SelectMany( f => f.Dependencies )
|
||||
.ToList();
|
||||
|
||||
foreach(var dependency in dependencies) {
|
||||
Upgrade(dependency);
|
||||
}
|
||||
|
||||
var migrations = GetDataMigrations(feature);
|
||||
|
||||
// apply update methods to each migration class for the module
|
||||
foreach ( var migration in migrations ) {
|
||||
// copy the objet for the Linq query
|
||||
var tempMigration = migration;
|
||||
|
||||
// get current version for this migration
|
||||
var dataMigrationRecord = _dataMigrationRepository.Table
|
||||
.Where(dm => dm.DataMigrationClass == tempMigration.GetType().FullName)
|
||||
.FirstOrDefault();
|
||||
|
||||
var updateMethodNameRegex = new Regex(@"^UpdateFrom(?<version>\d+)$", RegexOptions.Compiled);
|
||||
var current = 0;
|
||||
if(dataMigrationRecord != null) {
|
||||
current = dataMigrationRecord.Current;
|
||||
}
|
||||
|
||||
// do we need to call Create() ?
|
||||
if(current == 0) {
|
||||
// try to resolve a Create method
|
||||
|
||||
var createMethod = migration.GetType().GetMethod("Create", BindingFlags.Public | BindingFlags.Instance);
|
||||
if(createMethod != null && createMethod.ReturnType == typeof(int)) {
|
||||
current = (int)createMethod.Invoke(migration, new object[0]);
|
||||
}
|
||||
else {
|
||||
var commands = _dataMigrationGenerator.CreateCommands();
|
||||
/// TODO: Execute commands and define current version number
|
||||
}
|
||||
}
|
||||
|
||||
// update methods might also be called after Create()
|
||||
var lookupTable = new Dictionary<int, MethodInfo>();
|
||||
// construct a lookup table with all managed initial versions
|
||||
foreach(var methodInfo in migration.GetType().GetMethods(BindingFlags.Public | BindingFlags.Instance)) {
|
||||
var match = updateMethodNameRegex.Match(methodInfo.Name);
|
||||
if(match.Success) {
|
||||
lookupTable.Add(int.Parse(match.Groups["version"].Value), methodInfo);
|
||||
}
|
||||
}
|
||||
|
||||
while(lookupTable.ContainsKey(current)) {
|
||||
try {
|
||||
Logger.Information("Applying migration for {0} from version {1}", feature, current);
|
||||
current = (int)lookupTable[current].Invoke(migration, new object[0]);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
Logger.Error(ex, "An unexpected error orccured while applying migration on {0} from version {1}", feature, current);
|
||||
}
|
||||
}
|
||||
|
||||
// if current is 0, it means no upgrade/create method was found or succeeded
|
||||
if ( current != 0 ) {
|
||||
if (dataMigrationRecord == null) {
|
||||
_dataMigrationRepository.Create(new DataMigrationRecord {Current = current, DataMigrationClass = migration.GetType().FullName});
|
||||
}
|
||||
else {
|
||||
dataMigrationRecord.Current = current;
|
||||
_dataMigrationRepository.Update(dataMigrationRecord);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns all the available IDataMigration instances for a specific module
|
||||
/// </summary>
|
||||
public IEnumerable<IDataMigration> GetDataMigrations(string feature) {
|
||||
return _dataMigrations
|
||||
.Where(dm => String.Equals(dm.Feature, feature, StringComparison.OrdinalIgnoreCase))
|
||||
.ToList();
|
||||
}
|
||||
}
|
||||
}
|
7
src/Orchard/DataMigration/DataMigrationRecord.cs
Normal file
7
src/Orchard/DataMigration/DataMigrationRecord.cs
Normal file
@@ -0,0 +1,7 @@
|
||||
namespace Orchard.DataMigration {
|
||||
public class DataMigrationRecord {
|
||||
public virtual int Id { get; set; }
|
||||
public virtual string DataMigrationClass { get; set; }
|
||||
public virtual int Current { get; set; }
|
||||
}
|
||||
}
|
11
src/Orchard/DataMigration/DefaultDataMigrationGenerator.cs
Normal file
11
src/Orchard/DataMigration/DefaultDataMigrationGenerator.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Orchard.DataMigration.Commands;
|
||||
|
||||
namespace Orchard.DataMigration {
|
||||
public class DefaultDataMigrationGenerator : IDataMigrationGenerator {
|
||||
public IEnumerable<IDataMigrationCommand> CreateCommands() {
|
||||
return Enumerable.Empty<IDataMigrationCommand>();
|
||||
}
|
||||
}
|
||||
}
|
5
src/Orchard/DataMigration/IDataMigration.cs
Normal file
5
src/Orchard/DataMigration/IDataMigration.cs
Normal file
@@ -0,0 +1,5 @@
|
||||
namespace Orchard.DataMigration {
|
||||
public interface IDataMigration : IDependency {
|
||||
string Feature { get; }
|
||||
}
|
||||
}
|
4
src/Orchard/DataMigration/IDataMigrationCommand.cs
Normal file
4
src/Orchard/DataMigration/IDataMigrationCommand.cs
Normal file
@@ -0,0 +1,4 @@
|
||||
namespace Orchard.DataMigration {
|
||||
public interface IDataMigrationCommand {
|
||||
}
|
||||
}
|
9
src/Orchard/DataMigration/IDataMigrationGenerator.cs
Normal file
9
src/Orchard/DataMigration/IDataMigrationGenerator.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
using System.Collections.Generic;
|
||||
using Orchard.DataMigration.Commands;
|
||||
|
||||
namespace Orchard.DataMigration {
|
||||
// Builds and runs the representative migration create calls
|
||||
public interface IDataMigrationGenerator : IDependency {
|
||||
IEnumerable<IDataMigrationCommand> CreateCommands();
|
||||
}
|
||||
}
|
5
src/Orchard/DataMigration/IDataMigrationManager.cs
Normal file
5
src/Orchard/DataMigration/IDataMigrationManager.cs
Normal file
@@ -0,0 +1,5 @@
|
||||
namespace Orchard.DataMigration {
|
||||
public interface IDataMigrationManager : IDependency {
|
||||
void Upgrade(string feature);
|
||||
}
|
||||
}
|
@@ -305,6 +305,7 @@
|
||||
<Compile Include="ContentManagement\MetaData\ContentPartInfo.cs">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Include="ContentManagement\MetaData\Models\SettingsDictionary.cs" />
|
||||
<Compile Include="ContentManagement\MetaData\Services\ContentDefinitionWriter.cs" />
|
||||
<Compile Include="ContentManagement\MetaData\IContentDefinitionManager.cs" />
|
||||
<Compile Include="ContentManagement\MetaData\IContentDefinitionReader.cs" />
|
||||
@@ -348,6 +349,15 @@
|
||||
<Compile Include="ContentManagement\ViewModels\TemplateViewModel.cs">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Include="DataMigration\Commands\DataMigrationCommands.cs" />
|
||||
<Compile Include="DataMigration\IDataMigrationCommand.cs" />
|
||||
<Compile Include="DataMigration\DefaultDataMigrationGenerator.cs" />
|
||||
<Compile Include="DataMigration\IDataMigrationGenerator.cs" />
|
||||
<Compile Include="DataMigration\DataMigration.cs" />
|
||||
<Compile Include="DataMigration\DataMigrationManager.cs" />
|
||||
<Compile Include="DataMigration\DataMigrationRecord.cs" />
|
||||
<Compile Include="DataMigration\IDataMigration.cs" />
|
||||
<Compile Include="DataMigration\IDataMigrationManager.cs" />
|
||||
<Compile Include="Data\SessionLocator.cs" />
|
||||
<Compile Include="Data\IRepository.cs" />
|
||||
<Compile Include="Data\ISessionLocator.cs" />
|
||||
|
Reference in New Issue
Block a user