Merge remote-tracking branch 'upstream/dev' into dev

This commit is contained in:
mahsaro
2015-08-04 13:38:09 +01:00
42 changed files with 413 additions and 245 deletions

View File

@@ -24,6 +24,7 @@ using Orchard.Packaging.Models;
using Orchard.Packaging.Services; using Orchard.Packaging.Services;
using Orchard.Recipes.Models; using Orchard.Recipes.Models;
using Orchard.Recipes.Providers.Executors; using Orchard.Recipes.Providers.Executors;
using Orchard.Recipes.Services;
using Orchard.Tests.Environment.Extensions; using Orchard.Tests.Environment.Extensions;
using Orchard.Tests.Environment.Features; using Orchard.Tests.Environment.Features;
using Orchard.Tests.Stubs; using Orchard.Tests.Stubs;
@@ -53,6 +54,7 @@ namespace Orchard.Tests.Modules.Recipes.RecipeHandlers {
_packagesInRepository = new StubPackagingSourceManager(); _packagesInRepository = new StubPackagingSourceManager();
_packageManager = new StubPackageManager(); _packageManager = new StubPackageManager();
builder.RegisterInstance(_folders).As<IExtensionFolders>(); builder.RegisterInstance(_folders).As<IExtensionFolders>();
builder.RegisterType<RecipeExecutionLogger>().AsSelf();
builder.RegisterType<ExtensionManager>().As<IExtensionManager>(); builder.RegisterType<ExtensionManager>().As<IExtensionManager>();
builder.RegisterType<FeatureManager>().As<IFeatureManager>(); builder.RegisterType<FeatureManager>().As<IFeatureManager>();
builder.RegisterType<StubCacheManager>().As<ICacheManager>(); builder.RegisterType<StubCacheManager>().As<ICacheManager>();

View File

@@ -4,6 +4,7 @@ using NUnit.Framework;
using Orchard.Recipes.Models; using Orchard.Recipes.Models;
using Orchard.Recipes.Providers.RecipeHandlers; using Orchard.Recipes.Providers.RecipeHandlers;
using Orchard.Recipes.Services; using Orchard.Recipes.Services;
using Orchard.Tests.Stubs;
namespace Orchard.Tests.Modules.Recipes.RecipeHandlers { namespace Orchard.Tests.Modules.Recipes.RecipeHandlers {
[TestFixture] [TestFixture]
@@ -13,6 +14,7 @@ namespace Orchard.Tests.Modules.Recipes.RecipeHandlers {
[SetUp] [SetUp]
public void Init() { public void Init() {
var builder = new ContainerBuilder(); var builder = new ContainerBuilder();
builder.RegisterType<RecipeExecutionLogger>().AsSelf();
builder.RegisterType<StubRecipeExecutionStep>().As<IRecipeExecutionStep>().AsSelf().SingleInstance(); builder.RegisterType<StubRecipeExecutionStep>().As<IRecipeExecutionStep>().AsSelf().SingleInstance();
builder.RegisterType<RecipeExecutionStepHandler>().SingleInstance(); builder.RegisterType<RecipeExecutionStepHandler>().SingleInstance();
@@ -37,6 +39,11 @@ namespace Orchard.Tests.Modules.Recipes.RecipeHandlers {
} }
public class StubRecipeExecutionStep : RecipeExecutionStep { public class StubRecipeExecutionStep : RecipeExecutionStep {
public StubRecipeExecutionStep(
RecipeExecutionLogger logger) : base(logger) {
}
public override string Name { public override string Name {
get { return "FakeRecipeStep"; } get { return "FakeRecipeStep"; }
} }

View File

@@ -22,6 +22,7 @@ using Orchard.FileSystems.VirtualPath;
using Orchard.Packaging.GalleryServer; using Orchard.Packaging.GalleryServer;
using Orchard.Packaging.Services; using Orchard.Packaging.Services;
using Orchard.Recipes.Models; using Orchard.Recipes.Models;
using Orchard.Recipes.Services;
using Orchard.Tests.DisplayManagement.Descriptors; using Orchard.Tests.DisplayManagement.Descriptors;
using Orchard.Tests.Environment.Extensions; using Orchard.Tests.Environment.Extensions;
using Orchard.Tests.Environment.Features; using Orchard.Tests.Environment.Features;
@@ -56,6 +57,7 @@ namespace Orchard.Tests.Modules.Recipes.RecipeHandlers {
_packagesInRepository = new ModuleStepTest.StubPackagingSourceManager(); _packagesInRepository = new ModuleStepTest.StubPackagingSourceManager();
_packageManager = new ModuleStepTest.StubPackageManager(); _packageManager = new ModuleStepTest.StubPackageManager();
builder.RegisterInstance(_folders).As<IExtensionFolders>(); builder.RegisterInstance(_folders).As<IExtensionFolders>();
builder.RegisterType<RecipeExecutionLogger>().AsSelf();
builder.RegisterType<ExtensionManager>().As<IExtensionManager>(); builder.RegisterType<ExtensionManager>().As<IExtensionManager>();
builder.RegisterType<FeatureManager>().As<IFeatureManager>(); builder.RegisterType<FeatureManager>().As<IFeatureManager>();
builder.RegisterType<StubCacheManager>().As<ICacheManager>(); builder.RegisterType<StubCacheManager>().As<ICacheManager>();

View File

@@ -1,5 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.Specialized;
using System.Web; using System.Web;
using System.Web.Mvc; using System.Web.Mvc;
using System.Web.Routing; using System.Web.Routing;
@@ -7,25 +8,30 @@ using Autofac;
using Moq; using Moq;
using NUnit.Framework; using NUnit.Framework;
using Orchard.Caching; using Orchard.Caching;
using Orchard.ContentManagement;
using Orchard.ContentManagement.Handlers;
using Orchard.ContentManagement.MetaData; using Orchard.ContentManagement.MetaData;
using Orchard.ContentManagement.MetaData.Services; using Orchard.ContentManagement.MetaData.Services;
using Orchard.ContentManagement.Records;
using Orchard.Core.Settings.Handlers;
using Orchard.Core.Settings.Metadata; using Orchard.Core.Settings.Metadata;
using Orchard.Data; using Orchard.Core.Settings.Models;
using Orchard.Core.Settings.Services;
using Orchard.DisplayManagement; using Orchard.DisplayManagement;
using Orchard.DisplayManagement.Descriptors; using Orchard.DisplayManagement.Descriptors;
using Orchard.DisplayManagement.Implementation; using Orchard.DisplayManagement.Implementation;
using Orchard.Environment; using Orchard.Environment;
using Orchard.ContentManagement; using Orchard.Environment.Configuration;
using Orchard.ContentManagement.Handlers;
using Orchard.ContentManagement.Records;
using Orchard.Environment.Extensions; using Orchard.Environment.Extensions;
using Orchard.Localization; using Orchard.Localization;
using Orchard.Messaging.Events;
using Orchard.Messaging.Services; using Orchard.Messaging.Services;
using Orchard.Mvc;
using Orchard.Security; using Orchard.Security;
using Orchard.Security.Permissions; using Orchard.Security.Permissions;
using Orchard.Security.Providers; 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.Tests.Stubs;
using Orchard.UI.Notify; using Orchard.UI.Notify;
using Orchard.Users.Controllers; using Orchard.Users.Controllers;
@@ -33,15 +39,6 @@ using Orchard.Users.Events;
using Orchard.Users.Handlers; using Orchard.Users.Handlers;
using Orchard.Users.Models; using Orchard.Users.Models;
using Orchard.Users.Services; 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 { namespace Orchard.Tests.Modules.Users.Controllers {
[TestFixture] [TestFixture]
@@ -74,7 +71,6 @@ namespace Orchard.Tests.Modules.Users.Controllers {
builder.RegisterType<UserPartHandler>().As<IContentHandler>(); builder.RegisterType<UserPartHandler>().As<IContentHandler>();
builder.RegisterType<OrchardServices>().As<IOrchardServices>(); 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.RegisterInstance(new Work<IEnumerable<IShapeTableEventHandler>>(resolve => _container.Resolve<IEnumerable<IShapeTableEventHandler>>())).AsSelf();
builder.RegisterType<DefaultShapeTableManager>().As<IShapeTableManager>(); builder.RegisterType<DefaultShapeTableManager>().As<IShapeTableManager>();
builder.RegisterType<DefaultShapeFactory>().As<IShapeFactory>(); builder.RegisterType<DefaultShapeFactory>().As<IShapeFactory>();

View File

@@ -30,6 +30,7 @@ using Orchard.UI.PageClass;
using Orchard.Users.Handlers; using Orchard.Users.Handlers;
using Orchard.Users.Models; using Orchard.Users.Models;
using Orchard.Users.Services; using Orchard.Users.Services;
using Orchard.Tests.ContentManagement;
using Orchard.Services; using Orchard.Services;
namespace Orchard.Tests.Modules.Users.Services { namespace Orchard.Tests.Modules.Users.Services {
@@ -41,19 +42,6 @@ namespace Orchard.Tests.Modules.Users.Services {
private ISession _session; private ISession _session;
private IContainer _container; private IContainer _container;
private StubClock _clock; 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] [TestFixtureSetUp]
public void InitFixture() { public void InitFixture() {
var databaseFileName = System.IO.Path.GetTempFileName(); var databaseFileName = System.IO.Path.GetTempFileName();
@@ -98,12 +86,19 @@ namespace Orchard.Tests.Modules.Users.Services {
builder.RegisterType<InfosetHandler>().As<IContentHandler>(); builder.RegisterType<InfosetHandler>().As<IContentHandler>();
_session = _sessionFactory.OpenSession(); _session = _sessionFactory.OpenSession();
builder.RegisterInstance(new TestSessionLocator(_session)).As<ISessionLocator>(); builder.RegisterInstance(new TestTransactionManager(_session)).As<ITransactionManager>();
_container = builder.Build(); _container = builder.Build();
_membershipValidationService = _container.Resolve<IMembershipValidationService>(); _membershipValidationService = _container.Resolve<IMembershipValidationService>();
_membershipService = _container.Resolve<IMembershipService>(); _membershipService = _container.Resolve<IMembershipService>();
} }
[TearDown]
public void Cleanup() {
if (_container != null)
_container.Dispose();
}
[Test] [Test]
public void CreateUserShouldAllocateModelAndCreateRecords() { public void CreateUserShouldAllocateModelAndCreateRecords() {
var user = _membershipService.CreateUser(new CreateUserParams("a", "b", "c", null, null, true)); var user = _membershipService.CreateUser(new CreateUserParams("a", "b", "c", null, null, true));

View File

@@ -34,6 +34,7 @@ using Orchard.Users.Services;
using Orchard.Services; using Orchard.Services;
using Orchard.Tests.Messaging; using Orchard.Tests.Messaging;
using Orchard.Tests.Modules.Stubs; using Orchard.Tests.Modules.Stubs;
using Orchard.Tests.ContentManagement;
namespace Orchard.Tests.Modules.Users.Services { namespace Orchard.Tests.Modules.Users.Services {
[TestFixture] [TestFixture]
@@ -47,19 +48,6 @@ namespace Orchard.Tests.Modules.Users.Services {
private IContainer _container; private IContainer _container;
private CultureInfo _currentCulture; 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] [TestFixtureSetUp]
public void InitFixture() { public void InitFixture() {
_currentCulture = Thread.CurrentThread.CurrentCulture; _currentCulture = Thread.CurrentThread.CurrentCulture;
@@ -109,9 +97,8 @@ namespace Orchard.Tests.Modules.Users.Services {
builder.RegisterInstance(ShellSettingsUtility.CreateEncryptionEnabled()); builder.RegisterInstance(ShellSettingsUtility.CreateEncryptionEnabled());
_session = _sessionFactory.OpenSession(); _session = _sessionFactory.OpenSession();
_session.BeginTransaction(); builder.RegisterInstance(new TestTransactionManager(_session)).As<ITransactionManager>();
builder.RegisterInstance(new TestSessionLocator(_session)).As<ISessionLocator>();
_container = builder.Build(); _container = builder.Build();
_membershipService = _container.Resolve<IMembershipService>(); _membershipService = _container.Resolve<IMembershipService>();
_userService = _container.Resolve<IUserService>(); _userService = _container.Resolve<IUserService>();
@@ -119,8 +106,8 @@ namespace Orchard.Tests.Modules.Users.Services {
[TearDown] [TearDown]
public void TearDown() { public void TearDown() {
_session.Transaction.Commit(); if (_container != null)
_session.Transaction.Dispose(); _container.Dispose();
} }
[Test] [Test]

View File

@@ -610,6 +610,3 @@ namespace Orchard.Tests.ContentManagement {
} }
} }
} }

View File

@@ -248,7 +248,4 @@ namespace Orchard.Tests.ContentManagement {
} }
} }

View File

@@ -1038,7 +1038,4 @@ namespace Orchard.Tests.ContentManagement {
Assert.That(result.Count(), Is.EqualTo(1)); Assert.That(result.Count(), Is.EqualTo(1));
} }
} }
} }

View File

@@ -498,10 +498,10 @@ namespace Orchard.Core.Shapes {
var totalPageCount = pageSize > 0 ? (int)Math.Ceiling(TotalItemCount / pageSize) : 1; var totalPageCount = pageSize > 0 ? (int)Math.Ceiling(TotalItemCount / pageSize) : 1;
var firstText = FirstText ?? T("<<"); var firstText = FirstText ?? T("&lt;&lt;");
var previousText = PreviousText ?? T("<"); var previousText = PreviousText ?? T("&lt;");
var nextText = NextText ?? T(">"); var nextText = NextText ?? T("&gt;");
var lastText = LastText ?? T(">>"); var lastText = LastText ?? T("&gt;&gt;");
var gapText = GapText ?? T("..."); var gapText = GapText ?? T("...");
var routeData = new RouteValueDictionary(Html.ViewContext.RouteData.Values); var routeData = new RouteValueDictionary(Html.ViewContext.RouteData.Values);

View File

@@ -1,4 +1,5 @@
using System; using System;
using System.Linq;
using Orchard.AuditTrail.Models; using Orchard.AuditTrail.Models;
using Orchard.ContentManagement; using Orchard.ContentManagement;
using Orchard.Data; using Orchard.Data;
@@ -15,7 +16,12 @@ namespace Orchard.AuditTrail.Recipes.Executors {
private readonly IAuthorizer _authorizer; private readonly IAuthorizer _authorizer;
private readonly IWorkContextAccessor _wca; 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; _auditTrailEventRepository = auditTrailEventRepository;
_authorizer = authorizer; _authorizer = authorizer;
_wca = wca; _wca = wca;
@@ -31,20 +37,30 @@ namespace Orchard.AuditTrail.Recipes.Executors {
return; return;
} }
foreach (var eventElement in context.RecipeStep.Step.Elements()) { var elements = context.RecipeStep.Step.Elements().ToArray();
var record = new AuditTrailEventRecord { for (var i = 0; i < elements.Length; i ++) {
EventName = eventElement.Attr<string>("Name"), var eventElement = elements[i];
FullEventName = eventElement.Attr<string>("FullName"), Logger.Information("Importing audit trail event {0}/{1}.", i + 1, elements.Length);
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); 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;
}
} }
} }
} }

View File

@@ -1,33 +1,48 @@
using System; using System;
using System.Linq;
using Orchard.ContentManagement; using Orchard.ContentManagement;
using Orchard.DynamicForms.Models; using Orchard.DynamicForms.Models;
using Orchard.DynamicForms.Services; using Orchard.DynamicForms.Services;
using Orchard.Environment.Extensions; using Orchard.Logging;
using Orchard.Recipes.Models; using Orchard.Recipes.Models;
using Orchard.Recipes.Services; using Orchard.Recipes.Services;
namespace Orchard.DynamicForms.Recipes.Executors { namespace Orchard.DynamicForms.Recipes.Executors {
public class FormSubmissionsStep : RecipeExecutionStep { public class FormSubmissionsStep : RecipeExecutionStep {
private readonly IFormService _formService; private readonly IFormService _formService;
public FormSubmissionsStep(IFormService formService) {
public FormSubmissionsStep(
IFormService formService,
RecipeExecutionLogger logger) : base(logger) {
_formService = formService; _formService = formService;
} }
public override string Name { public override string Name {
get { return "Forms"; } 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) { public override void Execute(RecipeExecutionContext context) {
_formService.CreateSubmission(new Submission { var formElements = context.RecipeStep.Step.Elements();
FormName = formName, foreach (var formElement in formElements) {
CreatedUtc = submissionElement.Attr<DateTime>("CreatedUtc"), var formName = formElement.Attr<string>("Name");
FormData = submissionElement.Value 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;
} }
} }
} }

View File

@@ -11,6 +11,5 @@ namespace Orchard.ImportExport.Models {
public string DatabaseTablePrefix { get; set; } public string DatabaseTablePrefix { get; set; }
public IEnumerable<string> EnabledFeatures { get; set; } public IEnumerable<string> EnabledFeatures { get; set; }
public XDocument RecipeDocument { get; set; } public XDocument RecipeDocument { get; set; }
public bool DropExistingTables { get; set; }
} }
} }

View File

@@ -87,6 +87,8 @@
<Compile Include="Providers\ExportActions\BuildRecipeAction.cs" /> <Compile Include="Providers\ExportActions\BuildRecipeAction.cs" />
<Compile Include="Models\ExportActionConfigurationContext.cs" /> <Compile Include="Models\ExportActionConfigurationContext.cs" />
<Compile Include="Models\ImportActionConfigurationContext.cs" /> <Compile Include="Models\ImportActionConfigurationContext.cs" />
<Compile Include="Services\DatabaseManager.cs" />
<Compile Include="Services\IDatabaseManager.cs" />
<Compile Include="ViewModels\RecipeExecutionStepViewModel.cs" /> <Compile Include="ViewModels\RecipeExecutionStepViewModel.cs" />
<Compile Include="Services\ISetupService.cs" /> <Compile Include="Services\ISetupService.cs" />
<Compile Include="Models\SetupContext.cs" /> <Compile Include="Models\SetupContext.cs" />

View File

@@ -23,6 +23,7 @@ namespace Orchard.ImportExport.Providers.ImportActions {
private readonly IEnumerable<IRecipeExecutionStep> _recipeExecutionSteps; private readonly IEnumerable<IRecipeExecutionStep> _recipeExecutionSteps;
private readonly IRecipeParser _recipeParser; private readonly IRecipeParser _recipeParser;
private readonly IRecipeExecutor _recipeExecutor; private readonly IRecipeExecutor _recipeExecutor;
private readonly IDatabaseManager _databaseManager;
public ExecuteRecipeAction( public ExecuteRecipeAction(
IOrchardServices orchardServices, IOrchardServices orchardServices,
@@ -31,7 +32,8 @@ namespace Orchard.ImportExport.Providers.ImportActions {
IFeatureManager featureManager, IFeatureManager featureManager,
IEnumerable<IRecipeExecutionStep> recipeExecutionSteps, IEnumerable<IRecipeExecutionStep> recipeExecutionSteps,
IRecipeParser recipeParser, IRecipeParser recipeParser,
IRecipeExecutor recipeExecutor) { IRecipeExecutor recipeExecutor,
IDatabaseManager databaseManager) {
_orchardServices = orchardServices; _orchardServices = orchardServices;
_setupService = setupService; _setupService = setupService;
@@ -40,6 +42,7 @@ namespace Orchard.ImportExport.Providers.ImportActions {
_recipeExecutionSteps = recipeExecutionSteps; _recipeExecutionSteps = recipeExecutionSteps;
_recipeParser = recipeParser; _recipeParser = recipeParser;
_recipeExecutor = recipeExecutor; _recipeExecutor = recipeExecutor;
_databaseManager = databaseManager;
} }
public override string Name { get { return "ExecuteRecipe"; } } public override string Name { get { return "ExecuteRecipe"; } }
@@ -153,8 +156,8 @@ namespace Orchard.ImportExport.Providers.ImportActions {
} }
private string Setup(XDocument recipeDocument) { private string Setup(XDocument recipeDocument) {
// Prepare Setup.
var setupContext = new SetupContext { var setupContext = new SetupContext {
DropExistingTables = true,
RecipeDocument = recipeDocument, RecipeDocument = recipeDocument,
AdminPassword = SuperUserPassword, AdminPassword = SuperUserPassword,
AdminUsername = _orchardServices.WorkContext.CurrentSite.SuperUser, AdminUsername = _orchardServices.WorkContext.CurrentSite.SuperUser,
@@ -162,8 +165,13 @@ namespace Orchard.ImportExport.Providers.ImportActions {
DatabaseProvider = _shellSettings.DataProvider, DatabaseProvider = _shellSettings.DataProvider,
DatabaseTablePrefix = _shellSettings.DataTablePrefix, DatabaseTablePrefix = _shellSettings.DataTablePrefix,
SiteName = _orchardServices.WorkContext.CurrentSite.SiteName, 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); return _setupService.Setup(setupContext);
} }
@@ -184,5 +192,10 @@ namespace Orchard.ImportExport.Providers.ImportActions {
step.Step.UpdateStep(context); step.Step.UpdateStep(context);
} }
} }
private void DropTenantDatabaseTables() {
_databaseManager.DropTenantDatabaseTables();
_orchardServices.TransactionManager.RequireNew();
}
} }
} }

View File

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

View File

@@ -0,0 +1,8 @@
using System.Collections.Generic;
namespace Orchard.ImportExport.Services {
public interface IDatabaseManager : IDependency {
IEnumerable<string> GetTenantDatabaseTableNames();
void DropTenantDatabaseTables();
}
}

View File

@@ -87,29 +87,11 @@ namespace Orchard.ImportExport.Services
// Initialize database explicitly, and store shell descriptor. // Initialize database explicitly, and store shell descriptor.
using (var bootstrapLifetimeScope = _shellContainerFactory.CreateContainer(shellSettings, shellBlueprint)) { using (var bootstrapLifetimeScope = _shellContainerFactory.CreateContainer(shellSettings, shellBlueprint)) {
using (var environment = bootstrapLifetimeScope.CreateWorkContextScope()) { using (var environment = bootstrapLifetimeScope.CreateWorkContextScope()) {
// Workaround to avoid a Transaction issue with PostgreSQL.
// 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.
environment.Resolve<ITransactionManager>().RequireNew(); environment.Resolve<ITransactionManager>().RequireNew();
var schemaBuilder = new SchemaBuilder(environment.Resolve<IDataMigrationInterpreter>());
schemaBuilder.CreateTable("Orchard_Framework_DataMigrationRecord", table => table schemaBuilder.CreateTable("Orchard_Framework_DataMigrationRecord", table => table
.Column<int>("Id", column => column.PrimaryKey().Identity()) .Column<int>("Id", column => column.PrimaryKey().Identity())
.Column<string>("DataMigrationClass") .Column<string>("DataMigrationClass")
@@ -131,10 +113,7 @@ namespace Orchard.ImportExport.Services
while ( _processingEngine.AreTasksPending() ) while ( _processingEngine.AreTasksPending() )
_processingEngine.ExecuteNextTask(); _processingEngine.ExecuteNextTask();
// Creating a standalone environment. // Create 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.
// Must mark state as Running - otherwise standalone environment is created "for setup". // Must mark state as Running - otherwise standalone environment is created "for setup".
shellSettings.State = TenantState.Running; shellSettings.State = TenantState.Running;
using (var environment = _orchardHost.CreateStandaloneEnvironment(shellSettings)) { using (var environment = _orchardHost.CreateStandaloneEnvironment(shellSettings)) {
@@ -193,19 +172,5 @@ namespace Orchard.ImportExport.Services
return executionId; 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);
}
}
}
} }
} }

View File

@@ -1,6 +1,8 @@
using System.Collections.Generic; using System;
using System.Collections.Generic;
using Orchard.Data; using Orchard.Data;
using Orchard.Layouts.Models; using Orchard.Layouts.Models;
using Orchard.Logging;
using Orchard.Recipes.Models; using Orchard.Recipes.Models;
using Orchard.Recipes.Services; using Orchard.Recipes.Services;
@@ -8,7 +10,10 @@ namespace Orchard.Layouts.Recipes.Executors {
public class CustomElementsStep : RecipeExecutionStep { public class CustomElementsStep : RecipeExecutionStep {
private readonly IRepository<ElementBlueprint> _repository; private readonly IRepository<ElementBlueprint> _repository;
public CustomElementsStep(IRepository<ElementBlueprint> repository) { public CustomElementsStep(
IRepository<ElementBlueprint> repository,
RecipeExecutionLogger logger) : base(logger) {
_repository = repository; _repository = repository;
} }
@@ -23,13 +28,20 @@ namespace Orchard.Layouts.Recipes.Executors {
public override void Execute(RecipeExecutionContext context) { public override void Execute(RecipeExecutionContext context) {
foreach (var elementElement in context.RecipeStep.Step.Elements()) { foreach (var elementElement in context.RecipeStep.Step.Elements()) {
var typeName = elementElement.Attribute("ElementTypeName").Value; var typeName = elementElement.Attribute("ElementTypeName").Value;
var element = GetOrCreateElement(typeName); Logger.Information("Importing custom element '{0}'.", typeName);
element.BaseElementTypeName = elementElement.Attribute("BaseElementTypeName").Value; try {
element.ElementDisplayName = elementElement.Attribute("ElementDisplayName").Value; var element = GetOrCreateElement(typeName);
element.ElementDescription = elementElement.Attribute("ElementDescription").Value; element.BaseElementTypeName = elementElement.Attribute("BaseElementTypeName").Value;
element.ElementCategory = elementElement.Attribute("ElementCategory").Value; element.ElementDisplayName = elementElement.Attribute("ElementDisplayName").Value;
element.BaseElementState = elementElement.Element("BaseElementState").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;
}
} }
} }

View File

@@ -53,7 +53,10 @@ namespace Orchard.Localization.Controllers {
var contentItemTranslation = _contentManager.New<LocalizationPart>(masterContentItem.ContentType); var contentItemTranslation = _contentManager.New<LocalizationPart>(masterContentItem.ContentType);
contentItemTranslation.MasterContentItem = masterContentItem; 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); return View(content);
} }

View File

@@ -10,12 +10,14 @@ namespace Orchard.Modules.Recipes.Executors {
public class FeatureStep : RecipeExecutionStep { public class FeatureStep : RecipeExecutionStep {
private readonly IFeatureManager _featureManager; private readonly IFeatureManager _featureManager;
public FeatureStep(IFeatureManager featureManager) { public FeatureStep(
IFeatureManager featureManager,
RecipeExecutionLogger logger) : base(logger) {
_featureManager = featureManager; _featureManager = featureManager;
} }
public override string Name public override string Name {
{
get { return "Feature"; } get { return "Feature"; }
} }

View File

@@ -13,7 +13,9 @@ namespace Orchard.Recipes.Providers.Executors {
private readonly ICommandManager _commandManager; private readonly ICommandManager _commandManager;
private readonly CommandParser _commandParser; private readonly CommandParser _commandParser;
public CommandStep(ICommandManager commandManager) { public CommandStep(ICommandManager commandManager,
RecipeExecutionLogger logger) : base(logger) {
_commandManager = commandManager; _commandManager = commandManager;
_commandParser = new CommandParser(); _commandParser = new CommandParser();
} }

View File

@@ -23,7 +23,8 @@ namespace Orchard.Recipes.Providers.Executors {
public ContentDefinitionStep( public ContentDefinitionStep(
IContentDefinitionManager contentDefinitionManager, IContentDefinitionManager contentDefinitionManager,
IContentDefinitionReader contentDefinitionReader, IContentDefinitionReader contentDefinitionReader,
IContentDefinitionEventHandler contentDefinitonEventHandlers) { IContentDefinitionEventHandler contentDefinitonEventHandlers,
RecipeExecutionLogger logger) : base(logger) {
_contentDefinitionManager = contentDefinitionManager; _contentDefinitionManager = contentDefinitionManager;
_contentDefinitionReader = contentDefinitionReader; _contentDefinitionReader = contentDefinitionReader;

View File

@@ -14,7 +14,11 @@ namespace Orchard.Recipes.Providers.Executors {
private readonly IOrchardServices _orchardServices; private readonly IOrchardServices _orchardServices;
private readonly ITransactionManager _transactionManager; private readonly ITransactionManager _transactionManager;
public ContentStep(IOrchardServices orchardServices, ITransactionManager transactionManager) { public ContentStep(
IOrchardServices orchardServices,
ITransactionManager transactionManager,
RecipeExecutionLogger logger) : base(logger) {
_orchardServices = orchardServices; _orchardServices = orchardServices;
_transactionManager = transactionManager; _transactionManager = transactionManager;
BatchSize = 64; BatchSize = 64;
@@ -79,6 +83,7 @@ namespace Orchard.Recipes.Providers.Executors {
// Determine if the import is to be batched in multiple transactions. // Determine if the import is to be batched in multiple transactions.
var startIndex = 0; var startIndex = 0;
var itemIndex = 0;
var batchSize = GetBatchSizeForDataStep(context.RecipeStep.Step); var batchSize = GetBatchSizeForDataStep(context.RecipeStep.Step);
Logger.Debug("Using batch size {0}.", batchSize); Logger.Debug("Using batch size {0}.", batchSize);
@@ -96,7 +101,7 @@ namespace Orchard.Recipes.Providers.Executors {
if (elementDictionary[nextIdentity.ToString()].HasAttributes) { if (elementDictionary[nextIdentity.ToString()].HasAttributes) {
itemId = elementDictionary[nextIdentity.ToString()].FirstAttribute.Value; 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 { try {
_orchardServices.ContentManager.Import( _orchardServices.ContentManager.Import(
elementDictionary[nextIdentity.ToString()], elementDictionary[nextIdentity.ToString()],
@@ -106,6 +111,7 @@ namespace Orchard.Recipes.Providers.Executors {
Logger.Error(ex, "Error while importing data item '{0}'.", itemId); Logger.Error(ex, "Error while importing data item '{0}'.", itemId);
throw; throw;
} }
itemIndex++;
nextIdentity = importContentSession.GetNextInBatch(); nextIdentity = importContentSession.GetNextInBatch();
} }

View File

@@ -10,7 +10,10 @@ namespace Orchard.Recipes.Providers.Executors {
public class MigrationStep : RecipeExecutionStep { public class MigrationStep : RecipeExecutionStep {
private readonly IDataMigrationManager _dataMigrationManager; private readonly IDataMigrationManager _dataMigrationManager;
public MigrationStep(IDataMigrationManager dataMigrationManager) { public MigrationStep(
IDataMigrationManager dataMigrationManager,
RecipeExecutionLogger logger) : base(logger) {
_dataMigrationManager = dataMigrationManager; _dataMigrationManager = dataMigrationManager;
} }

View File

@@ -18,7 +18,8 @@ namespace Orchard.Recipes.Providers.Executors {
public ModuleStep( public ModuleStep(
IPackagingSourceManager packagingSourceManager, IPackagingSourceManager packagingSourceManager,
IPackageManager packageManager, IPackageManager packageManager,
IExtensionManager extensionManager) { IExtensionManager extensionManager,
RecipeExecutionLogger logger) : base(logger) {
_packagingSourceManager = packagingSourceManager; _packagingSourceManager = packagingSourceManager;
_packageManager = packageManager; _packageManager = packageManager;
@@ -47,7 +48,7 @@ namespace Orchard.Recipes.Providers.Executors {
} }
if (packageId == null) { 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. // download and install module from the orchard feed or a custom feed if repository is specified.

View File

@@ -13,18 +13,19 @@ namespace Orchard.Recipes.Providers.Executors {
private readonly IRecipeHarvester _recipeHarvester; private readonly IRecipeHarvester _recipeHarvester;
private readonly IRecipeStepQueue _recipeStepQueue; private readonly IRecipeStepQueue _recipeStepQueue;
private readonly IRepository<RecipeStepResultRecord> _recipeStepResultRecordRepository; private readonly IRepository<RecipeStepResultRecord> _recipeStepResultRecordRepository;
private readonly ISessionLocator _sessionLocator; private readonly ITransactionManager _transactionManager;
public RecipesStep( public RecipesStep(
IRecipeHarvester recipeHarvester, IRecipeHarvester recipeHarvester,
IRecipeStepQueue recipeStepQueue, IRecipeStepQueue recipeStepQueue,
IRepository<RecipeStepResultRecord> recipeStepResultRecordRepository, IRepository<RecipeStepResultRecord> recipeStepResultRecordRepository,
ISessionLocator sessionLocator) { ITransactionManager transactionManager,
RecipeExecutionLogger logger) : base(logger) {
_recipeHarvester = recipeHarvester; _recipeHarvester = recipeHarvester;
_recipeStepQueue = recipeStepQueue; _recipeStepQueue = recipeStepQueue;
_recipeStepResultRecordRepository = recipeStepResultRecordRepository; _recipeStepResultRecordRepository = recipeStepResultRecordRepository;
_sessionLocator = sessionLocator; _transactionManager = transactionManager;
} }
public override string Name { get { return "Recipes"; } } public override string Name { get { return "Recipes"; } }
@@ -37,25 +38,28 @@ namespace Orchard.Recipes.Providers.Executors {
public override void Execute(RecipeExecutionContext context) { public override void Execute(RecipeExecutionContext context) {
var recipeElements = context.RecipeStep.Step.Elements(); var recipeElements = context.RecipeStep.Step.Elements();
var recipesDictionary = new Dictionary<string, IDictionary<string, Recipe>>(); var recipesDictionary = new Dictionary<string, IDictionary<string, Recipe>>();
var session = _sessionLocator.For(typeof(RecipeStepResultRecord)); var session = _transactionManager.GetSession();
foreach (var recipeElement in recipeElements) { foreach (var recipeElement in recipeElements) {
var extensionId = recipeElement.Attr("ExtensionId"); var extensionId = recipeElement.Attr("ExtensionId");
var recipeName = recipeElement.Attr("Name"); var recipeName = recipeElement.Attr("Name");
var recipes = recipesDictionary.ContainsKey(extensionId) ? recipesDictionary[extensionId] : default(IDictionary<string, Recipe>);
if (recipes == null) { Logger.Information("Executing recipe '{0}' in extension '{1}'.", recipeName, extensionId);
recipes = recipesDictionary[extensionId] = HarvestRecipes(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]);
} }
catch (Exception ex) {
var recipe = recipes.ContainsKey(recipeName) ? recipes[recipeName] : default(Recipe); Logger.Error(ex, "Error while executing recipe '{0}' in extension '{1}'.", recipeName, extensionId);
throw;
if (recipe == null) {
Logger.Error(String.Format("No recipe named {0} was found for extension {1}", recipeName, extensionId));
continue;
} }
EnqueueRecipe(session, context.ExecutionId, recipe);
} }
} }

View File

@@ -14,7 +14,12 @@ namespace Orchard.Recipes.Providers.Executors {
private readonly IContentManager _contentManager; private readonly IContentManager _contentManager;
private readonly Lazy<IEnumerable<IContentHandler>> _handlers; 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; _siteService = siteService;
_contentManager = contentManager; _contentManager = contentManager;
_handlers = handlers; _handlers = handlers;

View File

@@ -33,7 +33,6 @@ namespace Orchard.Recipes.Services {
public void ScheduleWork(string executionId) { public void ScheduleWork(string executionId) {
var shellDescriptor = _shellDescriptorManager.GetShellDescriptor(); 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 // TODO: this task entry may need to become appdata folder backed if it isn't already
_processingEngine.AddTask( _processingEngine.AddTask(
_shellSettings, _shellSettings,
@@ -45,15 +44,18 @@ namespace Orchard.Recipes.Services {
public void ExecuteWork(string executionId) { public void ExecuteWork(string executionId) {
ThreadContext.Properties["ExecutionId"] = executionId; ThreadContext.Properties["ExecutionId"] = executionId;
try { try {
Logger.Information("Executing next step of recipe.");
// todo: this callback should be guarded against concurrency by the IProcessingEngine // todo: this callback should be guarded against concurrency by the IProcessingEngine
var scheduleMore = _recipeStepExecutor.Value.ExecuteNextStep(executionId); var scheduleMore = _recipeStepExecutor.Value.ExecuteNextStep(executionId);
if (scheduleMore) if (scheduleMore) {
Logger.Information("Scheduling next step of recipe.");
ScheduleWork(executionId); ScheduleWork(executionId);
else }
else {
Logger.Information("All recipe steps executed; restarting shell.");
// https://github.com/OrchardCMS/Orchard/issues/3672 // 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. // 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); _events.Changed(_shellDescriptorManager.GetShellDescriptor(), _shellSettings.Name);
}
} }
finally { finally {
ThreadContext.Properties["ExecutionId"] = null; ThreadContext.Properties["ExecutionId"] = null;

View File

@@ -28,12 +28,12 @@ namespace Orchard.Recipes.Services {
public bool ExecuteNextStep(string executionId) { public bool ExecuteNextStep(string executionId) {
var nextRecipeStep = _recipeStepQueue.Dequeue(executionId); var nextRecipeStep = _recipeStepQueue.Dequeue(executionId);
if (nextRecipeStep == null) { if (nextRecipeStep == null) {
Logger.Information("Recipe execution completed."); Logger.Information("No more recipe steps left to execute.");
_recipeExecuteEventHandler.ExecutionComplete(executionId); _recipeExecuteEventHandler.ExecutionComplete(executionId);
return false; 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 }; var recipeContext = new RecipeContext { RecipeStep = nextRecipeStep, Executed = false, ExecutionId = executionId };

View File

@@ -8,7 +8,7 @@ using StackExchange.Redis;
namespace Orchard.Redis.Configuration { namespace Orchard.Redis.Configuration {
public class RedisConnectionProvider : IRedisConnectionProvider { 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; private readonly ShellSettings _shellSettings;
public RedisConnectionProvider(ShellSettings shellSettings) { public RedisConnectionProvider(ShellSettings shellSettings) {
@@ -37,12 +37,16 @@ namespace Orchard.Redis.Configuration {
throw new ArgumentNullException("connectionString"); throw new ArgumentNullException("connectionString");
} }
var connectionMultiplexer = _connectionMultiplexers.GetOrAdd(connectionString, cfg => { // when using ConcurrentDictionary, multiple threads can create the value
Logger.Debug("Creating a new cache client for: {0}", connectionString); // at the same time, so we need to pass a Lazy so that it's only
return ConnectionMultiplexer.Connect(connectionString); // 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;
} }
} }
} }

View File

@@ -15,7 +15,7 @@ namespace Orchard.Redis.OutputCache {
[OrchardFeature("Orchard.Redis.OutputCache")] [OrchardFeature("Orchard.Redis.OutputCache")]
[OrchardSuppressDependency("Orchard.OutputCache.Services.DefaultCacheStorageProvider")] [OrchardSuppressDependency("Orchard.OutputCache.Services.DefaultCacheStorageProvider")]
public class RedisOutputCacheStorageProvider : Component, IOutputCacheStorageProvider { public class RedisOutputCacheStorageProvider : IOutputCacheStorageProvider {
private readonly ShellSettings _shellSettings; private readonly ShellSettings _shellSettings;
private readonly IRedisConnectionProvider _redisConnectionProvider; private readonly IRedisConnectionProvider _redisConnectionProvider;
@@ -23,18 +23,22 @@ namespace Orchard.Redis.OutputCache {
public const string ConnectionStringKey = "Orchard.Redis.OutputCache"; public const string ConnectionStringKey = "Orchard.Redis.OutputCache";
private readonly string _connectionString; private readonly string _connectionString;
private readonly ConnectionMultiplexer _connectionMultiplexer;
public RedisOutputCacheStorageProvider(ShellSettings shellSettings, IRedisConnectionProvider redisConnectionProvider) { public RedisOutputCacheStorageProvider(ShellSettings shellSettings, IRedisConnectionProvider redisConnectionProvider) {
_shellSettings = shellSettings; _shellSettings = shellSettings;
_redisConnectionProvider = redisConnectionProvider; _redisConnectionProvider = redisConnectionProvider;
_connectionString = _redisConnectionProvider.GetConnectionString(ConnectionStringKey); _connectionString = _redisConnectionProvider.GetConnectionString(ConnectionStringKey);
_connectionMultiplexer = _redisConnectionProvider.GetConnection(_connectionString);
Logger = NullLogger.Instance; Logger = NullLogger.Instance;
} }
public ILogger Logger { get; set; }
public IDatabase Database { public IDatabase Database {
get { get {
return _redisConnectionProvider.GetConnection(_connectionString).GetDatabase(); return _connectionMultiplexer.GetDatabase();
} }
} }
@@ -97,9 +101,8 @@ namespace Orchard.Redis.OutputCache {
_keysCache = new HashSet<string>(); _keysCache = new HashSet<string>();
var prefix = GetLocalizedKey(""); var prefix = GetLocalizedKey("");
var connection = _redisConnectionProvider.GetConnection(_connectionString); foreach (var endPoint in _connectionMultiplexer.GetEndPoints()) {
foreach (var endPoint in connection.GetEndPoints()) { var server = _connectionMultiplexer.GetServer(endPoint);
var server = connection.GetServer(endPoint);
foreach (var key in server.Keys(pattern: GetLocalizedKey("*"))) { foreach (var key in server.Keys(pattern: GetLocalizedKey("*"))) {
_keysCache.Add(key.ToString().Substring(prefix.Length)); _keysCache.Add(key.ToString().Substring(prefix.Length));
} }

View File

@@ -9,7 +9,10 @@ namespace Orchard.Roles.Recipes.Executors {
public class RolesStep : RecipeExecutionStep { public class RolesStep : RecipeExecutionStep {
private readonly IRoleService _roleService; private readonly IRoleService _roleService;
public RolesStep(IRoleService roleService) { public RolesStep(
IRoleService roleService,
RecipeExecutionLogger logger) : base(logger) {
_roleService = roleService; _roleService = roleService;
} }
@@ -23,7 +26,7 @@ namespace Orchard.Roles.Recipes.Executors {
foreach (var roleElement in context.RecipeStep.Step.Elements()) { foreach (var roleElement in context.RecipeStep.Step.Elements()) {
var roleName = roleElement.Attribute("Name").Value; var roleName = roleElement.Attribute("Name").Value;
Logger.Information("Processing role '{0}'.", roleName); Logger.Information("Importing role '{0}'.", roleName);
try { try {
var role = _roleService.GetRoleByName(roleName); 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))); _roleService.UpdateRole(role.Id, role.Name, permissionsValid.Union(role.RolesPermissions.Select(p => p.Permission.Name)));
} }
catch (Exception ex) { catch (Exception ex) {
Logger.Error(ex, "Error while processing role '{0}'.", roleName); Logger.Error(ex, "Error while importing role '{0}'.", roleName);
throw; throw;
} }
} }

View File

@@ -1,5 +1,6 @@
using System; using System;
using System.Linq; using System.Linq;
using Orchard.Logging;
using Orchard.Recipes.Models; using Orchard.Recipes.Models;
using Orchard.Recipes.Services; using Orchard.Recipes.Services;
using Orchard.Rules.Models; using Orchard.Rules.Models;
@@ -9,7 +10,10 @@ namespace Orchard.Rules.Recipes.Executors {
public class RulesStep : RecipeExecutionStep { public class RulesStep : RecipeExecutionStep {
private readonly IRulesServices _rulesServices; private readonly IRulesServices _rulesServices;
public RulesStep(IRulesServices rulesServices) { public RulesStep(
IRulesServices rulesServices,
RecipeExecutionLogger logger) : base(logger) {
_rulesServices = rulesServices; _rulesServices = rulesServices;
} }
@@ -19,27 +23,34 @@ namespace Orchard.Rules.Recipes.Executors {
public override void Execute(RecipeExecutionContext context) { public override void Execute(RecipeExecutionContext context) {
foreach (var rule in context.RecipeStep.Step.Elements()) { 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); try {
ruleRecord.Enabled = bool.Parse(rule.Attribute("Enabled").Value); var ruleRecord = _rulesServices.CreateRule(ruleName);
ruleRecord.Enabled = bool.Parse(rule.Attribute("Enabled").Value);
ruleRecord.Actions = rule.Element("Actions").Elements().Select(action => ruleRecord.Actions = rule.Element("Actions").Elements().Select(action =>
new ActionRecord { new ActionRecord {
Type = action.Attribute("Type").Value, Type = action.Attribute("Type").Value,
Category = action.Attribute("Category").Value, Category = action.Attribute("Category").Value,
Position = int.Parse(action.Attribute("Position").Value), Position = int.Parse(action.Attribute("Position").Value),
Parameters = action.Attribute("Parameters").Value, Parameters = action.Attribute("Parameters").Value,
RuleRecord = ruleRecord RuleRecord = ruleRecord
}).ToList(); }).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.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;
}
} }
} }
} }

View File

@@ -1,3 +1,5 @@
using System;
using Orchard.Logging;
using Orchard.Recipes.Models; using Orchard.Recipes.Models;
using Orchard.Recipes.Services; using Orchard.Recipes.Services;
using Orchard.Themes.Services; using Orchard.Themes.Services;
@@ -10,13 +12,23 @@ namespace Orchard.Themes.Recipes.Executors {
get { return "CurrentTheme"; } get { return "CurrentTheme"; }
} }
public CurrentThemeStep(ISiteThemeService siteThemeService) { public CurrentThemeStep(
ISiteThemeService siteThemeService,
RecipeExecutionLogger logger) : base(logger) {
_siteThemeService = siteThemeService; _siteThemeService = siteThemeService;
} }
public override void Execute(RecipeExecutionContext context) { public override void Execute(RecipeExecutionContext context) {
var themeId = context.RecipeStep.Step.Attribute("id").Value; 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;
}
} }
} }
} }

View File

@@ -23,7 +23,8 @@ namespace Orchard.Themes.Recipes.Executors {
IPackageManager packageManager, IPackageManager packageManager,
IExtensionManager extensionManager, IExtensionManager extensionManager,
IThemeService themeService, IThemeService themeService,
ISiteThemeService siteThemeService) { ISiteThemeService siteThemeService,
RecipeExecutionLogger logger) : base(logger) {
_packagingSourceManager = packagingSourceManager; _packagingSourceManager = packagingSourceManager;
_packageManager = packageManager; _packageManager = packageManager;

View File

@@ -1,6 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using Orchard.Data; using Orchard.Data;
using Orchard.Logging;
using Orchard.Recipes.Models; using Orchard.Recipes.Models;
using Orchard.Recipes.Services; using Orchard.Recipes.Services;
using Orchard.Workflows.Models; using Orchard.Workflows.Models;
@@ -14,7 +15,8 @@ namespace Orchard.Workflows.Recipes.Executors {
public WorkflowsStep( public WorkflowsStep(
IRepository<WorkflowDefinitionRecord> workflowDefinitionRepository, IRepository<WorkflowDefinitionRecord> workflowDefinitionRepository,
IRepository<ActivityRecord> activityRepository, IRepository<ActivityRecord> activityRepository,
IRepository<TransitionRecord> transitionRepository) { IRepository<TransitionRecord> transitionRepository,
RecipeExecutionLogger logger) : base(logger) {
_workflowDefinitionRepository = workflowDefinitionRepository; _workflowDefinitionRepository = workflowDefinitionRepository;
_activityRepository = activityRepository; _activityRepository = activityRepository;
@@ -27,39 +29,51 @@ namespace Orchard.Workflows.Recipes.Executors {
public override void Execute(RecipeExecutionContext context) { public override void Execute(RecipeExecutionContext context) {
foreach (var workflowDefinitionElement in context.RecipeStep.Step.Elements()) { foreach (var workflowDefinitionElement in context.RecipeStep.Step.Elements()) {
var workflowDefinition = GetOrCreateWorkflowDefinition(workflowDefinitionElement.Attribute("Name").Value); var workflowName = workflowDefinitionElement.Attribute("Name").Value;
var activitiesElement = workflowDefinitionElement.Element("Activities"); Logger.Information("Importing workflow '{0}'.", workflowName);
var transitionsElement = workflowDefinitionElement.Element("Transitions");
var activitiesDictionary = new Dictionary<int, ActivityRecord>();
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()) { workflowDefinition.Enabled = Boolean.Parse(workflowDefinitionElement.Attribute("Enabled").Value);
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
};
activitiesDictionary.Add(localId, activity); foreach (var activityElement in activitiesElement.Elements()) {
workflowDefinition.ActivityRecords.Add(activity); 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
});
}
} }
catch (Exception ex) {
foreach (var transitionElement in transitionsElement.Elements()) { Logger.Error(ex, "Error while importing workflow '{0}'.", workflowName);
var sourceActivityId = Int32.Parse(transitionElement.Attribute("SourceActivityId").Value); throw;
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
});
} }
} }
} }

View File

@@ -1,6 +1,6 @@
@{ @{
Model.PreviousText = T("<"); Model.PreviousText = T("&lt;");
Model.NextText = T(">"); Model.NextText = T("&gt;");
var routeData = new RouteValueDictionary(ViewContext.RouteData.Values); var routeData = new RouteValueDictionary(ViewContext.RouteData.Values);
var queryString = ViewContext.HttpContext.Request.QueryString; var queryString = ViewContext.HttpContext.Request.QueryString;

View File

@@ -1,12 +1,12 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Data; using System.Data;
using System.Diagnostics.CodeAnalysis;
using System.Globalization; using System.Globalization;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using NHibernate.Dialect; using NHibernate.Dialect;
using NHibernate.SqlTypes; using NHibernate.SqlTypes;
using Orchard.ContentManagement.Records;
using Orchard.Data.Migration.Schema; using Orchard.Data.Migration.Schema;
using Orchard.Environment.Configuration; using Orchard.Environment.Configuration;
using Orchard.Localization; using Orchard.Localization;
@@ -24,11 +24,12 @@ namespace Orchard.Data.Migration.Interpreters {
public DefaultDataMigrationInterpreter( public DefaultDataMigrationInterpreter(
ShellSettings shellSettings, ShellSettings shellSettings,
ITransactionManager ITransactionManager, ITransactionManager transactionManager,
IEnumerable<ICommandInterpreter> commandInterpreters, IEnumerable<ICommandInterpreter> commandInterpreters,
ISessionFactoryHolder sessionFactoryHolder) { ISessionFactoryHolder sessionFactoryHolder) {
_shellSettings = shellSettings; _shellSettings = shellSettings;
_transactionManager = ITransactionManager; _transactionManager = transactionManager;
_commandInterpreters = commandInterpreters; _commandInterpreters = commandInterpreters;
_sqlStatements = new List<string>(); _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() { private void RunPendingStatements() {
var session = _transactionManager.GetSession(); var session = _transactionManager.GetSession();

View File

@@ -165,6 +165,7 @@
<Compile Include="Recipes\Services\RecipeBuilder.cs" /> <Compile Include="Recipes\Services\RecipeBuilder.cs" />
<Compile Include="Recipes\Services\RecipeBuilderStep.cs" /> <Compile Include="Recipes\Services\RecipeBuilderStep.cs" />
<Compile Include="Recipes\Models\RecipeExecutionContext.cs" /> <Compile Include="Recipes\Models\RecipeExecutionContext.cs" />
<Compile Include="Recipes\Services\RecipeExecutionLogger.cs" />
<Compile Include="Recipes\Services\RecipeExecutionStep.cs" /> <Compile Include="Recipes\Services\RecipeExecutionStep.cs" />
<Compile Include="Recipes\Services\RecipeExecutor.cs" /> <Compile Include="Recipes\Services\RecipeExecutor.cs" />
<Compile Include="Recipes\Services\UpdateRecipeExecutionStepContext.cs" /> <Compile Include="Recipes\Services\UpdateRecipeExecutionStepContext.cs" />

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

View File

@@ -1,10 +1,21 @@
using System.Collections.Generic; using System.Collections.Generic;
using Orchard.ContentManagement; using Orchard.ContentManagement;
using Orchard.Localization; using Orchard.Localization;
using Orchard.Logging;
using Orchard.Recipes.Models; using Orchard.Recipes.Models;
namespace Orchard.Recipes.Services { 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 abstract string Name { get; }
public virtual IEnumerable<string> Names { public virtual IEnumerable<string> Names {
@@ -23,6 +34,10 @@ namespace Orchard.Recipes.Services {
get { return GetType().Name; } get { return GetType().Name; }
} }
protected virtual ILogger Logger {
get { return _logger; }
}
public virtual dynamic BuildEditor(dynamic shapeFactory) { public virtual dynamic BuildEditor(dynamic shapeFactory) {
return null; return null;
} }