mirror of
https://github.com/OrchardCMS/Orchard.git
synced 2025-10-15 19:54:57 +08:00
Merge remote-tracking branch 'upstream/dev' into dev
This commit is contained in:
@@ -24,6 +24,7 @@ using Orchard.Packaging.Models;
|
||||
using Orchard.Packaging.Services;
|
||||
using Orchard.Recipes.Models;
|
||||
using Orchard.Recipes.Providers.Executors;
|
||||
using Orchard.Recipes.Services;
|
||||
using Orchard.Tests.Environment.Extensions;
|
||||
using Orchard.Tests.Environment.Features;
|
||||
using Orchard.Tests.Stubs;
|
||||
@@ -53,6 +54,7 @@ namespace Orchard.Tests.Modules.Recipes.RecipeHandlers {
|
||||
_packagesInRepository = new StubPackagingSourceManager();
|
||||
_packageManager = new StubPackageManager();
|
||||
builder.RegisterInstance(_folders).As<IExtensionFolders>();
|
||||
builder.RegisterType<RecipeExecutionLogger>().AsSelf();
|
||||
builder.RegisterType<ExtensionManager>().As<IExtensionManager>();
|
||||
builder.RegisterType<FeatureManager>().As<IFeatureManager>();
|
||||
builder.RegisterType<StubCacheManager>().As<ICacheManager>();
|
||||
|
@@ -4,6 +4,7 @@ using NUnit.Framework;
|
||||
using Orchard.Recipes.Models;
|
||||
using Orchard.Recipes.Providers.RecipeHandlers;
|
||||
using Orchard.Recipes.Services;
|
||||
using Orchard.Tests.Stubs;
|
||||
|
||||
namespace Orchard.Tests.Modules.Recipes.RecipeHandlers {
|
||||
[TestFixture]
|
||||
@@ -13,6 +14,7 @@ namespace Orchard.Tests.Modules.Recipes.RecipeHandlers {
|
||||
[SetUp]
|
||||
public void Init() {
|
||||
var builder = new ContainerBuilder();
|
||||
builder.RegisterType<RecipeExecutionLogger>().AsSelf();
|
||||
builder.RegisterType<StubRecipeExecutionStep>().As<IRecipeExecutionStep>().AsSelf().SingleInstance();
|
||||
builder.RegisterType<RecipeExecutionStepHandler>().SingleInstance();
|
||||
|
||||
@@ -37,6 +39,11 @@ namespace Orchard.Tests.Modules.Recipes.RecipeHandlers {
|
||||
}
|
||||
|
||||
public class StubRecipeExecutionStep : RecipeExecutionStep {
|
||||
|
||||
public StubRecipeExecutionStep(
|
||||
RecipeExecutionLogger logger) : base(logger) {
|
||||
}
|
||||
|
||||
public override string Name {
|
||||
get { return "FakeRecipeStep"; }
|
||||
}
|
||||
|
@@ -22,6 +22,7 @@ using Orchard.FileSystems.VirtualPath;
|
||||
using Orchard.Packaging.GalleryServer;
|
||||
using Orchard.Packaging.Services;
|
||||
using Orchard.Recipes.Models;
|
||||
using Orchard.Recipes.Services;
|
||||
using Orchard.Tests.DisplayManagement.Descriptors;
|
||||
using Orchard.Tests.Environment.Extensions;
|
||||
using Orchard.Tests.Environment.Features;
|
||||
@@ -56,6 +57,7 @@ namespace Orchard.Tests.Modules.Recipes.RecipeHandlers {
|
||||
_packagesInRepository = new ModuleStepTest.StubPackagingSourceManager();
|
||||
_packageManager = new ModuleStepTest.StubPackageManager();
|
||||
builder.RegisterInstance(_folders).As<IExtensionFolders>();
|
||||
builder.RegisterType<RecipeExecutionLogger>().AsSelf();
|
||||
builder.RegisterType<ExtensionManager>().As<IExtensionManager>();
|
||||
builder.RegisterType<FeatureManager>().As<IFeatureManager>();
|
||||
builder.RegisterType<StubCacheManager>().As<ICacheManager>();
|
||||
|
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.Web;
|
||||
using System.Web.Mvc;
|
||||
using System.Web.Routing;
|
||||
@@ -7,25 +8,30 @@ using Autofac;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using Orchard.Caching;
|
||||
using Orchard.ContentManagement;
|
||||
using Orchard.ContentManagement.Handlers;
|
||||
using Orchard.ContentManagement.MetaData;
|
||||
using Orchard.ContentManagement.MetaData.Services;
|
||||
using Orchard.ContentManagement.Records;
|
||||
using Orchard.Core.Settings.Handlers;
|
||||
using Orchard.Core.Settings.Metadata;
|
||||
using Orchard.Data;
|
||||
using Orchard.Core.Settings.Models;
|
||||
using Orchard.Core.Settings.Services;
|
||||
using Orchard.DisplayManagement;
|
||||
using Orchard.DisplayManagement.Descriptors;
|
||||
using Orchard.DisplayManagement.Implementation;
|
||||
using Orchard.Environment;
|
||||
using Orchard.ContentManagement;
|
||||
using Orchard.ContentManagement.Handlers;
|
||||
using Orchard.ContentManagement.Records;
|
||||
using Orchard.Environment.Configuration;
|
||||
using Orchard.Environment.Extensions;
|
||||
using Orchard.Localization;
|
||||
using Orchard.Messaging.Events;
|
||||
using Orchard.Messaging.Services;
|
||||
using Orchard.Mvc;
|
||||
using Orchard.Security;
|
||||
using Orchard.Security.Permissions;
|
||||
using Orchard.Security.Providers;
|
||||
using Orchard.Tests.ContentManagement;
|
||||
using Orchard.Settings;
|
||||
using Orchard.Tests.Messaging;
|
||||
using Orchard.Tests.Modules.Stubs;
|
||||
using Orchard.Tests.Stubs;
|
||||
using Orchard.UI.Notify;
|
||||
using Orchard.Users.Controllers;
|
||||
@@ -33,15 +39,6 @@ using Orchard.Users.Events;
|
||||
using Orchard.Users.Handlers;
|
||||
using Orchard.Users.Models;
|
||||
using Orchard.Users.Services;
|
||||
using Orchard.Settings;
|
||||
using Orchard.Core.Settings.Services;
|
||||
using Orchard.Tests.Messaging;
|
||||
using Orchard.Core.Settings.Models;
|
||||
using Orchard.Core.Settings.Handlers;
|
||||
using System.Collections.Specialized;
|
||||
using Orchard.Mvc;
|
||||
using Orchard.Tests.Modules.Stubs;
|
||||
using Orchard.Environment.Configuration;
|
||||
|
||||
namespace Orchard.Tests.Modules.Users.Controllers {
|
||||
[TestFixture]
|
||||
@@ -74,7 +71,6 @@ namespace Orchard.Tests.Modules.Users.Controllers {
|
||||
builder.RegisterType<UserPartHandler>().As<IContentHandler>();
|
||||
builder.RegisterType<OrchardServices>().As<IOrchardServices>();
|
||||
|
||||
builder.RegisterInstance(new TestTransactionManager(_session)).As<ITransactionManager>();
|
||||
builder.RegisterInstance(new Work<IEnumerable<IShapeTableEventHandler>>(resolve => _container.Resolve<IEnumerable<IShapeTableEventHandler>>())).AsSelf();
|
||||
builder.RegisterType<DefaultShapeTableManager>().As<IShapeTableManager>();
|
||||
builder.RegisterType<DefaultShapeFactory>().As<IShapeFactory>();
|
||||
|
@@ -30,6 +30,7 @@ using Orchard.UI.PageClass;
|
||||
using Orchard.Users.Handlers;
|
||||
using Orchard.Users.Models;
|
||||
using Orchard.Users.Services;
|
||||
using Orchard.Tests.ContentManagement;
|
||||
using Orchard.Services;
|
||||
|
||||
namespace Orchard.Tests.Modules.Users.Services {
|
||||
@@ -41,19 +42,6 @@ namespace Orchard.Tests.Modules.Users.Services {
|
||||
private ISession _session;
|
||||
private IContainer _container;
|
||||
private StubClock _clock;
|
||||
|
||||
public class TestSessionLocator : ISessionLocator {
|
||||
private readonly ISession _session;
|
||||
|
||||
public TestSessionLocator(ISession session) {
|
||||
_session = session;
|
||||
}
|
||||
|
||||
public ISession For(Type entityType) {
|
||||
return _session;
|
||||
}
|
||||
}
|
||||
|
||||
[TestFixtureSetUp]
|
||||
public void InitFixture() {
|
||||
var databaseFileName = System.IO.Path.GetTempFileName();
|
||||
@@ -98,12 +86,19 @@ namespace Orchard.Tests.Modules.Users.Services {
|
||||
builder.RegisterType<InfosetHandler>().As<IContentHandler>();
|
||||
|
||||
_session = _sessionFactory.OpenSession();
|
||||
builder.RegisterInstance(new TestSessionLocator(_session)).As<ISessionLocator>();
|
||||
builder.RegisterInstance(new TestTransactionManager(_session)).As<ITransactionManager>();
|
||||
|
||||
_container = builder.Build();
|
||||
_membershipValidationService = _container.Resolve<IMembershipValidationService>();
|
||||
_membershipService = _container.Resolve<IMembershipService>();
|
||||
}
|
||||
|
||||
[TearDown]
|
||||
public void Cleanup() {
|
||||
if (_container != null)
|
||||
_container.Dispose();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CreateUserShouldAllocateModelAndCreateRecords() {
|
||||
var user = _membershipService.CreateUser(new CreateUserParams("a", "b", "c", null, null, true));
|
||||
|
@@ -34,6 +34,7 @@ using Orchard.Users.Services;
|
||||
using Orchard.Services;
|
||||
using Orchard.Tests.Messaging;
|
||||
using Orchard.Tests.Modules.Stubs;
|
||||
using Orchard.Tests.ContentManagement;
|
||||
|
||||
namespace Orchard.Tests.Modules.Users.Services {
|
||||
[TestFixture]
|
||||
@@ -47,19 +48,6 @@ namespace Orchard.Tests.Modules.Users.Services {
|
||||
private IContainer _container;
|
||||
private CultureInfo _currentCulture;
|
||||
|
||||
|
||||
public class TestSessionLocator : ISessionLocator {
|
||||
private readonly ISession _session;
|
||||
|
||||
public TestSessionLocator(ISession session) {
|
||||
_session = session;
|
||||
}
|
||||
|
||||
public ISession For(Type entityType) {
|
||||
return _session;
|
||||
}
|
||||
}
|
||||
|
||||
[TestFixtureSetUp]
|
||||
public void InitFixture() {
|
||||
_currentCulture = Thread.CurrentThread.CurrentCulture;
|
||||
@@ -109,9 +97,8 @@ namespace Orchard.Tests.Modules.Users.Services {
|
||||
builder.RegisterInstance(ShellSettingsUtility.CreateEncryptionEnabled());
|
||||
|
||||
_session = _sessionFactory.OpenSession();
|
||||
_session.BeginTransaction();
|
||||
builder.RegisterInstance(new TestTransactionManager(_session)).As<ITransactionManager>();
|
||||
|
||||
builder.RegisterInstance(new TestSessionLocator(_session)).As<ISessionLocator>();
|
||||
_container = builder.Build();
|
||||
_membershipService = _container.Resolve<IMembershipService>();
|
||||
_userService = _container.Resolve<IUserService>();
|
||||
@@ -119,8 +106,8 @@ namespace Orchard.Tests.Modules.Users.Services {
|
||||
|
||||
[TearDown]
|
||||
public void TearDown() {
|
||||
_session.Transaction.Commit();
|
||||
_session.Transaction.Dispose();
|
||||
if (_container != null)
|
||||
_container.Dispose();
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
@@ -610,6 +610,3 @@ namespace Orchard.Tests.ContentManagement {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@@ -248,7 +248,4 @@ namespace Orchard.Tests.ContentManagement {
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
@@ -1038,7 +1038,4 @@ namespace Orchard.Tests.ContentManagement {
|
||||
Assert.That(result.Count(), Is.EqualTo(1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
@@ -498,10 +498,10 @@ namespace Orchard.Core.Shapes {
|
||||
|
||||
var totalPageCount = pageSize > 0 ? (int)Math.Ceiling(TotalItemCount / pageSize) : 1;
|
||||
|
||||
var firstText = FirstText ?? T("<<");
|
||||
var previousText = PreviousText ?? T("<");
|
||||
var nextText = NextText ?? T(">");
|
||||
var lastText = LastText ?? T(">>");
|
||||
var firstText = FirstText ?? T("<<");
|
||||
var previousText = PreviousText ?? T("<");
|
||||
var nextText = NextText ?? T(">");
|
||||
var lastText = LastText ?? T(">>");
|
||||
var gapText = GapText ?? T("...");
|
||||
|
||||
var routeData = new RouteValueDictionary(Html.ViewContext.RouteData.Values);
|
||||
|
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Orchard.AuditTrail.Models;
|
||||
using Orchard.ContentManagement;
|
||||
using Orchard.Data;
|
||||
@@ -15,7 +16,12 @@ namespace Orchard.AuditTrail.Recipes.Executors {
|
||||
private readonly IAuthorizer _authorizer;
|
||||
private readonly IWorkContextAccessor _wca;
|
||||
|
||||
public AuditTrailStep(IRepository<AuditTrailEventRecord> auditTrailEventRepository, IAuthorizer authorizer, IWorkContextAccessor wca) {
|
||||
public AuditTrailStep(
|
||||
IRepository<AuditTrailEventRecord> auditTrailEventRepository,
|
||||
IAuthorizer authorizer,
|
||||
IWorkContextAccessor wca,
|
||||
RecipeExecutionLogger logger) : base(logger) {
|
||||
|
||||
_auditTrailEventRepository = auditTrailEventRepository;
|
||||
_authorizer = authorizer;
|
||||
_wca = wca;
|
||||
@@ -31,20 +37,30 @@ namespace Orchard.AuditTrail.Recipes.Executors {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var eventElement in context.RecipeStep.Step.Elements()) {
|
||||
var record = new AuditTrailEventRecord {
|
||||
EventName = eventElement.Attr<string>("Name"),
|
||||
FullEventName = eventElement.Attr<string>("FullName"),
|
||||
Category = eventElement.Attr<string>("Category"),
|
||||
UserName = eventElement.Attr<string>("User"),
|
||||
CreatedUtc = eventElement.Attr<DateTime>("CreatedUtc"),
|
||||
EventFilterKey = eventElement.Attr<string>("EventFilterKey"),
|
||||
EventFilterData = eventElement.Attr<string>("EventFilterData"),
|
||||
Comment = eventElement.El("Comment"),
|
||||
EventData = eventElement.Element("EventData").ToString(),
|
||||
};
|
||||
var elements = context.RecipeStep.Step.Elements().ToArray();
|
||||
for (var i = 0; i < elements.Length; i ++) {
|
||||
var eventElement = elements[i];
|
||||
Logger.Information("Importing audit trail event {0}/{1}.", i + 1, elements.Length);
|
||||
|
||||
_auditTrailEventRepository.Create(record);
|
||||
try {
|
||||
var record = new AuditTrailEventRecord {
|
||||
EventName = eventElement.Attr<string>("Name"),
|
||||
FullEventName = eventElement.Attr<string>("FullName"),
|
||||
Category = eventElement.Attr<string>("Category"),
|
||||
UserName = eventElement.Attr<string>("User"),
|
||||
CreatedUtc = eventElement.Attr<DateTime>("CreatedUtc"),
|
||||
EventFilterKey = eventElement.Attr<string>("EventFilterKey"),
|
||||
EventFilterData = eventElement.Attr<string>("EventFilterData"),
|
||||
Comment = eventElement.El("Comment"),
|
||||
EventData = eventElement.Element("EventData").ToString(),
|
||||
};
|
||||
|
||||
_auditTrailEventRepository.Create(record);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
Logger.Error(ex, "Error while importing audit trail event {0}/{1}.", i + 1, elements.Length);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,33 +1,48 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Orchard.ContentManagement;
|
||||
using Orchard.DynamicForms.Models;
|
||||
using Orchard.DynamicForms.Services;
|
||||
using Orchard.Environment.Extensions;
|
||||
using Orchard.Logging;
|
||||
using Orchard.Recipes.Models;
|
||||
using Orchard.Recipes.Services;
|
||||
|
||||
namespace Orchard.DynamicForms.Recipes.Executors {
|
||||
public class FormSubmissionsStep : RecipeExecutionStep {
|
||||
private readonly IFormService _formService;
|
||||
public FormSubmissionsStep(IFormService formService) {
|
||||
|
||||
public FormSubmissionsStep(
|
||||
IFormService formService,
|
||||
RecipeExecutionLogger logger) : base(logger) {
|
||||
|
||||
_formService = formService;
|
||||
}
|
||||
|
||||
public override string Name {
|
||||
get { return "Forms"; }
|
||||
}
|
||||
public override void Execute(RecipeExecutionContext context) {
|
||||
var formsElement = context.RecipeStep.Step.Elements();
|
||||
foreach (var formElement in formsElement) {
|
||||
var formName = formElement.Attr<string>("Name");
|
||||
var submissionElements = formElement.Element("Submissions").Elements();
|
||||
|
||||
foreach (var submissionElement in submissionElements) {
|
||||
_formService.CreateSubmission(new Submission {
|
||||
FormName = formName,
|
||||
CreatedUtc = submissionElement.Attr<DateTime>("CreatedUtc"),
|
||||
FormData = submissionElement.Value
|
||||
});
|
||||
public override void Execute(RecipeExecutionContext context) {
|
||||
var formElements = context.RecipeStep.Step.Elements();
|
||||
foreach (var formElement in formElements) {
|
||||
var formName = formElement.Attr<string>("Name");
|
||||
Logger.Information("Importing form '{0}'.", formName);
|
||||
|
||||
try {
|
||||
var submissionElements = formElement.Element("Submissions").Elements().ToArray();
|
||||
for (var i = 0; i < submissionElements.Length; i++) {
|
||||
Logger.Information("Importing form submission {0}/{1}.", i + 1, submissionElements.Length);
|
||||
var submissionElement = submissionElements[i];
|
||||
_formService.CreateSubmission(new Submission {
|
||||
FormName = formName,
|
||||
CreatedUtc = submissionElement.Attr<DateTime>("CreatedUtc"),
|
||||
FormData = submissionElement.Value
|
||||
});
|
||||
}
|
||||
}
|
||||
catch (Exception ex) {
|
||||
Logger.Error(ex, "Error while importing form '{0}'.", formName);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -11,6 +11,5 @@ namespace Orchard.ImportExport.Models {
|
||||
public string DatabaseTablePrefix { get; set; }
|
||||
public IEnumerable<string> EnabledFeatures { get; set; }
|
||||
public XDocument RecipeDocument { get; set; }
|
||||
public bool DropExistingTables { get; set; }
|
||||
}
|
||||
}
|
@@ -87,6 +87,8 @@
|
||||
<Compile Include="Providers\ExportActions\BuildRecipeAction.cs" />
|
||||
<Compile Include="Models\ExportActionConfigurationContext.cs" />
|
||||
<Compile Include="Models\ImportActionConfigurationContext.cs" />
|
||||
<Compile Include="Services\DatabaseManager.cs" />
|
||||
<Compile Include="Services\IDatabaseManager.cs" />
|
||||
<Compile Include="ViewModels\RecipeExecutionStepViewModel.cs" />
|
||||
<Compile Include="Services\ISetupService.cs" />
|
||||
<Compile Include="Models\SetupContext.cs" />
|
||||
|
@@ -23,6 +23,7 @@ namespace Orchard.ImportExport.Providers.ImportActions {
|
||||
private readonly IEnumerable<IRecipeExecutionStep> _recipeExecutionSteps;
|
||||
private readonly IRecipeParser _recipeParser;
|
||||
private readonly IRecipeExecutor _recipeExecutor;
|
||||
private readonly IDatabaseManager _databaseManager;
|
||||
|
||||
public ExecuteRecipeAction(
|
||||
IOrchardServices orchardServices,
|
||||
@@ -31,7 +32,8 @@ namespace Orchard.ImportExport.Providers.ImportActions {
|
||||
IFeatureManager featureManager,
|
||||
IEnumerable<IRecipeExecutionStep> recipeExecutionSteps,
|
||||
IRecipeParser recipeParser,
|
||||
IRecipeExecutor recipeExecutor) {
|
||||
IRecipeExecutor recipeExecutor,
|
||||
IDatabaseManager databaseManager) {
|
||||
|
||||
_orchardServices = orchardServices;
|
||||
_setupService = setupService;
|
||||
@@ -40,6 +42,7 @@ namespace Orchard.ImportExport.Providers.ImportActions {
|
||||
_recipeExecutionSteps = recipeExecutionSteps;
|
||||
_recipeParser = recipeParser;
|
||||
_recipeExecutor = recipeExecutor;
|
||||
_databaseManager = databaseManager;
|
||||
}
|
||||
|
||||
public override string Name { get { return "ExecuteRecipe"; } }
|
||||
@@ -153,8 +156,8 @@ namespace Orchard.ImportExport.Providers.ImportActions {
|
||||
}
|
||||
|
||||
private string Setup(XDocument recipeDocument) {
|
||||
// Prepare Setup.
|
||||
var setupContext = new SetupContext {
|
||||
DropExistingTables = true,
|
||||
RecipeDocument = recipeDocument,
|
||||
AdminPassword = SuperUserPassword,
|
||||
AdminUsername = _orchardServices.WorkContext.CurrentSite.SuperUser,
|
||||
@@ -162,8 +165,13 @@ namespace Orchard.ImportExport.Providers.ImportActions {
|
||||
DatabaseProvider = _shellSettings.DataProvider,
|
||||
DatabaseTablePrefix = _shellSettings.DataTablePrefix,
|
||||
SiteName = _orchardServices.WorkContext.CurrentSite.SiteName,
|
||||
EnabledFeatures = _featureManager.GetEnabledFeatures().Select(x => x.Id).ToArray()
|
||||
EnabledFeatures = Enumerable.Empty<string>()
|
||||
};
|
||||
|
||||
// Delete the tenant tables.
|
||||
DropTenantDatabaseTables();
|
||||
|
||||
// Execute Setup.
|
||||
return _setupService.Setup(setupContext);
|
||||
}
|
||||
|
||||
@@ -184,5 +192,10 @@ namespace Orchard.ImportExport.Providers.ImportActions {
|
||||
step.Step.UpdateStep(context);
|
||||
}
|
||||
}
|
||||
|
||||
private void DropTenantDatabaseTables() {
|
||||
_databaseManager.DropTenantDatabaseTables();
|
||||
_orchardServices.TransactionManager.RequireNew();
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,42 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Orchard.Data;
|
||||
using Orchard.Data.Migration.Interpreters;
|
||||
using Orchard.Data.Migration.Schema;
|
||||
using Orchard.Logging;
|
||||
|
||||
namespace Orchard.ImportExport.Services {
|
||||
public class DatabaseManager : Component, IDatabaseManager {
|
||||
private readonly ISessionFactoryHolder _sessionFactoryHolder;
|
||||
private readonly IDataMigrationInterpreter _dataMigrationInterpreter;
|
||||
|
||||
public DatabaseManager(
|
||||
ISessionFactoryHolder sessionFactoryHolder,
|
||||
IDataMigrationInterpreter dataMigrationInterpreter) {
|
||||
|
||||
_sessionFactoryHolder = sessionFactoryHolder;
|
||||
_dataMigrationInterpreter = dataMigrationInterpreter;
|
||||
}
|
||||
|
||||
public IEnumerable<string> GetTenantDatabaseTableNames() {
|
||||
var configuration = _sessionFactoryHolder.GetConfiguration();
|
||||
var result = configuration.ClassMappings.Select(x => x.Table.Name);
|
||||
return result.ToArray();
|
||||
}
|
||||
|
||||
public void DropTenantDatabaseTables() {
|
||||
var tableNames = GetTenantDatabaseTableNames();
|
||||
var schemaBuilder = new SchemaBuilder(_dataMigrationInterpreter);
|
||||
|
||||
foreach (var tableName in tableNames) {
|
||||
try {
|
||||
schemaBuilder.DropTable(schemaBuilder.RemoveDataTablePrefix(tableName));
|
||||
}
|
||||
catch (Exception ex) {
|
||||
Logger.Warning(ex, "Failed to drop table '{0}'.", tableName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,8 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Orchard.ImportExport.Services {
|
||||
public interface IDatabaseManager : IDependency {
|
||||
IEnumerable<string> GetTenantDatabaseTableNames();
|
||||
void DropTenantDatabaseTables();
|
||||
}
|
||||
}
|
@@ -87,29 +87,11 @@ namespace Orchard.ImportExport.Services
|
||||
|
||||
// Initialize database explicitly, and store shell descriptor.
|
||||
using (var bootstrapLifetimeScope = _shellContainerFactory.CreateContainer(shellSettings, shellBlueprint)) {
|
||||
|
||||
using (var environment = bootstrapLifetimeScope.CreateWorkContextScope()) {
|
||||
|
||||
// Check if the database is already created (in case an exception occured in the second phase).
|
||||
var schemaBuilder = new SchemaBuilder(environment.Resolve<IDataMigrationInterpreter>());
|
||||
var installationPresent = true;
|
||||
try {
|
||||
var tablePrefix = String.IsNullOrEmpty(shellSettings.DataTablePrefix) ? "" : shellSettings.DataTablePrefix + "_";
|
||||
schemaBuilder.ExecuteSql("SELECT * FROM " + tablePrefix + "Settings_ShellDescriptorRecord");
|
||||
}
|
||||
catch {
|
||||
installationPresent = false;
|
||||
}
|
||||
|
||||
if (installationPresent) {
|
||||
if (context.DropExistingTables) {
|
||||
DropTenantDatabaseTables(environment);
|
||||
}
|
||||
}
|
||||
|
||||
// Make a workaround to avoid the Transaction issue for PostgreSQL.
|
||||
// Workaround to avoid a Transaction issue with PostgreSQL.
|
||||
environment.Resolve<ITransactionManager>().RequireNew();
|
||||
|
||||
var schemaBuilder = new SchemaBuilder(environment.Resolve<IDataMigrationInterpreter>());
|
||||
schemaBuilder.CreateTable("Orchard_Framework_DataMigrationRecord", table => table
|
||||
.Column<int>("Id", column => column.PrimaryKey().Identity())
|
||||
.Column<string>("DataMigrationClass")
|
||||
@@ -131,10 +113,7 @@ namespace Orchard.ImportExport.Services
|
||||
while ( _processingEngine.AreTasksPending() )
|
||||
_processingEngine.ExecuteNextTask();
|
||||
|
||||
// Creating a standalone environment.
|
||||
// In theory this environment can be used to resolve any normal components by interface, and those
|
||||
// components will exist entirely in isolation - no crossover between the safemode container currently in effect.
|
||||
|
||||
// Create a standalone environment.
|
||||
// Must mark state as Running - otherwise standalone environment is created "for setup".
|
||||
shellSettings.State = TenantState.Running;
|
||||
using (var environment = _orchardHost.CreateStandaloneEnvironment(shellSettings)) {
|
||||
@@ -193,19 +172,5 @@ namespace Orchard.ImportExport.Services
|
||||
|
||||
return executionId;
|
||||
}
|
||||
|
||||
private void DropTenantDatabaseTables(IWorkContextScope environment) {
|
||||
var sessionFactoryHolder = environment.Resolve<ISessionFactoryHolder>();
|
||||
var schemaBuilder = new SchemaBuilder(environment.Resolve<IDataMigrationInterpreter>());
|
||||
var configuration = sessionFactoryHolder.GetConfiguration();
|
||||
foreach (var mapping in configuration.ClassMappings) {
|
||||
try {
|
||||
schemaBuilder.DropTable(mapping.Table.Name);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
Logger.Warning(ex, "Failed to drop table '{0}'.", mapping.Table.Name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,6 +1,8 @@
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Orchard.Data;
|
||||
using Orchard.Layouts.Models;
|
||||
using Orchard.Logging;
|
||||
using Orchard.Recipes.Models;
|
||||
using Orchard.Recipes.Services;
|
||||
|
||||
@@ -8,7 +10,10 @@ namespace Orchard.Layouts.Recipes.Executors {
|
||||
public class CustomElementsStep : RecipeExecutionStep {
|
||||
private readonly IRepository<ElementBlueprint> _repository;
|
||||
|
||||
public CustomElementsStep(IRepository<ElementBlueprint> repository) {
|
||||
public CustomElementsStep(
|
||||
IRepository<ElementBlueprint> repository,
|
||||
RecipeExecutionLogger logger) : base(logger) {
|
||||
|
||||
_repository = repository;
|
||||
}
|
||||
|
||||
@@ -23,13 +28,20 @@ namespace Orchard.Layouts.Recipes.Executors {
|
||||
public override void Execute(RecipeExecutionContext context) {
|
||||
foreach (var elementElement in context.RecipeStep.Step.Elements()) {
|
||||
var typeName = elementElement.Attribute("ElementTypeName").Value;
|
||||
var element = GetOrCreateElement(typeName);
|
||||
Logger.Information("Importing custom element '{0}'.", typeName);
|
||||
|
||||
element.BaseElementTypeName = elementElement.Attribute("BaseElementTypeName").Value;
|
||||
element.ElementDisplayName = elementElement.Attribute("ElementDisplayName").Value;
|
||||
element.ElementDescription = elementElement.Attribute("ElementDescription").Value;
|
||||
element.ElementCategory = elementElement.Attribute("ElementCategory").Value;
|
||||
element.BaseElementState = elementElement.Element("BaseElementState").Value;
|
||||
try {
|
||||
var element = GetOrCreateElement(typeName);
|
||||
element.BaseElementTypeName = elementElement.Attribute("BaseElementTypeName").Value;
|
||||
element.ElementDisplayName = elementElement.Attribute("ElementDisplayName").Value;
|
||||
element.ElementDescription = elementElement.Attribute("ElementDescription").Value;
|
||||
element.ElementCategory = elementElement.Attribute("ElementCategory").Value;
|
||||
element.BaseElementState = elementElement.Element("BaseElementState").Value;
|
||||
}
|
||||
catch (Exception ex) {
|
||||
Logger.Error(ex, "Error while importing custom element '{0}'.", typeName);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -53,7 +53,10 @@ namespace Orchard.Localization.Controllers {
|
||||
var contentItemTranslation = _contentManager.New<LocalizationPart>(masterContentItem.ContentType);
|
||||
contentItemTranslation.MasterContentItem = masterContentItem;
|
||||
|
||||
var content = _contentManager.BuildEditor(contentItemTranslation);
|
||||
// build the editor using the master content item so that
|
||||
// the form is pre-populated with the original values
|
||||
|
||||
var content = _contentManager.BuildEditor(masterContentItem);
|
||||
|
||||
return View(content);
|
||||
}
|
||||
|
@@ -10,12 +10,14 @@ namespace Orchard.Modules.Recipes.Executors {
|
||||
public class FeatureStep : RecipeExecutionStep {
|
||||
private readonly IFeatureManager _featureManager;
|
||||
|
||||
public FeatureStep(IFeatureManager featureManager) {
|
||||
public FeatureStep(
|
||||
IFeatureManager featureManager,
|
||||
RecipeExecutionLogger logger) : base(logger) {
|
||||
|
||||
_featureManager = featureManager;
|
||||
}
|
||||
|
||||
public override string Name
|
||||
{
|
||||
public override string Name {
|
||||
get { return "Feature"; }
|
||||
}
|
||||
|
||||
|
@@ -13,7 +13,9 @@ namespace Orchard.Recipes.Providers.Executors {
|
||||
private readonly ICommandManager _commandManager;
|
||||
private readonly CommandParser _commandParser;
|
||||
|
||||
public CommandStep(ICommandManager commandManager) {
|
||||
public CommandStep(ICommandManager commandManager,
|
||||
RecipeExecutionLogger logger) : base(logger) {
|
||||
|
||||
_commandManager = commandManager;
|
||||
_commandParser = new CommandParser();
|
||||
}
|
||||
|
@@ -23,7 +23,8 @@ namespace Orchard.Recipes.Providers.Executors {
|
||||
public ContentDefinitionStep(
|
||||
IContentDefinitionManager contentDefinitionManager,
|
||||
IContentDefinitionReader contentDefinitionReader,
|
||||
IContentDefinitionEventHandler contentDefinitonEventHandlers) {
|
||||
IContentDefinitionEventHandler contentDefinitonEventHandlers,
|
||||
RecipeExecutionLogger logger) : base(logger) {
|
||||
|
||||
_contentDefinitionManager = contentDefinitionManager;
|
||||
_contentDefinitionReader = contentDefinitionReader;
|
||||
|
@@ -14,7 +14,11 @@ namespace Orchard.Recipes.Providers.Executors {
|
||||
private readonly IOrchardServices _orchardServices;
|
||||
private readonly ITransactionManager _transactionManager;
|
||||
|
||||
public ContentStep(IOrchardServices orchardServices, ITransactionManager transactionManager) {
|
||||
public ContentStep(
|
||||
IOrchardServices orchardServices,
|
||||
ITransactionManager transactionManager,
|
||||
RecipeExecutionLogger logger) : base(logger) {
|
||||
|
||||
_orchardServices = orchardServices;
|
||||
_transactionManager = transactionManager;
|
||||
BatchSize = 64;
|
||||
@@ -79,6 +83,7 @@ namespace Orchard.Recipes.Providers.Executors {
|
||||
|
||||
// Determine if the import is to be batched in multiple transactions.
|
||||
var startIndex = 0;
|
||||
var itemIndex = 0;
|
||||
var batchSize = GetBatchSizeForDataStep(context.RecipeStep.Step);
|
||||
Logger.Debug("Using batch size {0}.", batchSize);
|
||||
|
||||
@@ -96,7 +101,7 @@ namespace Orchard.Recipes.Providers.Executors {
|
||||
if (elementDictionary[nextIdentity.ToString()].HasAttributes) {
|
||||
itemId = elementDictionary[nextIdentity.ToString()].FirstAttribute.Value;
|
||||
}
|
||||
Logger.Information("Importing data item '{0}'.", itemId);
|
||||
Logger.Information("Importing data item '{0}' (item {1}/{2}).", itemId, itemIndex + 1, elementDictionary.Count);
|
||||
try {
|
||||
_orchardServices.ContentManager.Import(
|
||||
elementDictionary[nextIdentity.ToString()],
|
||||
@@ -106,6 +111,7 @@ namespace Orchard.Recipes.Providers.Executors {
|
||||
Logger.Error(ex, "Error while importing data item '{0}'.", itemId);
|
||||
throw;
|
||||
}
|
||||
itemIndex++;
|
||||
nextIdentity = importContentSession.GetNextInBatch();
|
||||
}
|
||||
|
||||
|
@@ -10,7 +10,10 @@ namespace Orchard.Recipes.Providers.Executors {
|
||||
public class MigrationStep : RecipeExecutionStep {
|
||||
private readonly IDataMigrationManager _dataMigrationManager;
|
||||
|
||||
public MigrationStep(IDataMigrationManager dataMigrationManager) {
|
||||
public MigrationStep(
|
||||
IDataMigrationManager dataMigrationManager,
|
||||
RecipeExecutionLogger logger) : base(logger) {
|
||||
|
||||
_dataMigrationManager = dataMigrationManager;
|
||||
}
|
||||
|
||||
|
@@ -18,7 +18,8 @@ namespace Orchard.Recipes.Providers.Executors {
|
||||
public ModuleStep(
|
||||
IPackagingSourceManager packagingSourceManager,
|
||||
IPackageManager packageManager,
|
||||
IExtensionManager extensionManager) {
|
||||
IExtensionManager extensionManager,
|
||||
RecipeExecutionLogger logger) : base(logger) {
|
||||
|
||||
_packagingSourceManager = packagingSourceManager;
|
||||
_packageManager = packageManager;
|
||||
@@ -47,7 +48,7 @@ namespace Orchard.Recipes.Providers.Executors {
|
||||
}
|
||||
|
||||
if (packageId == null) {
|
||||
throw new InvalidOperationException("PackageId is required in a Module declaration in a recipe file.");
|
||||
throw new InvalidOperationException("PackageId is required in a module declaration in a recipe file.");
|
||||
}
|
||||
|
||||
// download and install module from the orchard feed or a custom feed if repository is specified.
|
||||
|
@@ -13,18 +13,19 @@ namespace Orchard.Recipes.Providers.Executors {
|
||||
private readonly IRecipeHarvester _recipeHarvester;
|
||||
private readonly IRecipeStepQueue _recipeStepQueue;
|
||||
private readonly IRepository<RecipeStepResultRecord> _recipeStepResultRecordRepository;
|
||||
private readonly ISessionLocator _sessionLocator;
|
||||
private readonly ITransactionManager _transactionManager;
|
||||
|
||||
public RecipesStep(
|
||||
IRecipeHarvester recipeHarvester,
|
||||
IRecipeStepQueue recipeStepQueue,
|
||||
IRepository<RecipeStepResultRecord> recipeStepResultRecordRepository,
|
||||
ISessionLocator sessionLocator) {
|
||||
ITransactionManager transactionManager,
|
||||
RecipeExecutionLogger logger) : base(logger) {
|
||||
|
||||
_recipeHarvester = recipeHarvester;
|
||||
_recipeStepQueue = recipeStepQueue;
|
||||
_recipeStepResultRecordRepository = recipeStepResultRecordRepository;
|
||||
_sessionLocator = sessionLocator;
|
||||
_transactionManager = transactionManager;
|
||||
}
|
||||
|
||||
public override string Name { get { return "Recipes"; } }
|
||||
@@ -37,25 +38,28 @@ namespace Orchard.Recipes.Providers.Executors {
|
||||
public override void Execute(RecipeExecutionContext context) {
|
||||
var recipeElements = context.RecipeStep.Step.Elements();
|
||||
var recipesDictionary = new Dictionary<string, IDictionary<string, Recipe>>();
|
||||
var session = _sessionLocator.For(typeof(RecipeStepResultRecord));
|
||||
var session = _transactionManager.GetSession();
|
||||
|
||||
foreach (var recipeElement in recipeElements) {
|
||||
var extensionId = recipeElement.Attr("ExtensionId");
|
||||
var recipeName = recipeElement.Attr("Name");
|
||||
var recipes = recipesDictionary.ContainsKey(extensionId) ? recipesDictionary[extensionId] : default(IDictionary<string, Recipe>);
|
||||
|
||||
if (recipes == null) {
|
||||
recipes = recipesDictionary[extensionId] = HarvestRecipes(extensionId);
|
||||
Logger.Information("Executing recipe '{0}' in extension '{1}'.", recipeName, extensionId);
|
||||
|
||||
try {
|
||||
var recipes = recipesDictionary.ContainsKey(extensionId) ? recipesDictionary[extensionId] : default(IDictionary<string, Recipe>);
|
||||
if (recipes == null)
|
||||
recipes = recipesDictionary[extensionId] = HarvestRecipes(extensionId);
|
||||
|
||||
if (!recipes.ContainsKey(recipeName))
|
||||
throw new Exception(String.Format("No recipe named '{0}' was found in extension '{1}'.", recipeName, extensionId));
|
||||
|
||||
EnqueueRecipe(session, context.ExecutionId, recipes[recipeName]);
|
||||
}
|
||||
|
||||
var recipe = recipes.ContainsKey(recipeName) ? recipes[recipeName] : default(Recipe);
|
||||
|
||||
if (recipe == null) {
|
||||
Logger.Error(String.Format("No recipe named {0} was found for extension {1}", recipeName, extensionId));
|
||||
continue;
|
||||
catch (Exception ex) {
|
||||
Logger.Error(ex, "Error while executing recipe '{0}' in extension '{1}'.", recipeName, extensionId);
|
||||
throw;
|
||||
}
|
||||
|
||||
EnqueueRecipe(session, context.ExecutionId, recipe);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -14,7 +14,12 @@ namespace Orchard.Recipes.Providers.Executors {
|
||||
private readonly IContentManager _contentManager;
|
||||
private readonly Lazy<IEnumerable<IContentHandler>> _handlers;
|
||||
|
||||
public SettingsStep(ISiteService siteService, IContentManager contentManager, Lazy<IEnumerable<IContentHandler>> handlers) {
|
||||
public SettingsStep(
|
||||
ISiteService siteService,
|
||||
IContentManager contentManager,
|
||||
Lazy<IEnumerable<IContentHandler>> handlers,
|
||||
RecipeExecutionLogger logger) : base(logger) {
|
||||
|
||||
_siteService = siteService;
|
||||
_contentManager = contentManager;
|
||||
_handlers = handlers;
|
||||
|
@@ -33,7 +33,6 @@ namespace Orchard.Recipes.Services {
|
||||
|
||||
public void ScheduleWork(string executionId) {
|
||||
var shellDescriptor = _shellDescriptorManager.GetShellDescriptor();
|
||||
Logger.Information("Scheduling execution of recipe {0}.", executionId);
|
||||
// TODO: this task entry may need to become appdata folder backed if it isn't already
|
||||
_processingEngine.AddTask(
|
||||
_shellSettings,
|
||||
@@ -45,15 +44,18 @@ namespace Orchard.Recipes.Services {
|
||||
public void ExecuteWork(string executionId) {
|
||||
ThreadContext.Properties["ExecutionId"] = executionId;
|
||||
try {
|
||||
Logger.Information("Executing next step of recipe.");
|
||||
// todo: this callback should be guarded against concurrency by the IProcessingEngine
|
||||
var scheduleMore = _recipeStepExecutor.Value.ExecuteNextStep(executionId);
|
||||
if (scheduleMore)
|
||||
if (scheduleMore) {
|
||||
Logger.Information("Scheduling next step of recipe.");
|
||||
ScheduleWork(executionId);
|
||||
else
|
||||
}
|
||||
else {
|
||||
Logger.Information("All recipe steps executed; restarting shell.");
|
||||
// https://github.com/OrchardCMS/Orchard/issues/3672
|
||||
// Because recipes execute in their own workcontext, we need to restart the shell, as signaling a cache won't work across workcontexts.
|
||||
_events.Changed(_shellDescriptorManager.GetShellDescriptor(), _shellSettings.Name);
|
||||
}
|
||||
}
|
||||
finally {
|
||||
ThreadContext.Properties["ExecutionId"] = null;
|
||||
|
@@ -28,12 +28,12 @@ namespace Orchard.Recipes.Services {
|
||||
public bool ExecuteNextStep(string executionId) {
|
||||
var nextRecipeStep = _recipeStepQueue.Dequeue(executionId);
|
||||
if (nextRecipeStep == null) {
|
||||
Logger.Information("Recipe execution completed.");
|
||||
Logger.Information("No more recipe steps left to execute.");
|
||||
_recipeExecuteEventHandler.ExecutionComplete(executionId);
|
||||
return false;
|
||||
}
|
||||
|
||||
Logger.Information("Running all recipe handlers for step '{0}'.", nextRecipeStep.Name);
|
||||
Logger.Information("Executing recipe step '{0}'.", nextRecipeStep.Name);
|
||||
|
||||
var recipeContext = new RecipeContext { RecipeStep = nextRecipeStep, Executed = false, ExecutionId = executionId };
|
||||
|
||||
|
@@ -8,7 +8,7 @@ using StackExchange.Redis;
|
||||
namespace Orchard.Redis.Configuration {
|
||||
|
||||
public class RedisConnectionProvider : IRedisConnectionProvider {
|
||||
private static ConcurrentDictionary<string, ConnectionMultiplexer> _connectionMultiplexers = new ConcurrentDictionary<string, ConnectionMultiplexer>();
|
||||
private static ConcurrentDictionary<string, Lazy<ConnectionMultiplexer>> _connectionMultiplexers = new ConcurrentDictionary<string, Lazy<ConnectionMultiplexer>>();
|
||||
private readonly ShellSettings _shellSettings;
|
||||
|
||||
public RedisConnectionProvider(ShellSettings shellSettings) {
|
||||
@@ -37,12 +37,16 @@ namespace Orchard.Redis.Configuration {
|
||||
throw new ArgumentNullException("connectionString");
|
||||
}
|
||||
|
||||
var connectionMultiplexer = _connectionMultiplexers.GetOrAdd(connectionString, cfg => {
|
||||
Logger.Debug("Creating a new cache client for: {0}", connectionString);
|
||||
return ConnectionMultiplexer.Connect(connectionString);
|
||||
});
|
||||
// when using ConcurrentDictionary, multiple threads can create the value
|
||||
// at the same time, so we need to pass a Lazy so that it's only
|
||||
// the object which is added that will create a ConnectionMultiplexer,
|
||||
// even when a delegate is passed
|
||||
|
||||
return connectionMultiplexer;
|
||||
return _connectionMultiplexers.GetOrAdd(connectionString,
|
||||
new Lazy<ConnectionMultiplexer>(() => {
|
||||
Logger.Debug("Creating a new cache client for: {0}", connectionString);
|
||||
return ConnectionMultiplexer.Connect(connectionString);
|
||||
})).Value;
|
||||
}
|
||||
}
|
||||
}
|
@@ -15,7 +15,7 @@ namespace Orchard.Redis.OutputCache {
|
||||
|
||||
[OrchardFeature("Orchard.Redis.OutputCache")]
|
||||
[OrchardSuppressDependency("Orchard.OutputCache.Services.DefaultCacheStorageProvider")]
|
||||
public class RedisOutputCacheStorageProvider : Component, IOutputCacheStorageProvider {
|
||||
public class RedisOutputCacheStorageProvider : IOutputCacheStorageProvider {
|
||||
|
||||
private readonly ShellSettings _shellSettings;
|
||||
private readonly IRedisConnectionProvider _redisConnectionProvider;
|
||||
@@ -23,18 +23,22 @@ namespace Orchard.Redis.OutputCache {
|
||||
|
||||
public const string ConnectionStringKey = "Orchard.Redis.OutputCache";
|
||||
private readonly string _connectionString;
|
||||
private readonly ConnectionMultiplexer _connectionMultiplexer;
|
||||
|
||||
public RedisOutputCacheStorageProvider(ShellSettings shellSettings, IRedisConnectionProvider redisConnectionProvider) {
|
||||
_shellSettings = shellSettings;
|
||||
_redisConnectionProvider = redisConnectionProvider;
|
||||
_connectionString = _redisConnectionProvider.GetConnectionString(ConnectionStringKey);
|
||||
_connectionMultiplexer = _redisConnectionProvider.GetConnection(_connectionString);
|
||||
|
||||
Logger = NullLogger.Instance;
|
||||
}
|
||||
|
||||
public ILogger Logger { get; set; }
|
||||
|
||||
public IDatabase Database {
|
||||
get {
|
||||
return _redisConnectionProvider.GetConnection(_connectionString).GetDatabase();
|
||||
return _connectionMultiplexer.GetDatabase();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -97,9 +101,8 @@ namespace Orchard.Redis.OutputCache {
|
||||
_keysCache = new HashSet<string>();
|
||||
var prefix = GetLocalizedKey("");
|
||||
|
||||
var connection = _redisConnectionProvider.GetConnection(_connectionString);
|
||||
foreach (var endPoint in connection.GetEndPoints()) {
|
||||
var server = connection.GetServer(endPoint);
|
||||
foreach (var endPoint in _connectionMultiplexer.GetEndPoints()) {
|
||||
var server = _connectionMultiplexer.GetServer(endPoint);
|
||||
foreach (var key in server.Keys(pattern: GetLocalizedKey("*"))) {
|
||||
_keysCache.Add(key.ToString().Substring(prefix.Length));
|
||||
}
|
||||
|
@@ -9,7 +9,10 @@ namespace Orchard.Roles.Recipes.Executors {
|
||||
public class RolesStep : RecipeExecutionStep {
|
||||
private readonly IRoleService _roleService;
|
||||
|
||||
public RolesStep(IRoleService roleService) {
|
||||
public RolesStep(
|
||||
IRoleService roleService,
|
||||
RecipeExecutionLogger logger) : base(logger) {
|
||||
|
||||
_roleService = roleService;
|
||||
}
|
||||
|
||||
@@ -23,7 +26,7 @@ namespace Orchard.Roles.Recipes.Executors {
|
||||
foreach (var roleElement in context.RecipeStep.Step.Elements()) {
|
||||
var roleName = roleElement.Attribute("Name").Value;
|
||||
|
||||
Logger.Information("Processing role '{0}'.", roleName);
|
||||
Logger.Information("Importing role '{0}'.", roleName);
|
||||
|
||||
try {
|
||||
var role = _roleService.GetRoleByName(roleName);
|
||||
@@ -40,7 +43,7 @@ namespace Orchard.Roles.Recipes.Executors {
|
||||
_roleService.UpdateRole(role.Id, role.Name, permissionsValid.Union(role.RolesPermissions.Select(p => p.Permission.Name)));
|
||||
}
|
||||
catch (Exception ex) {
|
||||
Logger.Error(ex, "Error while processing role '{0}'.", roleName);
|
||||
Logger.Error(ex, "Error while importing role '{0}'.", roleName);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Orchard.Logging;
|
||||
using Orchard.Recipes.Models;
|
||||
using Orchard.Recipes.Services;
|
||||
using Orchard.Rules.Models;
|
||||
@@ -9,7 +10,10 @@ namespace Orchard.Rules.Recipes.Executors {
|
||||
public class RulesStep : RecipeExecutionStep {
|
||||
private readonly IRulesServices _rulesServices;
|
||||
|
||||
public RulesStep(IRulesServices rulesServices) {
|
||||
public RulesStep(
|
||||
IRulesServices rulesServices,
|
||||
RecipeExecutionLogger logger) : base(logger) {
|
||||
|
||||
_rulesServices = rulesServices;
|
||||
}
|
||||
|
||||
@@ -19,27 +23,34 @@ namespace Orchard.Rules.Recipes.Executors {
|
||||
|
||||
public override void Execute(RecipeExecutionContext context) {
|
||||
foreach (var rule in context.RecipeStep.Step.Elements()) {
|
||||
var ruleName = rule.Attribute("Name").Value;
|
||||
Logger.Information("Importing rule '{0}'.", ruleName);
|
||||
|
||||
var ruleRecord = _rulesServices.CreateRule(rule.Attribute("Name").Value);
|
||||
ruleRecord.Enabled = bool.Parse(rule.Attribute("Enabled").Value);
|
||||
try {
|
||||
var ruleRecord = _rulesServices.CreateRule(ruleName);
|
||||
ruleRecord.Enabled = bool.Parse(rule.Attribute("Enabled").Value);
|
||||
|
||||
ruleRecord.Actions = rule.Element("Actions").Elements().Select(action =>
|
||||
new ActionRecord {
|
||||
Type = action.Attribute("Type").Value,
|
||||
Category = action.Attribute("Category").Value,
|
||||
Position = int.Parse(action.Attribute("Position").Value),
|
||||
Parameters = action.Attribute("Parameters").Value,
|
||||
RuleRecord = ruleRecord
|
||||
}).ToList();
|
||||
|
||||
ruleRecord.Events = rule.Element("Events").Elements().Select(action =>
|
||||
new EventRecord {
|
||||
Type = action.Attribute("Type").Value,
|
||||
Category = action.Attribute("Category").Value,
|
||||
Parameters = action.Attribute("Parameters").Value,
|
||||
RuleRecord = ruleRecord
|
||||
}).ToList();
|
||||
ruleRecord.Actions = rule.Element("Actions").Elements().Select(action =>
|
||||
new ActionRecord {
|
||||
Type = action.Attribute("Type").Value,
|
||||
Category = action.Attribute("Category").Value,
|
||||
Position = int.Parse(action.Attribute("Position").Value),
|
||||
Parameters = action.Attribute("Parameters").Value,
|
||||
RuleRecord = ruleRecord
|
||||
}).ToList();
|
||||
|
||||
ruleRecord.Events = rule.Element("Events").Elements().Select(action =>
|
||||
new EventRecord {
|
||||
Type = action.Attribute("Type").Value,
|
||||
Category = action.Attribute("Category").Value,
|
||||
Parameters = action.Attribute("Parameters").Value,
|
||||
RuleRecord = ruleRecord
|
||||
}).ToList();
|
||||
}
|
||||
catch (Exception ex) {
|
||||
Logger.Error(ex, "Error while importing rule '{0}'.", ruleName);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,3 +1,5 @@
|
||||
using System;
|
||||
using Orchard.Logging;
|
||||
using Orchard.Recipes.Models;
|
||||
using Orchard.Recipes.Services;
|
||||
using Orchard.Themes.Services;
|
||||
@@ -10,13 +12,23 @@ namespace Orchard.Themes.Recipes.Executors {
|
||||
get { return "CurrentTheme"; }
|
||||
}
|
||||
|
||||
public CurrentThemeStep(ISiteThemeService siteThemeService) {
|
||||
public CurrentThemeStep(
|
||||
ISiteThemeService siteThemeService,
|
||||
RecipeExecutionLogger logger) : base(logger) {
|
||||
_siteThemeService = siteThemeService;
|
||||
}
|
||||
|
||||
public override void Execute(RecipeExecutionContext context) {
|
||||
var themeId = context.RecipeStep.Step.Attribute("id").Value;
|
||||
_siteThemeService.SetSiteTheme(themeId);
|
||||
Logger.Information("Setting site theme to '{0}'.", themeId);
|
||||
|
||||
try {
|
||||
_siteThemeService.SetSiteTheme(themeId);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
Logger.Error(ex, "Error while setting site theme to '{0}'.", themeId);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -23,7 +23,8 @@ namespace Orchard.Themes.Recipes.Executors {
|
||||
IPackageManager packageManager,
|
||||
IExtensionManager extensionManager,
|
||||
IThemeService themeService,
|
||||
ISiteThemeService siteThemeService) {
|
||||
ISiteThemeService siteThemeService,
|
||||
RecipeExecutionLogger logger) : base(logger) {
|
||||
|
||||
_packagingSourceManager = packagingSourceManager;
|
||||
_packageManager = packageManager;
|
||||
|
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Orchard.Data;
|
||||
using Orchard.Logging;
|
||||
using Orchard.Recipes.Models;
|
||||
using Orchard.Recipes.Services;
|
||||
using Orchard.Workflows.Models;
|
||||
@@ -14,7 +15,8 @@ namespace Orchard.Workflows.Recipes.Executors {
|
||||
public WorkflowsStep(
|
||||
IRepository<WorkflowDefinitionRecord> workflowDefinitionRepository,
|
||||
IRepository<ActivityRecord> activityRepository,
|
||||
IRepository<TransitionRecord> transitionRepository) {
|
||||
IRepository<TransitionRecord> transitionRepository,
|
||||
RecipeExecutionLogger logger) : base(logger) {
|
||||
|
||||
_workflowDefinitionRepository = workflowDefinitionRepository;
|
||||
_activityRepository = activityRepository;
|
||||
@@ -27,39 +29,51 @@ namespace Orchard.Workflows.Recipes.Executors {
|
||||
|
||||
public override void Execute(RecipeExecutionContext context) {
|
||||
foreach (var workflowDefinitionElement in context.RecipeStep.Step.Elements()) {
|
||||
var workflowDefinition = GetOrCreateWorkflowDefinition(workflowDefinitionElement.Attribute("Name").Value);
|
||||
var activitiesElement = workflowDefinitionElement.Element("Activities");
|
||||
var transitionsElement = workflowDefinitionElement.Element("Transitions");
|
||||
var activitiesDictionary = new Dictionary<int, ActivityRecord>();
|
||||
var workflowName = workflowDefinitionElement.Attribute("Name").Value;
|
||||
Logger.Information("Importing workflow '{0}'.", workflowName);
|
||||
|
||||
workflowDefinition.Enabled = Boolean.Parse(workflowDefinitionElement.Attribute("Enabled").Value);
|
||||
try {
|
||||
var workflowDefinition = GetOrCreateWorkflowDefinition(workflowName);
|
||||
var activitiesElement = workflowDefinitionElement.Element("Activities");
|
||||
var transitionsElement = workflowDefinitionElement.Element("Transitions");
|
||||
var activitiesDictionary = new Dictionary<int, ActivityRecord>();
|
||||
|
||||
foreach (var activityElement in activitiesElement.Elements()) {
|
||||
var localId = Int32.Parse(activityElement.Attribute("Id").Value);
|
||||
var activity = new ActivityRecord {
|
||||
Name = activityElement.Attribute("Name").Value,
|
||||
Start = Boolean.Parse(activityElement.Attribute("Start").Value),
|
||||
X = Int32.Parse(activityElement.Attribute("X").Value),
|
||||
Y = Int32.Parse(activityElement.Attribute("Y").Value),
|
||||
State = activityElement.Element("State").Value
|
||||
};
|
||||
workflowDefinition.Enabled = Boolean.Parse(workflowDefinitionElement.Attribute("Enabled").Value);
|
||||
|
||||
activitiesDictionary.Add(localId, activity);
|
||||
workflowDefinition.ActivityRecords.Add(activity);
|
||||
foreach (var activityElement in activitiesElement.Elements()) {
|
||||
var localId = Int32.Parse(activityElement.Attribute("Id").Value);
|
||||
var activityName = activityElement.Attribute("Name").Value;
|
||||
Logger.Information("Importing activity '{0}' with ID '{1}'.", activityName, localId);
|
||||
var activity = new ActivityRecord {
|
||||
Name = activityName,
|
||||
Start = Boolean.Parse(activityElement.Attribute("Start").Value),
|
||||
X = Int32.Parse(activityElement.Attribute("X").Value),
|
||||
Y = Int32.Parse(activityElement.Attribute("Y").Value),
|
||||
State = activityElement.Element("State").Value
|
||||
};
|
||||
|
||||
activitiesDictionary.Add(localId, activity);
|
||||
workflowDefinition.ActivityRecords.Add(activity);
|
||||
}
|
||||
|
||||
foreach (var transitionElement in transitionsElement.Elements()) {
|
||||
var sourceActivityId = Int32.Parse(transitionElement.Attribute("SourceActivityId").Value);
|
||||
var sourceEndpoint = transitionElement.Attribute("SourceEndpoint").Value;
|
||||
var destinationActivityId = Int32.Parse(transitionElement.Attribute("DestinationActivityId").Value);
|
||||
var destinationEndpoint = transitionElement.Attribute("DestinationEndpoint").Value;
|
||||
Logger.Information("Importing transition between activities '{0}' and '{1}'.", sourceActivityId, destinationActivityId);
|
||||
|
||||
workflowDefinition.TransitionRecords.Add(new TransitionRecord {
|
||||
SourceActivityRecord = activitiesDictionary[sourceActivityId],
|
||||
SourceEndpoint = sourceEndpoint,
|
||||
DestinationActivityRecord = activitiesDictionary[destinationActivityId],
|
||||
DestinationEndpoint = destinationEndpoint
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var transitionElement in transitionsElement.Elements()) {
|
||||
var sourceActivityId = Int32.Parse(transitionElement.Attribute("SourceActivityId").Value);
|
||||
var sourceEndpoint = transitionElement.Attribute("SourceEndpoint").Value;
|
||||
var destinationActivityId = Int32.Parse(transitionElement.Attribute("DestinationActivityId").Value);
|
||||
var destinationEndpoint = transitionElement.Attribute("DestinationEndpoint").Value;
|
||||
|
||||
workflowDefinition.TransitionRecords.Add(new TransitionRecord {
|
||||
SourceActivityRecord = activitiesDictionary[sourceActivityId],
|
||||
SourceEndpoint = sourceEndpoint,
|
||||
DestinationActivityRecord = activitiesDictionary[destinationActivityId],
|
||||
DestinationEndpoint = destinationEndpoint
|
||||
});
|
||||
catch (Exception ex) {
|
||||
Logger.Error(ex, "Error while importing workflow '{0}'.", workflowName);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,6 +1,6 @@
|
||||
@{
|
||||
Model.PreviousText = T("<");
|
||||
Model.NextText = T(">");
|
||||
Model.PreviousText = T("<");
|
||||
Model.NextText = T(">");
|
||||
|
||||
var routeData = new RouteValueDictionary(ViewContext.RouteData.Values);
|
||||
var queryString = ViewContext.HttpContext.Request.QueryString;
|
||||
|
@@ -1,12 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using NHibernate.Dialect;
|
||||
using NHibernate.SqlTypes;
|
||||
using Orchard.ContentManagement.Records;
|
||||
using Orchard.Data.Migration.Schema;
|
||||
using Orchard.Environment.Configuration;
|
||||
using Orchard.Localization;
|
||||
@@ -24,11 +24,12 @@ namespace Orchard.Data.Migration.Interpreters {
|
||||
|
||||
public DefaultDataMigrationInterpreter(
|
||||
ShellSettings shellSettings,
|
||||
ITransactionManager ITransactionManager,
|
||||
ITransactionManager transactionManager,
|
||||
IEnumerable<ICommandInterpreter> commandInterpreters,
|
||||
ISessionFactoryHolder sessionFactoryHolder) {
|
||||
|
||||
_shellSettings = shellSettings;
|
||||
_transactionManager = ITransactionManager;
|
||||
_transactionManager = transactionManager;
|
||||
_commandInterpreters = commandInterpreters;
|
||||
_sqlStatements = new List<string>();
|
||||
|
||||
@@ -327,7 +328,7 @@ namespace Orchard.Data.Migration.Interpreters {
|
||||
|
||||
}
|
||||
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2100:Review SQL queries for security vulnerabilities", Justification = "Nothing comes from user input.")]
|
||||
[SuppressMessage("Microsoft.Security", "CA2100:Review SQL queries for security vulnerabilities", Justification = "Nothing comes from user input.")]
|
||||
private void RunPendingStatements() {
|
||||
|
||||
var session = _transactionManager.GetSession();
|
||||
|
@@ -165,6 +165,7 @@
|
||||
<Compile Include="Recipes\Services\RecipeBuilder.cs" />
|
||||
<Compile Include="Recipes\Services\RecipeBuilderStep.cs" />
|
||||
<Compile Include="Recipes\Models\RecipeExecutionContext.cs" />
|
||||
<Compile Include="Recipes\Services\RecipeExecutionLogger.cs" />
|
||||
<Compile Include="Recipes\Services\RecipeExecutionStep.cs" />
|
||||
<Compile Include="Recipes\Services\RecipeExecutor.cs" />
|
||||
<Compile Include="Recipes\Services\UpdateRecipeExecutionStepContext.cs" />
|
||||
|
22
src/Orchard/Recipes/Services/RecipeExecutionLogger.cs
Normal file
22
src/Orchard/Recipes/Services/RecipeExecutionLogger.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
using System;
|
||||
using Orchard.Logging;
|
||||
|
||||
namespace Orchard.Recipes.Services {
|
||||
public class RecipeExecutionLogger : ITransientDependency, ILogger {
|
||||
public RecipeExecutionLogger() {
|
||||
Logger = NullLogger.Instance;
|
||||
}
|
||||
|
||||
public Type ComponentType { get; internal set; }
|
||||
public ILogger Logger { get; set; }
|
||||
|
||||
public bool IsEnabled(LogLevel level) {
|
||||
return Logger.IsEnabled(level);
|
||||
}
|
||||
|
||||
public void Log(LogLevel level, Exception exception, string format, params object[] args) {
|
||||
var message = String.Format(format, args);
|
||||
Logger.Log(level, exception, "{0}: {1}", ComponentType.Name, message);
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,10 +1,21 @@
|
||||
using System.Collections.Generic;
|
||||
using Orchard.ContentManagement;
|
||||
using Orchard.Localization;
|
||||
using Orchard.Logging;
|
||||
using Orchard.Recipes.Models;
|
||||
|
||||
namespace Orchard.Recipes.Services {
|
||||
public abstract class RecipeExecutionStep : Component, IRecipeExecutionStep {
|
||||
public abstract class RecipeExecutionStep : IDependency, IRecipeExecutionStep {
|
||||
private readonly RecipeExecutionLogger _logger;
|
||||
|
||||
public RecipeExecutionStep(RecipeExecutionLogger logger) {
|
||||
_logger = logger;
|
||||
_logger.ComponentType = GetType();
|
||||
T = NullLocalizer.Instance;
|
||||
}
|
||||
|
||||
public Localizer T { get; set; }
|
||||
|
||||
public abstract string Name { get; }
|
||||
|
||||
public virtual IEnumerable<string> Names {
|
||||
@@ -23,6 +34,10 @@ namespace Orchard.Recipes.Services {
|
||||
get { return GetType().Name; }
|
||||
}
|
||||
|
||||
protected virtual ILogger Logger {
|
||||
get { return _logger; }
|
||||
}
|
||||
|
||||
public virtual dynamic BuildEditor(dynamic shapeFactory) {
|
||||
return null;
|
||||
}
|
||||
|
Reference in New Issue
Block a user