--HG--
branch : dev
This commit is contained in:
Louis DeJardin
2010-09-02 22:58:20 -07:00
114 changed files with 1953 additions and 781 deletions

View File

@@ -99,6 +99,14 @@
XPath="/configuration/system.web/compilation/@debug"
Value="false" />
<XmlUpdate XmlFileName="$(CloudRootFolder)\web.config"
XPath="/configuration/system.web/machineKey/@validationKey"
Value="AutoGenerate" />
<XmlUpdate XmlFileName="$(CloudRootFolder)\web.config"
XPath="/configuration/system.web/machineKey/@decryptionKey"
Value="AutoGenerate" />
<XmlUpdate XmlFileName="$(CloudRootFolder)\Config\Diagnostics.config"
XPath="/system.diagnostics/trace/@autoflush"
Value="false" />

View File

@@ -170,6 +170,14 @@
XPath="/configuration/system.web/compilation/@debug"
Value="false" />
<XmlUpdate XmlFileName="$(StageFolder)\web.config"
XPath="/configuration/system.web/machineKey/@validationKey"
Value="AutoGenerate" />
<XmlUpdate XmlFileName="$(StageFolder)\web.config"
XPath="/configuration/system.web/machineKey/@decryptionKey"
Value="AutoGenerate" />
<XmlUpdate XmlFileName="$(StageFolder)\Config\Diagnostics.config"
XPath="/system.diagnostics/trace/@autoflush"
Value="false" />

View File

@@ -2,7 +2,8 @@
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
<system.web>
<machineKey xdt:Transform="Insert" validationKey="013B82F217ABB7EAB1F699E4E5B4D290030644D435994692354DAE82B06568B058BFE3C57BF199A41FFDBC84F3BC74D9C5BD96D1265F36A22D58347B591AC8DD" decryptionKey="04797035C490263D73ED991C84C5DFCD0D0206AD4F12BC3638A38FBEABEBB8C7" validation="SHA1" decryption="AES" />
<machineKey xdt:Transform="Remove" />
<machineKey xdt:Transform="Insert" validationKey="AutoGenerate" decryptionKey="AutoGenerate" validation="SHA1" decryption="AES" />
</system.web>
<system.web.extensions xdt:Transform="Remove" />
</configuration>

View File

@@ -2,7 +2,8 @@
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
<system.web>
<machineKey xdt:Transform="Insert" validationKey="013B82F217ABB7EAB1F699E4E5B4D290030644D435994692354DAE82B06568B058BFE3C57BF199A41FFDBC84F3BC74D9C5BD96D1265F36A22D58347B591AC8DD" decryptionKey="04797035C490263D73ED991C84C5DFCD0D0206AD4F12BC3638A38FBEABEBB8C7" validation="SHA1" decryption="AES" />
<machineKey xdt:Transform="Remove" />
<machineKey xdt:Transform="Insert" validationKey="AutoGenerate" decryptionKey="AutoGenerate" validation="SHA1" decryption="AES" />
</system.web>
<system.web.extensions xdt:Transform="Remove" />
</configuration>

View File

@@ -19,6 +19,7 @@
<defaultSettings timeout="00:30:00"/>
</system.transactions>
<system.web>
<machineKey validationKey="013B82F217ABB7EAB1F699E4E5B4D290030644D435994692354DAE82B06568B058BFE3C57BF199A41FFDBC84F3BC74D9C5BD96D1265F36A22D58347B591AC8DD" decryptionKey="04797035C490263D73ED991C84C5DFCD0D0206AD4F12BC3638A38FBEABEBB8C7" validation="SHA1" decryption="AES" />
<httpRuntime requestValidationMode="2.0" />
<!--
Set compilation debug="true" to insert debugging

View File

@@ -0,0 +1,97 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Autofac;
using JetBrains.Annotations;
using Moq;
using NUnit.Framework;
using Orchard.ContentManagement;
using Orchard.ContentManagement.Drivers;
using Orchard.ContentManagement.Handlers;
using Orchard.ContentManagement.MetaData;
using Orchard.ContentManagement.Records;
using Orchard.Core.Common.Handlers;
using Orchard.Core.Common.Models;
using Orchard.Data;
using Orchard.Environment;
using Orchard.Security;
using Orchard.Tests.Modules;
using Orchard.UI.Notify;
namespace Orchard.Core.Tests.Body {
[TestFixture]
public class BodyPartTests : DatabaseEnabledTestsBase {
public override void Register(ContainerBuilder builder) {
builder.RegisterType<DefaultContentManager>().As<IContentManager>();
builder.RegisterType<DefaultContentManagerSession>().As<IContentManagerSession>();
builder.RegisterInstance(new Mock<IContentDefinitionManager>().Object);
builder.RegisterInstance(new Mock<ITransactionManager>().Object);
builder.RegisterInstance(new Mock<IAuthorizer>().Object);
builder.RegisterInstance(new Mock<INotifier>().Object);
builder.RegisterType<OrchardServices>().As<IOrchardServices>();
builder.RegisterType<ThingHandler>().As<IContentHandler>();
builder.RegisterType<DefaultContentQuery>().As<IContentQuery>();
builder.RegisterType<BodyPartHandler>().As<IContentHandler>();
}
[Test]
public void BodyCanHandleLongText() {
var contentManager = _container.Resolve<IContentManager>();
contentManager.Create<Thing>(ThingDriver.ContentType.Name, t => {
t.As<BodyPart>().Record = new BodyPartRecord();
t.Text = new String('x', 10000);
});
var bodies = contentManager.Query<BodyPart>().List();
Assert.That(bodies, Is.Not.Null);
Assert.That(bodies.Any(), Is.True);
Assert.That(bodies.First().Text, Is.EqualTo(new String('x', 10000)));
}
protected override IEnumerable<Type> DatabaseTypes {
get {
return new[] {
typeof(BodyPartRecord),
typeof(ContentTypeRecord),
typeof(ContentItemRecord),
typeof(ContentItemVersionRecord),
typeof(CommonPartRecord),
typeof(CommonPartVersionRecord),
};
}
}
[UsedImplicitly]
public class ThingHandler : ContentHandler {
public ThingHandler() {
Filters.Add(new ActivatingFilter<Thing>(ThingDriver.ContentType.Name));
Filters.Add(new ActivatingFilter<ContentPart<CommonPartVersionRecord>>(ThingDriver.ContentType.Name));
Filters.Add(new ActivatingFilter<CommonPart>(ThingDriver.ContentType.Name));
Filters.Add(new ActivatingFilter<BodyPart>(ThingDriver.ContentType.Name));
}
}
public class Thing : ContentPart {
public int Id { get { return ContentItem.Id; } }
public string Text {
get { return this.As<BodyPart>().Text; }
set { this.As<BodyPart>().Text = value; }
}
}
public class ThingDriver : ContentPartDriver<Thing> {
public readonly static ContentType ContentType = new ContentType {
Name = "thing",
DisplayName = "Thing"
};
}
}
}

View File

@@ -103,7 +103,7 @@ namespace Orchard.Core.Tests.Common.Providers {
var item = contentManager.Create<ICommonPart>("test-item", VersionOptions.Draft, init => { });
var viewModel = new OwnerEditorViewModel() { Owner = "User" };
updateModel.Setup(x => x.TryUpdateModel(viewModel, "", null, null)).Returns(true);
contentManager.UpdateEditorModel(item.ContentItem, updateModel.Object);
contentManager.UpdateEditorShape(item.ContentItem, updateModel.Object);
}
class UpdatModelStub : IUpdateModel {
@@ -142,7 +142,7 @@ namespace Orchard.Core.Tests.Common.Providers {
var updater = new UpdatModelStub() { Owner = null };
contentManager.UpdateEditorModel(item.ContentItem, updater);
contentManager.UpdateEditorShape(item.ContentItem, updater);
}
[Test, Ignore("Fix pending")]
@@ -160,7 +160,7 @@ namespace Orchard.Core.Tests.Common.Providers {
var updater = new UpdatModelStub() {Owner = ""};
contentManager.UpdateEditorModel(item.ContentItem, updater);
contentManager.UpdateEditorShape(item.ContentItem, updater);
Assert.That(updater.ModelErrors.ContainsKey("CommonPart.Owner"), Is.True);
}

View File

@@ -101,6 +101,7 @@
</ItemGroup>
<ItemGroup>
<Compile Include="Common\Providers\CommonPartProviderTests.cs" />
<Compile Include="Body\BodyPartTests.cs" />
<Compile Include="Routable\Services\RoutableServiceTests.cs" />
<Compile Include="Feeds\Controllers\FeedControllerTests.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />

View File

@@ -58,7 +58,7 @@ namespace Orchard.Core.Tests.Routable.Services {
public void InvalidCharactersShouldBeReplacedByADash() {
var contentManager = _container.Resolve<IContentManager>();
var thing = contentManager.Create<Thing>(ThingDriver.ContentType.Name, t => {
var thing = contentManager.Create<Thing>("thing", t => {
t.As<RoutePart>().Record = new RoutePartRecord();
t.Title = "Please do not use any of the following characters in your slugs: \":\", \"?\", \"#\", \"[\", \"]\", \"@\", \"!\", \"$\", \"&\", \"'\", \"(\", \")\", \"*\", \"+\", \",\", \";\", \"=\"";
});
@@ -159,13 +159,13 @@ namespace Orchard.Core.Tests.Routable.Services {
private RoutePart CreateRoutePart(string title, string slug = "", string containerPath = "") {
var contentManager = _container.Resolve<IContentManager>();
return contentManager.Create<Thing>(ThingDriver.ContentType.Name, t => {
return contentManager.Create<Thing>("thing", t => {
t.As<RoutePart>().Record = new RoutePartRecord();
if (!string.IsNullOrWhiteSpace(slug))
t.As<RoutePart>().Slug = slug;
t.Title = title;
if (!string.IsNullOrWhiteSpace(containerPath)) {
t.As<ICommonPart>().Container = contentManager.Create<Thing>(ThingDriver.ContentType.Name, tt => {
t.As<ICommonPart>().Container = contentManager.Create<Thing>("thing", tt => {
tt.As<RoutePart>().Path = containerPath;
tt.As<RoutePart>().Slug = containerPath;
});
@@ -191,10 +191,10 @@ namespace Orchard.Core.Tests.Routable.Services {
[UsedImplicitly]
public class ThingHandler : ContentHandler {
public ThingHandler() {
Filters.Add(new ActivatingFilter<Thing>(ThingDriver.ContentType.Name));
Filters.Add(new ActivatingFilter<ContentPart<CommonPartVersionRecord>>(ThingDriver.ContentType.Name));
Filters.Add(new ActivatingFilter<CommonPart>(ThingDriver.ContentType.Name));
Filters.Add(new ActivatingFilter<RoutePart>(ThingDriver.ContentType.Name));
Filters.Add(new ActivatingFilter<Thing>("thing"));
Filters.Add(new ActivatingFilter<ContentPart<CommonPartVersionRecord>>("thing"));
Filters.Add(new ActivatingFilter<CommonPart>("thing"));
Filters.Add(new ActivatingFilter<RoutePart>("thing"));
}
}
@@ -212,20 +212,13 @@ namespace Orchard.Core.Tests.Routable.Services {
}
}
public class ThingDriver : ContentItemDriver<Thing> {
public readonly static ContentType ContentType = new ContentType {
Name = "thing",
DisplayName = "Thing"
};
}
[UsedImplicitly]
public class StuffHandler : ContentHandler {
public StuffHandler() {
Filters.Add(new ActivatingFilter<Stuff>(StuffDriver.ContentType.Name));
Filters.Add(new ActivatingFilter<ContentPart<CommonPartVersionRecord>>(StuffDriver.ContentType.Name));
Filters.Add(new ActivatingFilter<CommonPart>(StuffDriver.ContentType.Name));
Filters.Add(new ActivatingFilter<RoutePart>(StuffDriver.ContentType.Name));
Filters.Add(new ActivatingFilter<Stuff>("stuff"));
Filters.Add(new ActivatingFilter<ContentPart<CommonPartVersionRecord>>("stuff"));
Filters.Add(new ActivatingFilter<CommonPart>("stuff"));
Filters.Add(new ActivatingFilter<RoutePart>("stuff"));
}
}
@@ -242,12 +235,5 @@ namespace Orchard.Core.Tests.Routable.Services {
set { this.As<RoutePart>().Slug = value; }
}
}
public class StuffDriver : ContentItemDriver<Stuff> {
public readonly static ContentType ContentType = new ContentType {
Name = "stuff",
DisplayName = "Stuff"
};
}
}
}

View File

@@ -10,6 +10,7 @@ using NUnit.Framework;
using Orchard.ContentManagement.MetaData;
using Orchard.ContentManagement.MetaData.Models;
using Orchard.ContentManagement.MetaData.Services;
using Orchard.Core.Messaging.Services;
using Orchard.Core.Settings.Metadata;
using Orchard.Data;
using Orchard.Environment;
@@ -17,6 +18,8 @@ using Orchard.ContentManagement;
using Orchard.ContentManagement.Handlers;
using Orchard.ContentManagement.Records;
using Orchard.Localization;
using Orchard.Messaging.Events;
using Orchard.Messaging.Services;
using Orchard.Security;
using Orchard.Security.Permissions;
using Orchard.UI.Notify;
@@ -41,6 +44,8 @@ namespace Orchard.Tests.Modules.Users.Controllers {
builder.RegisterType<ContentDefinitionManager>().As<IContentDefinitionManager>();
builder.RegisterType<DefaultContentManagerSession>().As<IContentManagerSession>();
builder.RegisterType<DefaultContentQuery>().As<IContentQuery>().InstancePerDependency();
builder.RegisterType<DefaultMessageManager>().As<IMessageManager>();
builder.RegisterInstance(new Mock<IMessageEventHandler>().Object);
builder.RegisterType<MembershipService>().As<IMembershipService>();
builder.RegisterType<UserService>().As<IUserService>();
builder.RegisterType<UserPartHandler>().As<IContentHandler>();

View File

@@ -2,16 +2,20 @@
using System.Web.Security;
using System.Xml.Linq;
using Autofac;
using Moq;
using NHibernate;
using NUnit.Framework;
using Orchard.ContentManagement.MetaData;
using Orchard.ContentManagement.MetaData.Models;
using Orchard.ContentManagement.MetaData.Services;
using Orchard.Core.Messaging.Services;
using Orchard.Core.Settings.Metadata;
using Orchard.Data;
using Orchard.ContentManagement;
using Orchard.ContentManagement.Handlers;
using Orchard.ContentManagement.Records;
using Orchard.Messaging.Events;
using Orchard.Messaging.Services;
using Orchard.Security;
using Orchard.Users.Handlers;
using Orchard.Users.Models;
@@ -59,6 +63,7 @@ namespace Orchard.Tests.Modules.Users.Services {
var builder = new ContainerBuilder();
//builder.RegisterModule(new ImplicitCollectionSupportModule());
builder.RegisterType<MembershipService>().As<IMembershipService>();
builder.RegisterType<DefaultContentQuery>().As<IContentQuery>();
builder.RegisterType<DefaultContentManager>().As<IContentManager>();
builder.RegisterType(typeof(SettingsFormatter))
.As(typeof(IMapper<XElement, SettingsDictionary>))
@@ -67,6 +72,8 @@ namespace Orchard.Tests.Modules.Users.Services {
builder.RegisterType<DefaultContentManagerSession>().As<IContentManagerSession>();
builder.RegisterType<UserPartHandler>().As<IContentHandler>();
builder.RegisterGeneric(typeof(Repository<>)).As(typeof(IRepository<>));
builder.RegisterInstance(new Mock<IMessageEventHandler>().Object);
builder.RegisterType<DefaultMessageManager>().As<IMessageManager>();
_session = _sessionFactory.OpenSession();
builder.RegisterInstance(new TestSessionLocator(_session)).As<ISessionLocator>();
_container = builder.Build();

View File

@@ -7,6 +7,8 @@ using Orchard.ContentManagement;
using Orchard.ContentManagement.Drivers;
using Orchard.ContentManagement.Drivers.Coordinators;
using Orchard.ContentManagement.Handlers;
using Orchard.DisplayManagement;
using Orchard.DisplayManagement.Implementation;
using Orchard.Environment.AutofacUtil;
using Orchard.Mvc.ViewModels;
using Orchard.Tests.Utility;
@@ -22,14 +24,15 @@ namespace Orchard.Tests.ContentManagement.Handlers.Coordinators {
var builder = new ContainerBuilder();
//builder.RegisterModule(new ImplicitCollectionSupportModule());
builder.RegisterType<ContentPartDriverCoordinator>().As<IContentHandler>();
builder.RegisterAutoMocking();
builder.RegisterType<ShapeHelperFactory>().As<IShapeHelperFactory>();
builder.RegisterAutoMocking(MockBehavior.Loose);
_container = builder.Build();
}
[Test]
public void DriverHandlerShouldNotThrowException() {
var contentHandler = _container.Resolve<IContentHandler>();
contentHandler.BuildDisplayModel(null);
contentHandler.BuildDisplayShape(null);
}
[Test]
@@ -41,12 +44,17 @@ namespace Orchard.Tests.ContentManagement.Handlers.Coordinators {
builder.RegisterInstance(driver2.Object);
builder.Update(_container);
var contentHandler = _container.Resolve<IContentHandler>();
var shapeHelperFactory = _container.Resolve<IShapeHelperFactory>();
var ctx = new BuildDisplayModelContext(new ContentItemViewModel(new ContentItem()), null);
var shape = shapeHelperFactory.CreateHelper();
ContentItem foo = shape.Foo();
var ctx = new BuildDisplayModelContext(new ContentItemViewModel(foo), "");
driver1.Verify(x => x.BuildDisplayModel(ctx), Times.Never());
contentHandler.BuildDisplayModel(ctx);
driver1.Verify(x => x.BuildDisplayModel(ctx));
driver1.Verify(x => x.BuildDisplayShape(ctx), Times.Never());
driver2.Verify(x => x.BuildDisplayShape(ctx), Times.Never());
contentHandler.BuildDisplayShape(ctx);
driver1.Verify(x => x.BuildDisplayShape(ctx));
driver2.Verify(x => x.BuildDisplayShape(ctx));
}
[Test]
@@ -55,15 +63,18 @@ namespace Orchard.Tests.ContentManagement.Handlers.Coordinators {
var builder = new ContainerBuilder();
builder.RegisterInstance(driver).As<IContentPartDriver>();
builder.Update(_container);
var contentHandler = _container.Resolve<IContentHandler>();
var shapeHelperFactory = _container.Resolve<IShapeHelperFactory>();
var item = new ContentItem();
item.Weld(new StubPart { Foo = new[] { "a", "b", "c" } });
var contentItem = new ContentItem();
contentItem.Weld(new StubPart { Foo = new[] { "a", "b", "c" } });
var shape = shapeHelperFactory.CreateHelper();
var item = shape.Item(contentItem);
var ctx = new BuildDisplayModelContext(new ContentItemViewModel(item), "");
Assert.That(ctx.ViewModel.Zones.Count(), Is.EqualTo(0));
contentHandler.BuildDisplayModel(ctx);
contentHandler.BuildDisplayShape(ctx);
Assert.That(ctx.ViewModel.Zones.Count(), Is.EqualTo(1));
Assert.That(ctx.ViewModel.Zones.Single().Key, Is.EqualTo("topmeta"));
Assert.That(ctx.ViewModel.Zones.Single().Value.Items.OfType<ContentPartDisplayZoneItem>().Single().Prefix, Is.EqualTo("Stub"));

View File

@@ -6,7 +6,7 @@ using Orchard.ContentManagement.ViewModels;
namespace Orchard.Tests.ContentManagement.Models {
public class AlphaHandler : ContentHandler {
public AlphaHandler() {
OnGetDisplayViewModel<Alpha>((ctx, part) => ctx.AddDisplay(new TemplateViewModel(part) { Position = "3" }));
OnGetDisplayShape<Alpha>((ctx, part) => ctx.AddDisplay(new TemplateViewModel(part) { Position = "3" }));
}
public override IEnumerable<ContentType> GetContentTypes() {
return new[] { new ContentType { Name = "alpha" } };

View File

@@ -4,7 +4,7 @@ using Orchard.ContentManagement.ViewModels;
namespace Orchard.Tests.ContentManagement.Models {
public class FlavoredHandler : ContentHandler {
public FlavoredHandler() {
OnGetDisplayViewModel<Flavored>((ctx, part) => ctx.AddDisplay(new TemplateViewModel(part)));
OnGetDisplayShape<Flavored>((ctx, part) => ctx.AddDisplay(new TemplateViewModel(part)));
}
protected override void Activating(ActivatingContentContext context) {
if (context.ContentType == "beta" || context.ContentType == "alpha") {

View File

@@ -4,7 +4,7 @@ using Orchard.ContentManagement.ViewModels;
namespace Orchard.Tests.ContentManagement.Models {
public class StyledHandler : ContentHandler {
public StyledHandler() {
OnGetDisplayViewModel<Styled>((ctx, part) => ctx.AddDisplay(new TemplateViewModel(part) { Position = "10" }));
OnGetDisplayShape<Styled>((ctx, part) => ctx.AddDisplay(new TemplateViewModel(part) { Position = "10" }));
}
protected override void Activating(ActivatingContentContext context) {

View File

@@ -14,43 +14,6 @@ using Orchard.Tests.Records;
namespace Orchard.Tests.Data.Builders {
[TestFixture]
public class SessionFactoryBuilderTests {
private string _tempDataFolder;
[SetUp]
public void Init() {
var tempFilePath = Path.GetTempFileName();
File.Delete(tempFilePath);
Directory.CreateDirectory(tempFilePath);
_tempDataFolder = tempFilePath;
}
[TearDown]
public void Term() {
try { Directory.Delete(_tempDataFolder, true); }
catch (IOException) { }
}
private static void CreateSqlServerDatabase(string databasePath) {
var databaseName = Path.GetFileNameWithoutExtension(databasePath);
using (var connection = new SqlConnection(
"Data Source=.\\SQLEXPRESS;Initial Catalog=tempdb;Integrated Security=true;User Instance=True;")) {
connection.Open();
using (var command = connection.CreateCommand()) {
command.CommandText =
"CREATE DATABASE " + databaseName +
" ON PRIMARY (NAME=" + databaseName +
", FILENAME='" + databasePath.Replace("'", "''") + "')";
command.ExecuteNonQuery();
command.CommandText =
"EXEC sp_detach_db '" + databaseName + "', 'true'";
command.ExecuteNonQuery();
}
}
}
[Test]
public void SqlCeSchemaShouldBeGeneratedAndUsable() {
@@ -58,69 +21,8 @@ namespace Orchard.Tests.Data.Builders {
new RecordBlueprint {TableName = "Hello", Type = typeof (FooRecord)}
};
var parameters = new SessionFactoryParameters {
Provider = "SqlCe",
DataFolder = _tempDataFolder,
RecordDescriptors = recordDescriptors
};
var manager = (IDataServicesProviderFactory) new DataServicesProviderFactory(new[] {
new Meta<CreateDataServicesProvider>(
(dataFolder, connectionString) => new SqlCeDataServicesProvider(dataFolder, connectionString),
new Dictionary<string, object> {{"ProviderName", "SqlCe"}})
});
var configuration = manager
.CreateProvider(parameters)
.BuildConfiguration(parameters);
configuration.SetProperty("connection.release_mode", "on_close");
new SchemaExport(configuration).Execute(false, true, false);
var sessionFactory = configuration.BuildSessionFactory();
var session = sessionFactory.OpenSession();
var foo = new FooRecord {Name = "hi there", Id = 1};
session.Save(foo);
session.Flush();
session.Close();
Assert.That(foo, Is.Not.EqualTo(0));
sessionFactory.Close();
}
[Test]
public void SqlServerSchemaShouldBeGeneratedAndUsable() {
var databasePath = Path.Combine(_tempDataFolder, "Orchard.mdf");
CreateSqlServerDatabase(databasePath);
var recordDescriptors = new[] {
new RecordBlueprint {TableName = "Hello", Type = typeof (FooRecord)}
};
var manager = (IDataServicesProviderFactory)new DataServicesProviderFactory(new[] {
new Meta<CreateDataServicesProvider>(
(dataFolder, connectionString) => new SqlServerDataServicesProvider(dataFolder, connectionString),
new Dictionary<string, object> {{"ProviderName", "SqlServer"}})
});
var parameters = new SessionFactoryParameters {
Provider = "SqlServer",
DataFolder = _tempDataFolder,
ConnectionString = "Data Source=.\\SQLEXPRESS;AttachDbFileName=" + databasePath + ";Integrated Security=True;User Instance=True;",
RecordDescriptors = recordDescriptors,
};
var configuration = manager
.CreateProvider(parameters)
.BuildConfiguration(parameters);
new SchemaExport(configuration).Execute(false, true, false);
var sessionFactory = configuration.BuildSessionFactory();
ProviderUtilities.RunWithSqlCe(recordDescriptors,
sessionFactory => {
var session = sessionFactory.OpenSession();
var foo = new FooRecord { Name = "hi there" };
session.Save(foo);
@@ -129,7 +31,27 @@ namespace Orchard.Tests.Data.Builders {
Assert.That(foo, Is.Not.EqualTo(0));
sessionFactory.Close();
});
}
[Test]
public void SqlServerSchemaShouldBeGeneratedAndUsable() {
var recordDescriptors = new[] {
new RecordBlueprint {TableName = "Hello", Type = typeof (FooRecord)}
};
ProviderUtilities.RunWithSqlServer(recordDescriptors,
sessionFactory => {
var session = sessionFactory.OpenSession();
var foo = new FooRecord { Name = "hi there" };
session.Save(foo);
session.Flush();
session.Close();
Assert.That(foo, Is.Not.EqualTo(0));
});
}
}
}

View File

@@ -0,0 +1,110 @@
using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.IO;
using Autofac.Features.Metadata;
using NHibernate;
using NHibernate.Tool.hbm2ddl;
using Orchard.Data.Providers;
using Orchard.Environment.ShellBuilders.Models;
namespace Orchard.Tests.Data {
public class ProviderUtilities {
public static void RunWithSqlServer(IEnumerable<RecordBlueprint> recordDescriptors, Action<ISessionFactory> action) {
var temporaryPath = Path.GetTempFileName();
if(File.Exists(temporaryPath))
File.Delete(temporaryPath);
Directory.CreateDirectory(temporaryPath);
var databasePath = Path.Combine(temporaryPath, "Orchard.mdf");
var databaseName = Path.GetFileNameWithoutExtension(databasePath);
try {
// create database
using ( var connection = new SqlConnection(
"Data Source=.\\SQLEXPRESS;Initial Catalog=tempdb;Integrated Security=true;User Instance=True;") ) {
connection.Open();
using ( var command = connection.CreateCommand() ) {
command.CommandText =
"CREATE DATABASE " + databaseName +
" ON PRIMARY (NAME=" + databaseName +
", FILENAME='" + databasePath.Replace("'", "''") + "')";
command.ExecuteNonQuery();
command.CommandText =
"EXEC sp_detach_db '" + databaseName + "', 'true'";
command.ExecuteNonQuery();
}
}
var manager = (IDataServicesProviderFactory)new DataServicesProviderFactory(new[] {
new Meta<CreateDataServicesProvider>(
(dataFolder, connectionString) => new SqlServerDataServicesProvider(dataFolder, connectionString),
new Dictionary<string, object> {{"ProviderName", "SqlServer"}})
});
var parameters = new SessionFactoryParameters {
Provider = "SqlServer",
DataFolder = temporaryPath,
ConnectionString = "Data Source=.\\SQLEXPRESS;AttachDbFileName=" + databasePath + ";Integrated Security=True;User Instance=True;",
RecordDescriptors = recordDescriptors,
};
var configuration = manager
.CreateProvider(parameters)
.BuildConfiguration(parameters);
new SchemaExport(configuration).Execute(false, true, false);
using ( var sessionFactory = configuration.BuildSessionFactory() ) {
action(sessionFactory);
}
}
finally {
try {
Directory.Delete(temporaryPath, true);
}
catch (IOException) {}
}
}
public static void RunWithSqlCe(IEnumerable<RecordBlueprint> recordDescriptors, Action<ISessionFactory> action) {
var temporaryPath = Path.GetTempFileName();
if ( File.Exists(temporaryPath) )
File.Delete(temporaryPath);
Directory.CreateDirectory(temporaryPath);
var databasePath = Path.Combine(temporaryPath, "Orchard.mdf");
var databaseName = Path.GetFileNameWithoutExtension(databasePath);
var parameters = new SessionFactoryParameters {
Provider = "SqlCe",
DataFolder = temporaryPath,
RecordDescriptors = recordDescriptors
};
try {
var manager = (IDataServicesProviderFactory)new DataServicesProviderFactory(new[] {
new Meta<CreateDataServicesProvider>(
(dataFolder, connectionString) => new SqlCeDataServicesProvider(dataFolder, connectionString),
new Dictionary<string, object> {{"ProviderName", "SqlCe"}})
});
var configuration = manager
.CreateProvider(parameters)
.BuildConfiguration(parameters);
configuration.SetProperty("connection.release_mode", "on_close");
new SchemaExport(configuration).Execute(false, true, false);
using ( var sessionFactory = configuration.BuildSessionFactory() ) {
action(sessionFactory);
}
}
finally {
try {
Directory.Delete(temporaryPath, true);
}
catch (IOException) {}
}
}
}
}

View File

@@ -0,0 +1,60 @@
using System;
using NUnit.Framework;
using Orchard.Environment.ShellBuilders.Models;
using Orchard.Tests.Records;
namespace Orchard.Tests.Data {
[TestFixture]
public class ProvidersTests {
[Test]
public void SqlCeShouldHandleBigFields() {
var recordDescriptors = new[] {
new RecordBlueprint {TableName = "Big", Type = typeof (BigRecord)}
};
ProviderUtilities.RunWithSqlCe(recordDescriptors,
sessionFactory => {
var session = sessionFactory.OpenSession();
var foo = new BigRecord { Body = new String('x', 10000) };
session.Save(foo);
session.Flush();
session.Close();
session = sessionFactory.OpenSession();
foo = session.Get<BigRecord>(foo.Id);
session.Close();
Assert.That(foo, Is.Not.Null);
Assert.That(foo.Body, Is.EqualTo(new String('x', 10000)));
});
}
[Test]
public void SqlServerShouldHandleBigFields() {
var recordDescriptors = new[] {
new RecordBlueprint {TableName = "Big", Type = typeof (BigRecord)}
};
ProviderUtilities.RunWithSqlServer(recordDescriptors,
sessionFactory => {
var session = sessionFactory.OpenSession();
var foo = new BigRecord { Body = new String('x', 10000) };
session.Save(foo);
session.Flush();
session.Close();
session = sessionFactory.OpenSession();
foo = session.Get<BigRecord>(foo.Id);
session.Close();
Assert.That(foo, Is.Not.Null);
Assert.That(foo.Body, Is.EqualTo(new String('x', 10000)));
});
}
}
}

View File

@@ -7,7 +7,6 @@ using System.Data;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Web;
using Autofac;
using Autofac.Features.Metadata;
using NHibernate;
@@ -16,10 +15,8 @@ using Orchard.Caching;
using Orchard.ContentManagement.Records;
using Orchard.Data;
using Orchard.Data.Conventions;
using Orchard.Data.Migration;
using Orchard.Data.Migration.Generator;
using Orchard.Data.Migration.Interpreters;
using Orchard.Data.Migration.Records;
using Orchard.Data.Migration.Schema;
using Orchard.DevTools.Services;
using Orchard.Environment.Configuration;

View File

@@ -190,7 +190,9 @@
<Compile Include="DataMigration\Utilities\NullInterpreter.cs" />
<Compile Include="DataUtility.cs" />
<Compile Include="Data\Builders\SessionFactoryBuilderTests.cs" />
<Compile Include="Data\ProviderUtilities.cs" />
<Compile Include="Data\RepositoryTests.cs" />
<Compile Include="Data\ProvidersTests.cs" />
<Compile Include="Data\StubLocator.cs" />
<Compile Include="DisplayManagement\ArgsUtility.cs" />
<Compile Include="DisplayManagement\DefaultDisplayManagerTests.cs" />
@@ -223,6 +225,7 @@
<Compile Include="Mvc\Html\HtmlHelperExtensionsTests.cs" />
<Compile Include="Mvc\Routes\ShellRouteTests.cs" />
<Compile Include="Mvc\Routes\UrlPrefixTests.cs" />
<Compile Include="Records\BigRecord.cs" />
<Compile Include="Stubs\StubReportsCoordinator.cs" />
<Compile Include="Stubs\StubVirtualPathProvider.cs" />
<Compile Include="Stubs\StubFileSystem.cs" />

View File

@@ -0,0 +1,9 @@
using Orchard.Data.Conventions;
namespace Orchard.Tests.Records {
public class BigRecord {
public virtual int Id { get; set; }
[StringLengthMax]
public virtual string Body { get; set; }
}
}

View File

@@ -190,7 +190,7 @@ namespace Orchard.Core.Contents.Controllers {
var entry = new ListContentsViewModel.Entry {
ContentItem = contentItem,
ContentItemMetadata = _contentManager.GetItemMetadata(contentItem),
ViewModel = _contentManager.BuildDisplayModel(contentItem, "SummaryAdmin"),
ViewModel = _contentManager.BuildDisplayShape(contentItem, "SummaryAdmin"),
};
if (string.IsNullOrEmpty(entry.ContentItemMetadata.DisplayText)) {
entry.ContentItemMetadata.DisplayText = string.Format("[{0}#{1}]", contentItem.ContentType, contentItem.Id);
@@ -225,7 +225,7 @@ namespace Orchard.Core.Contents.Controllers {
var model = new CreateItemViewModel {
Id = id,
Content = _contentManager.BuildEditorModel(contentItem)
Content = _contentManager.BuildEditorShape(contentItem)
};
PrepareEditorViewModel(model.Content);
return View("Create", model);
@@ -240,7 +240,7 @@ namespace Orchard.Core.Contents.Controllers {
return new HttpUnauthorizedResult();
_contentManager.Create(contentItem, VersionOptions.Draft);
model.Content = _contentManager.UpdateEditorModel(contentItem, this);
model.Content = _contentManager.UpdateEditorShape(contentItem, this);
if (!ModelState.IsValid) {
_transactionManager.Cancel();
@@ -266,7 +266,7 @@ namespace Orchard.Core.Contents.Controllers {
var model = new EditItemViewModel {
Id = id,
Content = _contentManager.BuildEditorModel(contentItem)
Content = _contentManager.BuildEditorShape(contentItem)
};
PrepareEditorViewModel(model.Content);
@@ -284,7 +284,7 @@ namespace Orchard.Core.Contents.Controllers {
if (!Services.Authorizer.Authorize(Permissions.EditOthersContent, contentItem, T("Couldn't edit content")))
return new HttpUnauthorizedResult();
model.Content = _contentManager.UpdateEditorModel(contentItem, this);
model.Content = _contentManager.UpdateEditorShape(contentItem, this);
if (!ModelState.IsValid) {
_transactionManager.Cancel();
PrepareEditorViewModel(model.Content);

View File

@@ -20,7 +20,7 @@ namespace Orchard.Core.Contents.Controllers {
var contentItem = _contentManager.Get(id, VersionOptions.Published);
var model = Shape.Content(
_contentManager.BuildDisplayModel(contentItem, "Detail")
_contentManager.BuildDisplayShape(contentItem, "Detail")
);
//PrepareDisplayViewModel(model.Content);
return View(model);
@@ -37,7 +37,7 @@ namespace Orchard.Core.Contents.Controllers {
var contentItem = _contentManager.Get(id, versionOptions);
var model = new DisplayItemViewModel {
Content = _contentManager.BuildDisplayModel(contentItem, "Detail")
Content = _contentManager.BuildDisplayShape(contentItem, "Detail")
};
PrepareDisplayViewModel(model.Content);
return View("Preview", model);

View File

@@ -1,22 +0,0 @@
using Orchard.ContentManagement;
using Orchard.ContentManagement.Aspects;
using Orchard.ContentManagement.Drivers;
using Orchard.Core.Contents.ViewModels;
using Orchard.Core.ContentsLocation.Models;
namespace Orchard.Core.Contents.Drivers {
public class ContentsDriver : ContentItemDriver<ContentPart> {
protected override string GetDisplayText(ContentPart item) {
return item.Is<IRoutableAspect>()
? item.As<IRoutableAspect>().Title
: base.GetDisplayText(item);
}
protected override DriverResult Display(ContentPart part, string displayType) {
var location = part.GetLocation(displayType, "secondary", null);
return Combined(
ContentItemTemplate("Items/Contents.Item").LongestMatch(displayType, "Summary", "SummaryAdmin"),
ContentPartTemplate(new PublishContentViewModel(part.ContentItem), "Parts/Contents.Publish").LongestMatch(displayType, "Summary", "SummaryAdmin").Location(location));
}
}
}

View File

@@ -60,7 +60,7 @@ namespace Orchard.Core.Localization.Controllers {
Id = id,
SelectedCulture = selectedCulture,
SiteCultures = siteCultures,
Content = _contentManager.BuildEditorModel(contentItem)
Content = _contentManager.BuildEditorShape(contentItem)
};
Services.TransactionManager.Cancel();
@@ -98,13 +98,13 @@ namespace Orchard.Core.Localization.Controllers {
}
}
viewModel.Content = _contentManager.UpdateEditorModel(contentItemTranslation, this);
viewModel.Content = _contentManager.UpdateEditorShape(contentItemTranslation, this);
if (!ModelState.IsValid) {
Services.TransactionManager.Cancel();
viewModel.SiteCultures = _cultureManager.ListCultures().Where(s => s != _localizationService.GetContentCulture(contentItem) && s != _cultureManager.GetSiteCulture());
contentItem.As<LocalizationPart>().Culture.Culture = null;
viewModel.Content = _contentManager.BuildEditorModel(contentItem);
viewModel.Content = _contentManager.BuildEditorShape(contentItem);
PrepareEditorViewModel(viewModel.Content);
return View(viewModel);
}

View File

@@ -0,0 +1,14 @@
using Orchard.Data.Migration;
namespace Orchard.Core.Messaging.DataMigrations {
public class MessagingDataMigration : DataMigrationImpl {
public int Create() {
SchemaBuilder.CreateTable("MessageSettingsPartRecord", table => table
.ContentPartRecord()
.Column<string>("DefaultChannelService")
);
return 1;
}
}
}

View File

@@ -0,0 +1,48 @@
using JetBrains.Annotations;
using Orchard.ContentManagement;
using Orchard.ContentManagement.Drivers;
using Orchard.Core.ContentsLocation.Models;
using Orchard.Core.Messaging.Models;
using Orchard.Core.Messaging.Services;
using Orchard.Core.Messaging.ViewModels;
using Orchard.Localization;
using Orchard.Messaging.Services;
namespace Orchard.Core.Messaging.Drivers {
[UsedImplicitly]
public class ContentSubscriptionPartDriver : ContentPartDriver<MessageSettingsPart> {
private readonly IMessageManager _messageQueueManager;
public IOrchardServices Services { get; set; }
public ContentSubscriptionPartDriver(IOrchardServices services, IMessageManager messageQueueManager) {
_messageQueueManager = messageQueueManager;
Services = services;
T = NullLocalizer.Instance;
}
public Localizer T { get; set; }
protected override string Prefix { get { return "MessageSettings"; } }
protected override DriverResult Editor(MessageSettingsPart part) {
var model = new ContentSubscriptionPartViewModel {
ChannelServices = _messageQueueManager.GetAvailableChannelServices(),
MessageSettings = part
};
return ContentPartTemplate(model, "Parts/Messaging.MessageSettings");
}
protected override DriverResult Editor(MessageSettingsPart part, IUpdateModel updater) {
var model = new ContentSubscriptionPartViewModel {
MessageSettings = part
};
if (updater.TryUpdateModel(model, Prefix, null, null)) {
}
return ContentPartTemplate(model, "Parts/Messaging.MessageSettings");
}
}
}

View File

@@ -0,0 +1,14 @@
using JetBrains.Annotations;
using Orchard.Core.Messaging.Models;
using Orchard.Data;
using Orchard.ContentManagement.Handlers;
namespace Orchard.Core.Messaging.Handlers {
[UsedImplicitly]
public class SmtpSettingsPartHandler : ContentHandler {
public SmtpSettingsPartHandler(IRepository<MessageSettingsPartRecord> repository) {
Filters.Add(new ActivatingFilter<MessageSettingsPart>("Site"));
Filters.Add(StorageFilter.For(repository));
}
}
}

View File

@@ -0,0 +1,11 @@
using Orchard.ContentManagement;
namespace Orchard.Core.Messaging.Models {
public class MessageSettingsPart : ContentPart<MessageSettingsPartRecord> {
public string DefaultChannelService {
get { return Record.DefaultChannelService; }
set { Record.DefaultChannelService = value; }
}
}
}

View File

@@ -0,0 +1,11 @@
using Orchard.ContentManagement.Records;
namespace Orchard.Core.Messaging.Models {
public class MessageSettingsPartRecord : ContentPartRecord {
/// <summary>
/// Default service used for messages
/// </summary>
public virtual string DefaultChannelService { get; set; }
}
}

View File

@@ -0,0 +1,12 @@
Name: Messaging
antiforgery: enabled
author: The Orchard Team
website: http://orchardproject.net
version: 0.1.0
orchardversion: 0.6.0
description: The Messaging module adds messaging functionalities.
features:
Messaging:
Description: Messaging services.
Category: Messaging
Dependencies: Settings

View File

@@ -0,0 +1,81 @@
using System;
using System.Collections.Generic;
using System.Linq;
using JetBrains.Annotations;
using Orchard.ContentManagement;
using Orchard.Core.Messaging.Models;
using Orchard.Logging;
using Orchard.Messaging.Events;
using Orchard.Messaging.Models;
using Orchard.Messaging.Services;
using Orchard.Settings;
using Orchard.ContentManagement.Records;
namespace Orchard.Core.Messaging.Services {
public class DefaultMessageManager : IMessageManager {
private readonly IMessageEventHandler _messageEventHandler;
private readonly IEnumerable<IMessagingChannel> _channels;
protected virtual ISite CurrentSite { get; [UsedImplicitly] private set; }
public ILogger Logger { get; set; }
public DefaultMessageManager(
IMessageEventHandler messageEventHandler,
IEnumerable<IMessagingChannel> channels) {
_messageEventHandler = messageEventHandler;
_channels = channels;
}
public void Send(ContentItemRecord recipient, string type, string service = null, Dictionary<string, string> properties = null) {
if ( !HasChannels() )
return;
var messageSettings = CurrentSite.As<MessageSettingsPart>().Record;
if ( messageSettings == null || String.IsNullOrWhiteSpace(messageSettings.DefaultChannelService) ) {
return;
}
Logger.Information("Sending message {0}", type);
try {
// if the service is not explicit, use the default one, as per settings configuration
if (String.IsNullOrWhiteSpace(service)) {
service = messageSettings.DefaultChannelService;
}
var context = new MessageContext {
Recipient = recipient,
Type = type,
Service = service
};
if ( properties != null ) {
foreach (var key in properties.Keys)
context.Properties.Add(key, properties[key]);
}
_messageEventHandler.Sending(context);
foreach ( var channel in _channels ) {
channel.SendMessage(context);
}
_messageEventHandler.Sent(context);
Logger.Information("Message {0} sent", type);
}
catch ( Exception e ) {
Logger.Error(e, "An error occured while sending the message {0}", type);
}
}
public bool HasChannels() {
return _channels.Any();
}
public IEnumerable<string> GetAvailableChannelServices() {
return _channels.SelectMany(c => c.GetAvailableServices());
}
}
}

View File

@@ -0,0 +1,9 @@
using Orchard.Core.Messaging.Models;
using System.Collections.Generic;
namespace Orchard.Core.Messaging.ViewModels {
public class ContentSubscriptionPartViewModel {
public MessageSettingsPart MessageSettings { get; set; }
public IEnumerable<string> ChannelServices { get; set; }
}
}

View File

@@ -0,0 +1,20 @@
<%@ Control Language="C#" Inherits="Orchard.Mvc.ViewUserControl<ContentSubscriptionPartViewModel>" %>
<%@ Import Namespace="Orchard.Core.Messaging.Models"%>
<%@ Import Namespace="Orchard.Core.Messaging.ViewModels"%>
<fieldset>
<legend><%: T("Messaging")%></legend>
<div>
<label for="<%: Html.FieldIdFor(m => m.MessageSettings.DefaultChannelService)%>"><%: T("Default channel service for messages")%></label>
<% if ( Model.ChannelServices.Any() ) { %>
<select id="<%:Html.FieldIdFor(m => m.MessageSettings.DefaultChannelService) %>" name="<%:Html.FieldNameFor(m => m.MessageSettings.DefaultChannelService) %>">
<% foreach ( var service in Model.ChannelServices ) {%>
<option <%: Model.MessageSettings.DefaultChannelService == service ? "selected=\"selected\"" : "" %> value="<%: service %>"><%: service%></option>
<% }
}
else {%>
<span class="hint"><%: T("You must enable a messaging channel (e.g., Orchard.Email) before being able to send messages.") %></span>
<% }%>
</select>
</div>
</fieldset>

View File

@@ -0,0 +1,34 @@
<?xml version="1.0"?>
<configuration>
<system.web>
<httpHandlers>
<add path="*" verb="*"
type="System.Web.HttpNotFoundHandler"/>
</httpHandlers>
<!--
Enabling request validation in view pages would cause validation to occur
after the input has already been processed by the controller. By default
MVC performs request validation before a controller processes the input.
To change this behavior apply the ValidateInputAttribute to a
controller or action.
-->
<pages
validateRequest="false"
pageParserFilterType="System.Web.Mvc.ViewTypeParserFilter, System.Web.Mvc, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"
pageBaseType="System.Web.Mvc.ViewPage, System.Web.Mvc, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"
userControlBaseType="System.Web.Mvc.ViewUserControl, System.Web.Mvc, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35">
<controls>
<add assembly="System.Web.Mvc, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" namespace="System.Web.Mvc" tagPrefix="mvc" />
</controls>
</pages>
</system.web>
<system.webServer>
<validation validateIntegratedModeConfiguration="false"/>
<handlers>
<remove name="BlockViewHandler"/>
<add name="BlockViewHandler" path="*" verb="*" preCondition="integratedMode" type="System.Web.HttpNotFoundHandler"/>
</handlers>
</system.webServer>
</configuration>

View File

@@ -80,8 +80,8 @@ namespace Orchard.Core.Navigation.Controllers {
if (!_services.Authorizer.Authorize(Permissions.ManageMainMenu, T("Couldn't manage the main menu")))
return new HttpUnauthorizedResult();
var menuPart = _services.ContentManager.New<MenuPart>(MenuItemPartDriver.ContentType.Name);
model.MenuItem = _services.ContentManager.UpdateEditorModel(menuPart, this);
var menuPart = _services.ContentManager.New<MenuPart>("MenuItem");
model.MenuItem = _services.ContentManager.UpdateEditorShape(menuPart, this);
if (!ModelState.IsValid) {
_services.TransactionManager.Cancel();

View File

@@ -6,32 +6,20 @@ using Orchard.Security;
namespace Orchard.Core.Navigation.Drivers {
[UsedImplicitly]
public class MenuItemPartDriver : ContentItemDriver<MenuItemPart> {
public class MenuItemPartDriver : ContentPartDriver<MenuItemPart> {
private readonly IAuthorizationService _authorizationService;
private readonly IWorkContextAccessor _workContextAccessor;
public readonly static ContentType ContentType = new ContentType {
Name = "MenuItem",
DisplayName = "Menu Item"
};
public MenuItemPartDriver(IAuthorizationService authorizationService) {
public MenuItemPartDriver(IAuthorizationService authorizationService, IWorkContextAccessor workContextAccessor) {
_authorizationService = authorizationService;
}
public virtual IUser CurrentUser { get; set; }
protected override ContentType GetContentType() {
return ContentType;
}
protected override string Prefix { get { return ""; } }
protected override string GetDisplayText(MenuItemPart itemPart) {
return itemPart.Url;
_workContextAccessor = workContextAccessor;
}
protected override DriverResult Editor(MenuItemPart itemPart, IUpdateModel updater) {
if (!_authorizationService.TryCheckAccess(Permissions.ManageMainMenu, CurrentUser, itemPart))
//todo: (heskew) need context
var currentUser = _workContextAccessor.GetContext().CurrentUser;
if (!_authorizationService.TryCheckAccess(Permissions.ManageMainMenu, currentUser, itemPart))
return null;
updater.TryUpdateModel(itemPart, Prefix, null, null);

View File

@@ -1,5 +1,4 @@
using JetBrains.Annotations;
using Orchard.Core.Navigation.Drivers;
using Orchard.Core.Navigation.Models;
using Orchard.Data;
using Orchard.ContentManagement.Handlers;
@@ -8,7 +7,7 @@ namespace Orchard.Core.Navigation.Handlers {
[UsedImplicitly]
public class MenuItemPartHandler : ContentHandler {
public MenuItemPartHandler(IRepository<MenuItemPartRecord> repository) {
Filters.Add(new ActivatingFilter<MenuItemPart>(MenuItemPartDriver.ContentType.Name));
Filters.Add(new ActivatingFilter<MenuItemPart>("MenuItem"));
Filters.Add(StorageFilter.For(repository));
}
}

View File

@@ -82,7 +82,6 @@
<Compile Include="Common\ViewModels\TextContentFieldDisplayViewModel.cs" />
<Compile Include="Common\ViewModels\TextContentFieldEditorViewModel.cs" />
<Compile Include="Contents\Controllers\ItemController.cs" />
<Compile Include="Contents\Drivers\ContentsDriver.cs" />
<Compile Include="Contents\Extensions\MetaDataExtensions.cs" />
<Compile Include="Contents\Handlers\ContentsHandler.cs" />
<Compile Include="Contents\Permissions.cs" />
@@ -91,6 +90,13 @@
<Compile Include="Contents\Settings\ContentPartSettings.cs" />
<Compile Include="Contents\ViewModels\PublishContentViewModel.cs" />
<Compile Include="Localization\ViewModels\EditLocalizationViewModel.cs" />
<Compile Include="Messaging\DataMigrations\MessagingDataMigration.cs" />
<Compile Include="Messaging\Drivers\MessageSettingsPartDriver.cs" />
<Compile Include="Messaging\Handlers\MessageSettingsPartHandler.cs" />
<Compile Include="Messaging\Models\MessageSettingsPart.cs" />
<Compile Include="Messaging\Models\MessageSettingsPartRecord.cs" />
<Compile Include="Messaging\Services\DefaultMessageManager.cs" />
<Compile Include="Messaging\ViewModels\MessageSettingsPartViewModel.cs" />
<Compile Include="PublishLater\DataMigrations\PublishLaterDataMigration.cs" />
<Compile Include="PublishLater\Drivers\PublishLaterPartDriver.cs" />
<Compile Include="PublishLater\Models\PublishLaterPart.cs" />
@@ -196,7 +202,6 @@
<Compile Include="Scheduling\Models\Task.cs" />
<Compile Include="Settings\DataMigrations\SettingsDataMigration.cs" />
<Compile Include="Settings\ViewModels\SiteCulturesViewModel.cs" />
<Compile Include="Settings\Drivers\SiteSettingsPartDriver.cs" />
<Compile Include="Settings\Metadata\ContentDefinitionManager.cs" />
<Compile Include="Settings\Metadata\Records\ContentFieldDefinitionRecord.cs" />
<Compile Include="Settings\Metadata\Records\ContentPartDefinitionRecord.cs" />
@@ -248,6 +253,8 @@
<Content Include="Contents\Views\DisplayTemplates\Parts\Contents.Publish.SummaryAdmin.ascx" />
<Content Include="Contents\Views\DisplayTemplates\Parts\Contents.Publish.ascx" />
<Content Include="Localization\Views\EditorTemplates\Parts\Localization.Translation.ascx" />
<Content Include="Messaging\Module.txt" />
<Content Include="Messaging\Views\EditorTemplates\Parts\Messaging.MessageSettings.ascx" />
<Content Include="PublishLater\Content\Admin\images\draft.gif" />
<Content Include="PublishLater\Content\Admin\images\offline.gif" />
<Content Include="PublishLater\Content\Admin\images\online.gif" />
@@ -366,6 +373,7 @@
<Content Include="Reports\Views\Web.config" />
<Content Include="PublishLater\Views\Web.config" />
<Content Include="ContentsLocation\Views\Web.config" />
<Content Include="Messaging\Views\Web.config" />
<None Include="Contents\Views\Content.cshtml" />
<None Include="Contents\Views\Item\Display.cshtml" />
</ItemGroup>

View File

@@ -40,7 +40,7 @@ namespace Orchard.Core.Routable.Controllers {
throw new ApplicationException("Ambiguous content");
}
var model = new RoutableDisplayViewModel {
Routable = _contentManager.BuildDisplayModel<IRoutableAspect>(hits.Single(), "Detail")
Routable = _contentManager.BuildDisplayShape<IRoutableAspect>(hits.Single(), "Detail")
};
PrepareDisplayViewModel(model.Routable);
return View("Display", model);
@@ -71,7 +71,7 @@ namespace Orchard.Core.Routable.Controllers {
}
}
_contentManager.UpdateEditorModel(contentItem, this);
_contentManager.UpdateEditorShape(contentItem, this);
_transactionManager.Cancel();
return Json(contentItem.As<IRoutableAspect>().Slug ?? slug);

View File

@@ -37,7 +37,7 @@ namespace Orchard.Core.Routable.Services {
return new NotFoundResult();
var model = new RoutableDisplayViewModel {
Routable = _contentManager.BuildDisplayModel<IRoutableAspect>(contentItem.As<RoutePart>(), "Detail")
Routable = _contentManager.BuildDisplayShape<IRoutableAspect>(contentItem.As<RoutePart>(), "Detail")
};
return new ViewResult {

View File

@@ -33,7 +33,7 @@ namespace Orchard.Core.Settings.Controllers {
Site = _siteService.GetSiteSettings().As<SiteSettingsPart>(),
SiteCultures = _cultureManager.ListCultures()
};
model.ViewModel = Services.ContentManager.BuildEditorModel(model.Site);
model.ViewModel = Services.ContentManager.BuildEditorShape(model.Site);
return View(model);
}
@@ -43,7 +43,7 @@ namespace Orchard.Core.Settings.Controllers {
return new HttpUnauthorizedResult();
var viewModel = new SettingsIndexViewModel { Site = _siteService.GetSiteSettings().As<SiteSettingsPart>() };
viewModel.ViewModel = Services.ContentManager.UpdateEditorModel(viewModel.Site.ContentItem, this);
viewModel.ViewModel = Services.ContentManager.UpdateEditorShape(viewModel.Site.ContentItem, this);
if (!TryUpdateModel(viewModel)) {
return View(viewModel);

View File

@@ -1,20 +0,0 @@
using JetBrains.Annotations;
using Orchard.ContentManagement;
using Orchard.ContentManagement.Drivers;
using Orchard.Core.Settings.Models;
namespace Orchard.Core.Settings.Drivers {
[UsedImplicitly]
public class SiteSettingsPartDriver : ContentItemDriver<SiteSettingsPart> {
protected override ContentType GetContentType() {
return SiteSettingsPart.ContentType;
}
protected override DriverResult Editor(SiteSettingsPart part) {
return ContentItemTemplate("Items/Settings.Site");
}
protected override DriverResult Editor(SiteSettingsPart part, IUpdateModel updater) {
return ContentItemTemplate("Items/Settings.Site");
}
}
}

View File

@@ -34,8 +34,8 @@ namespace Orchard.DevTools.Controllers {
.Select(x => x.GetType())
.SelectMany(x => AllTypes(x))
.Distinct();
model.DisplayModel = _contentManager.BuildDisplayModel(model.Item, "Detail");
model.EditorModel = _contentManager.BuildEditorModel(model.Item);
model.DisplayModel = _contentManager.BuildDisplayShape(model.Item, "Detail");
model.EditorModel = _contentManager.BuildEditorShape(model.Item);
return View(model);
}

View File

@@ -6,12 +6,12 @@ using Orchard.DevTools.Models;
namespace Orchard.DevTools.Handlers {
[UsedImplicitly]
public class DebugLinkHandler : ContentHandler {
protected override void BuildDisplayModel(BuildDisplayModelContext context) {
protected override void BuildDisplayShape(BuildDisplayModelContext context) {
var devToolsSettings = context.ContentItem.TypeDefinition.Settings.GetModel<Settings.DevToolsSettings>();
if (devToolsSettings.ShowDebugLinks)
context.AddDisplay(new TemplateViewModel(new ShowDebugLink { ContentItem = context.ContentItem }) { TemplateName = "Parts/DevTools.ShowDebugLink", ZoneName = "recap", Position = "9999" });
}
protected override void BuildEditorModel(BuildEditorModelContext context) {
protected override void BuildEditorShape(BuildEditorModelContext context) {
var devToolsSettings = context.ContentItem.TypeDefinition.Settings.GetModel<Settings.DevToolsSettings>();
if (devToolsSettings.ShowDebugLinks)
context.AddEditor(new TemplateViewModel(new ShowDebugLink { ContentItem = context.ContentItem }) { TemplateName = "Parts/DevTools.ShowDebugLink", ZoneName = "recap", Position = "9999" });

View File

@@ -0,0 +1,22 @@
using Orchard.Data.Migration;
namespace Orchard.Email.DataMigrations {
public class EmailDataMigration : DataMigrationImpl {
public int Create() {
SchemaBuilder.CreateTable("SmtpSettingsPartRecord", table => table
.ContentPartRecord()
.Column<string>("Address")
.Column<string>("Host")
.Column<int>("Port")
.Column<bool>("EnableSsl")
.Column<bool>("RequireCredentials")
.Column<string>("UserName")
.Column<string>("Password")
);
return 1;
}
}
}

View File

@@ -0,0 +1,29 @@
using Orchard.ContentManagement;
using Orchard.ContentManagement.Drivers;
using Orchard.Email.Models;
using Orchard.Localization;
namespace Orchard.Email.Drivers {
// We define a specific driver instead of using a TemplateFilterForRecord, because we need the ;odel to be the part and not the record.
// Thus the encryption/decryption will be done when accessing the part's property
public class SmtpSettingsPartDriver : ContentPartDriver<SmtpSettingsPart> {
public SmtpSettingsPartDriver() {
T = NullLocalizer.Instance;
}
public Localizer T { get; set; }
protected override string Prefix { get { return "SmtpSettings"; } }
protected override DriverResult Editor(SmtpSettingsPart termPart) {
return ContentPartTemplate(termPart, "Parts/Smtp.SiteSettings");
}
protected override DriverResult Editor(SmtpSettingsPart termPart, IUpdateModel updater) {
updater.TryUpdateModel(termPart, Prefix, null, null);
return Editor(termPart);
}
}
}

View File

@@ -0,0 +1,14 @@
using JetBrains.Annotations;
using Orchard.Email.Models;
using Orchard.Data;
using Orchard.ContentManagement.Handlers;
namespace Orchard.Email.Handlers {
[UsedImplicitly]
public class SmtpSettingsPartHandler : ContentHandler {
public SmtpSettingsPartHandler(IRepository<SmtpSettingsPartRecord> repository) {
Filters.Add(new ActivatingFilter<SmtpSettingsPart>("Site"));
Filters.Add(StorageFilter.For(repository));
}
}
}

View File

@@ -0,0 +1,49 @@
using System.Text;
using System.Web.Security;
using Orchard.ContentManagement;
using System;
namespace Orchard.Email.Models {
public class SmtpSettingsPart : ContentPart<SmtpSettingsPartRecord> {
public bool IsValid() {
return !String.IsNullOrWhiteSpace(Record.Host)
&& Record.Port > 0
&& !String.IsNullOrWhiteSpace(Record.Address);
}
public string Address {
get { return Record.Address; }
set { Record.Address = value; }
}
public string Host {
get { return Record.Host; }
set { Record.Host = value; }
}
public int Port {
get { return Record.Port; }
set { Record.Port = value; }
}
public bool EnableSsl {
get { return Record.EnableSsl; }
set { Record.EnableSsl = value; }
}
public bool RequireCredentials {
get { return Record.RequireCredentials; }
set { Record.RequireCredentials = value; }
}
public string UserName {
get { return Record.UserName; }
set { Record.UserName = value; }
}
public string Password {
get { return String.IsNullOrWhiteSpace(Record.Password) ? String.Empty : Encoding.UTF8.GetString(MachineKey.Decode(Record.Password, MachineKeyProtection.All)); ; }
set { Record.Password = String.IsNullOrWhiteSpace(value) ? String.Empty : MachineKey.Encode(Encoding.UTF8.GetBytes(value), MachineKeyProtection.All); }
}
}
}

View File

@@ -0,0 +1,48 @@
using System.Net.Mail;
using Orchard.ContentManagement.Records;
using System.ComponentModel.DataAnnotations;
namespace Orchard.Email.Models {
public class SmtpSettingsPartRecord : ContentPartRecord {
/// <summary>
/// From address in the mail message
/// </summary>
public virtual string Address { get; set; }
/// <summary>
/// Server name hosting the SMTP service
/// </summary>
public virtual string Host { get; set; }
/// <summary>
/// Port number on which SMTP service runs
/// </summary>
public virtual int Port { get; set; }
/// <summary>
/// Whether to enable SSL communications with the server
/// </summary>
public virtual bool EnableSsl { get; set; }
/// <summary>
/// Whether specific credentials should be used
/// </summary>
public virtual bool RequireCredentials { get; set; }
/// <summary>
/// The username to connect to the SMTP server if DefaultCredentials is False
/// </summary>
public virtual string UserName { get; set; }
/// <summary>
/// The password to connect to the SMTP server if DefaultCredentials is False
/// </summary>
public virtual string Password { get; set; }
public SmtpSettingsPartRecord() {
Port = 25;
RequireCredentials = false;
EnableSsl = false;
}
}
}

View File

@@ -0,0 +1,12 @@
Name: Email Messaging
antiforgery: enabled
author: The Orchard Team
website: http://orchardproject.net
version: 0.1.0
orchardversion: 0.6.0
description: The Email Messaging module adds Email sending functionalities.
features:
Orchard.Email:
Description: Email Messaging services.
Category: Messaging
Dependencies: Messaging

View File

@@ -0,0 +1,142 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>9.0.30729</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{05660F47-D649-48BD-9DED-DF4E01E7CFF9}</ProjectGuid>
<ProjectTypeGuids>{F85E285D-A4E0-4152-9332-AB1D724D3325};{349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc}</ProjectTypeGuids>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Orchard.Email</RootNamespace>
<AssemblyName>Orchard.Email</AssemblyName>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<MvcBuildViews>false</MvcBuildViews>
<FileUpgradeFlags>
</FileUpgradeFlags>
<OldToolsVersion>3.5</OldToolsVersion>
<UpgradeBackupLocation />
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Data" />
<Reference Include="System.ComponentModel.DataAnnotations">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="System.Web.ApplicationServices" />
<Reference Include="System.Web.DynamicData" />
<Reference Include="System.Web.Entity" />
<Reference Include="System.Web.Extensions" />
<Reference Include="System.Web.Mvc, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\..\lib\aspnetmvc\System.Web.Mvc.dll</HintPath>
</Reference>
<Reference Include="System.Drawing" />
<Reference Include="System.Web" />
<Reference Include="System.Web.Abstractions" />
<Reference Include="System.Web.Routing" />
<Reference Include="System.Xml" />
<Reference Include="System.Configuration" />
<Reference Include="System.Web.Services" />
<Reference Include="System.EnterpriseServices" />
<Reference Include="System.Web.Mobile" />
<Reference Include="System.Xml.Linq" />
</ItemGroup>
<ItemGroup>
<Compile Include="DataMigrations\EmailDataMigration.cs" />
<Compile Include="Drivers\SmtpSettingsPartDriver.cs" />
<Compile Include="Handlers\SmtpSettingsPartHandler.cs" />
<Compile Include="Models\SmtpSettingsPart.cs" />
<Compile Include="Models\SmtpSettingsPartRecord.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Services\EmailMessageEventHandler.cs" />
<Compile Include="Services\EmailMessagingChannel.cs" />
<Compile Include="Services\MissingSettingsBanner.cs" />
</ItemGroup>
<ItemGroup>
<Content Include="Module.txt" />
<Content Include="Views\EditorTemplates\Parts\Smtp.SiteSettings.ascx" />
<Content Include="Web.config" />
<Content Include="Views\Web.config" />
</ItemGroup>
<ItemGroup />
<ItemGroup>
<ProjectReference Include="..\..\..\Orchard\Orchard.Framework.csproj">
<Project>{2D1D92BB-4555-4CBE-8D0E-63563D6CE4C6}</Project>
<Name>Orchard.Framework</Name>
</ProjectReference>
<ProjectReference Include="..\..\Core\Orchard.Core.csproj">
<Project>{9916839C-39FC-4CEB-A5AF-89CA7E87119F}</Project>
<Name>Orchard.Core</Name>
</ProjectReference>
<ProjectReference Include="..\Orchard.Users\Orchard.Users.csproj">
<Project>{79AED36E-ABD0-4747-93D3-8722B042454B}</Project>
<Name>Orchard.Users</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v10.0\WebApplications\Microsoft.WebApplication.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target> -->
<!-- To enable MVC area subproject support, uncomment the following two lines:
<UsingTask TaskName="Microsoft.Web.Mvc.Build.CreateAreaManifest" AssemblyName="Microsoft.Web.Mvc.Build, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
<UsingTask TaskName="Microsoft.Web.Mvc.Build.CopyAreaManifests" AssemblyName="Microsoft.Web.Mvc.Build, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
-->
<Target Name="AfterBuild" DependsOnTargets="AfterBuildCompiler">
<PropertyGroup>
<AreasManifestDir>$(ProjectDir)\..\Manifests</AreasManifestDir>
</PropertyGroup>
<!-- If this is an area child project, uncomment the following line:
<CreateAreaManifest AreaName="$(AssemblyName)" AreaType="Child" AreaPath="$(ProjectDir)" ManifestPath="$(AreasManifestDir)" ContentFiles="@(Content)" />
-->
<!-- If this is an area parent project, uncomment the following lines:
<CreateAreaManifest AreaName="$(AssemblyName)" AreaType="Parent" AreaPath="$(ProjectDir)" ManifestPath="$(AreasManifestDir)" ContentFiles="@(Content)" />
<CopyAreaManifests ManifestPath="$(AreasManifestDir)" CrossCopy="false" RenameViews="true" />
-->
</Target>
<Target Name="AfterBuildCompiler" Condition="'$(MvcBuildViews)'=='true'">
<AspNetCompiler VirtualPath="temp" PhysicalPath="$(ProjectDir)\..\$(ProjectName)" />
</Target>
<ProjectExtensions>
<VisualStudio>
<FlavorProperties GUID="{349c5851-65df-11da-9384-00065b846f21}">
<WebProjectProperties>
<UseIIS>False</UseIIS>
<AutoAssignPort>True</AutoAssignPort>
<DevelopmentServerPort>45979</DevelopmentServerPort>
<DevelopmentServerVPath>/</DevelopmentServerVPath>
<IISUrl>
</IISUrl>
<NTLMAuthentication>False</NTLMAuthentication>
<UseCustomServer>True</UseCustomServer>
<CustomServerUrl>http://orchard.codeplex.com</CustomServerUrl>
<SaveServerSettingsInUserFile>False</SaveServerSettingsInUserFile>
</WebProjectProperties>
</FlavorProperties>
</VisualStudio>
</ProjectExtensions>
</Project>

View File

@@ -0,0 +1,35 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("Orchard.Messaging.Email")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Orchard")]
[assembly: AssemblyCopyright("Copyright © CodePlex Foundation 2009")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("9c778ece-c759-47fb-95b6-e73c03d9e969")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Revision and Build Numbers
// by using the '*' as shown below:
[assembly: AssemblyVersion("0.5.0")]
[assembly: AssemblyFileVersion("0.5.0")]

View File

@@ -0,0 +1,29 @@
using Orchard.Messaging.Events;
using Orchard.ContentManagement;
using Orchard.Users.Models;
using Orchard.Messaging.Models;
namespace Orchard.Email.Services {
public class EmailMessageEventHandler : IMessageEventHandler {
private readonly IContentManager _contentManager;
public EmailMessageEventHandler(IContentManager contentManager) {
_contentManager = contentManager;
}
public void Sending(MessageContext context) {
var contentItem = _contentManager.Get(context.Recipient.Id);
if ( contentItem == null )
return;
var recipient = contentItem.As<UserPart>();
if ( recipient == null )
return;
context.MailMessage.To.Add(recipient.Email);
}
public void Sent(MessageContext context) {
}
}
}

View File

@@ -0,0 +1,71 @@
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Mail;
using JetBrains.Annotations;
using Orchard.ContentManagement;
using Orchard.Localization;
using Orchard.Logging;
using Orchard.Email.Models;
using Orchard.Settings;
using Orchard.Messaging.Services;
using Orchard.Messaging.Models;
namespace Orchard.Email.Services {
public class EmailMessagingChannel : IMessagingChannel {
public const string EmailService = "Email";
public EmailMessagingChannel() {
Logger = NullLogger.Instance;
}
protected virtual ISite CurrentSite { get; [UsedImplicitly] private set; }
public ILogger Logger { get; set; }
public Localizer T { get; set; }
public void SendMessage(MessageContext context) {
if ( !context.Service.Equals(EmailService, StringComparison.InvariantCultureIgnoreCase) )
return;
var smtpSettings = CurrentSite.As<SmtpSettingsPart>();
// can't process emails if the Smtp settings have not yet been set
if ( smtpSettings == null || !smtpSettings.IsValid() ) {
return;
}
var smtpClient = new SmtpClient { UseDefaultCredentials = !smtpSettings.RequireCredentials };
if ( !smtpClient.UseDefaultCredentials && !String.IsNullOrWhiteSpace(smtpSettings.UserName) ) {
smtpClient.Credentials = new NetworkCredential(smtpSettings.UserName, smtpSettings.Password);
}
if(context.MailMessage.To.Count == 0) {
Logger.Error("Recipient is missing an email address");
return;
}
if ( smtpSettings.Host != null )
smtpClient.Host = smtpSettings.Host;
smtpClient.Port = smtpSettings.Port;
smtpClient.EnableSsl = smtpSettings.EnableSsl;
smtpClient.DeliveryMethod = SmtpDeliveryMethod.Network;
context.MailMessage.From = new MailAddress(smtpSettings.Address);
context.MailMessage.IsBodyHtml = context.MailMessage.Body != null && context.MailMessage.Body.Contains("<") && context.MailMessage.Body.Contains(">");
try {
smtpClient.Send(context.MailMessage);
Logger.Debug("Message sent to {0}: {1}", context.MailMessage.To[0].Address, context.Type);
}
catch(Exception e) {
Logger.Error(e, "An unexpected error while sending a message to {0}: {1}", context.MailMessage.To[0].Address, context.Type);
}
}
public IEnumerable<string> GetAvailableServices() {
return new[] {EmailService};
}
}
}

View File

@@ -0,0 +1,37 @@
using System;
using System.Collections.Generic;
using JetBrains.Annotations;
using Orchard.ContentManagement;
using Orchard.Core.Messaging.Models;
using Orchard.Localization;
using Orchard.Email.Models;
using Orchard.Settings;
using Orchard.UI.Admin.Notification;
using Orchard.UI.Notify;
namespace Orchard.Email.Services {
public class MissingSettingsBanner: INotificationProvider {
public MissingSettingsBanner() {
T = NullLocalizer.Instance;
}
protected virtual ISite CurrentSite { get; [UsedImplicitly] private set; }
public Localizer T { get; set; }
public IEnumerable<NotifyEntry> GetNotifications() {
var smtpSettings = CurrentSite.As<SmtpSettingsPart>();
if ( smtpSettings == null || !smtpSettings.IsValid() ) {
yield return new NotifyEntry { Message = T("The SMTP settings needs to be configured." ), Type = NotifyType.Warning};
}
var messageSettings = CurrentSite.As<MessageSettingsPart>().Record;
if ( messageSettings == null || String.IsNullOrWhiteSpace(messageSettings.DefaultChannelService) ) {
yield return new NotifyEntry { Message = T("The default channel service needs to be configured."), Type = NotifyType.Warning };
}
}
}
}

View File

@@ -0,0 +1,43 @@
<%@ Control Language="C#" Inherits="Orchard.Mvc.ViewUserControl<SmtpSettingsPart>" %>
<%@ Import Namespace="Orchard.Email.Models"%>
<%@ Import Namespace="System.Net.Mail" %>
<fieldset>
<legend><%: T("SMTP")%></legend>
<div>
<label for="<%: Html.FieldIdFor(m => m.Address)%>"><%: T("Sender email address")%></label>
<%: Html.EditorFor(m => m.Address)%>
<%: Html.ValidationMessage("Address", "*")%>
</div>
<div>
<label for="<%: Html.FieldIdFor(m => m.Host)%>"><%: T("Host name")%></label>
<%: Html.EditorFor(m => m.Host)%>
<%: Html.ValidationMessage("Host", "*")%>
</div>
<div>
<label for="<%: Html.FieldIdFor(m => m.Port)%>"><%: T("Port number")%></label>
<%: Html.EditorFor(m => m.Port)%>
<%: Html.ValidationMessage("Port", "*")%>
</div>
<div>
<%: Html.EditorFor(m => m.EnableSsl)%>
<label for="<%: Html.FieldIdFor(m => m.EnableSsl)%>" class="forcheckbox"><%: T("Enable SSL communications")%></label>
<%: Html.ValidationMessage("EnableSsl", "*")%>
</div>
<div>
<%: Html.EditorFor(m => m.RequireCredentials)%>
<label for="<%: Html.FieldIdFor(m => m.RequireCredentials)%>" class="forcheckbox"><%: T("Require credentials")%></label>
<%: Html.ValidationMessage("RequireCredentials", "*")%>
</div>
<div data-controllerid="<%: Html.FieldIdFor(m => m.RequireCredentials)%>">
<div>
<label for="<%: Html.FieldIdFor(m => m.UserName)%>"><%: T("User name")%></label>
<%: Html.EditorFor(m => m.UserName)%>
<%: Html.ValidationMessage("UserName", "*")%>
</div>
<div>
<label for="<%: Html.FieldIdFor(m => m.Password)%>"><%: T("Password")%></label>
<%: Html.PasswordFor(m => m.Password)%>
<%: Html.ValidationMessage("Password", "*")%>
</div>
</div>
</fieldset>

View File

@@ -0,0 +1,34 @@
<?xml version="1.0"?>
<configuration>
<system.web>
<httpHandlers>
<add path="*" verb="*"
type="System.Web.HttpNotFoundHandler"/>
</httpHandlers>
<!--
Enabling request validation in view pages would cause validation to occur
after the input has already been processed by the controller. By default
MVC performs request validation before a controller processes the input.
To change this behavior apply the ValidateInputAttribute to a
controller or action.
-->
<pages
validateRequest="false"
pageParserFilterType="System.Web.Mvc.ViewTypeParserFilter, System.Web.Mvc, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"
pageBaseType="System.Web.Mvc.ViewPage, System.Web.Mvc, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"
userControlBaseType="System.Web.Mvc.ViewUserControl, System.Web.Mvc, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35">
<controls>
<add assembly="System.Web.Mvc, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" namespace="System.Web.Mvc" tagPrefix="mvc" />
</controls>
</pages>
</system.web>
<system.webServer>
<validation validateIntegratedModeConfiguration="false"/>
<handlers>
<remove name="BlockViewHandler"/>
<add name="BlockViewHandler" path="*" verb="*" preCondition="integratedMode" type="System.Web.HttpNotFoundHandler"/>
</handlers>
</system.webServer>
</configuration>

View File

@@ -0,0 +1,22 @@
<?xml version="1.0"?>
<configuration>
<system.web>
<compilation debug="true" targetFramework="4.0">
<assemblies>
<add assembly="System.Web.Mvc, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
</assemblies>
</compilation>
<pages controlRenderingCompatibilityVersion="3.5" clientIDMode="AutoID">
<namespaces>
<add namespace="System.Web.Mvc"/>
<add namespace="System.Web.Mvc.Ajax"/>
<add namespace="System.Web.Mvc.Html"/>
<add namespace="System.Web.Routing"/>
<add namespace="System.Linq"/>
<add namespace="System.Collections.Generic"/>
<add namespace="Orchard.Mvc.Html"/>
</namespaces>
</pages>
</system.web>
<system.web.extensions/>
</configuration>

View File

@@ -1,5 +1,9 @@
using System;
using System.Configuration;
using System.Security.Cryptography;
using System.Web.Configuration;
using System.Web.Mvc;
using System.Linq;
using Orchard.FileSystems.AppData;
using Orchard.Setup.Services;
using Orchard.Setup.ViewModels;
@@ -34,7 +38,34 @@ namespace Orchard.Setup.Controllers {
return View(model);
}
private bool ValidateMachineKey() {
// Get the machineKey section.
var section = ConfigurationManager.GetSection("system.web/machineKey") as MachineKeySection;
if (section == null
|| section.DecryptionKey.Contains("AutoGenerate")
|| section.ValidationKey.Contains("AutoGenerate")) {
var rng = new RNGCryptoServiceProvider();
var decryptionData = new byte[32];
var validationData = new byte[64];
rng.GetBytes(decryptionData);
rng.GetBytes(validationData);
string decryptionKey = BitConverter.ToString(decryptionData).Replace("-", "");
string validationKey = BitConverter.ToString(validationData).Replace("-", "");
ModelState.AddModelError("MachineKey", T("You need to define a MachineKey value in your web.config file. Here is one for you:\n <machineKey validationKey=\"{0}\" decryptionKey=\"{1}\" validation=\"SHA1\" decryption=\"AES\" />", validationKey, decryptionKey).ToString());
return false;
}
return true;
}
public ActionResult Index() {
ValidateMachineKey();
var initialSettings = _setupService.Prime();
return IndexViewResult(new SetupViewModel { AdminUsername = "admin", DatabaseIsPreconfigured = !string.IsNullOrEmpty(initialSettings.DataProvider)});
}
@@ -49,6 +80,8 @@ namespace Orchard.Setup.Controllers {
ModelState.AddModelError("ConfirmPassword", T("Password confirmation must match").ToString());
}
ValidateMachineKey();
if (!ModelState.IsValid) {
return IndexViewResult(model);
}

View File

@@ -77,6 +77,7 @@ namespace Orchard.Setup.Services {
"Routable",
"Settings",
//"XmlRpc",
"Messaging",
"Orchard.Users",
"Orchard.Roles",
//"TinyMce",

Binary file not shown.

After

Width:  |  Height:  |  Size: 603 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

@@ -9,6 +9,11 @@ using Orchard.Mvc.Extensions;
using Orchard.Security;
using Orchard.Users.Services;
using Orchard.Users.ViewModels;
using Orchard.Settings;
using JetBrains.Annotations;
using Orchard.ContentManagement;
using Orchard.Users.Models;
using Orchard.Mvc.Results;
namespace Orchard.Users.Controllers {
[HandleError]
@@ -30,6 +35,7 @@ namespace Orchard.Users.Controllers {
public ILogger Logger { get; set; }
public Localizer T { get; set; }
protected virtual ISite CurrentSite { get; [UsedImplicitly] private set; }
public ActionResult AccessDenied() {
var returnUrl = Request.QueryString["ReturnUrl"];
@@ -86,6 +92,12 @@ namespace Orchard.Users.Controllers {
}
public ActionResult Register() {
// ensure users can register
var registrationSettings = CurrentSite.As<RegistrationSettingsPart>();
if ( !registrationSettings.UsersCanRegister ) {
return new NotFoundResult();
}
ViewData["PasswordLength"] = MinPasswordLength;
return View();
@@ -93,14 +105,26 @@ namespace Orchard.Users.Controllers {
[HttpPost]
public ActionResult Register(string userName, string email, string password, string confirmPassword) {
// ensure users can register
var registrationSettings = CurrentSite.As<RegistrationSettingsPart>();
if ( !registrationSettings.UsersCanRegister ) {
return new NotFoundResult();
}
ViewData["PasswordLength"] = MinPasswordLength;
if (ValidateRegistration(userName, email, password, confirmPassword)) {
// Attempt to register the user
var user = _membershipService.CreateUser(new CreateUserParams(userName, password, email, null, null, true));
var user = _membershipService.CreateUser(new CreateUserParams(userName, password, email, null, null, false));
if (user != null) {
if ( user.As<UserPart>().EmailStatus == UserStatus.Pending ) {
string challengeToken = _membershipService.GetEncryptedChallengeToken(user.As<UserPart>());
_membershipService.SendChallengeEmail(user.As<UserPart>(), Url.AbsoluteAction(() => Url.Action("ChallengeEmail", "Account", new { Area = "Orchard.Users", token = challengeToken })));
return RedirectToAction("ChallengeEmailSent");
}
_authenticationService.SignIn(user, false /* createPersistentCookie */);
return Redirect("~/");
}
@@ -154,6 +178,29 @@ namespace Orchard.Users.Controllers {
return View();
}
public ActionResult ChallengeEmailSent() {
return View();
}
public ActionResult ChallengeEmailSuccess() {
return View();
}
public ActionResult ChallengeEmailFail() {
return View();
}
public ActionResult ChallengeEmail(string token) {
var user = _membershipService.ValidateChallengeToken(token);
if ( user != null ) {
_authenticationService.SignIn(user, false /* createPersistentCookie */);
return RedirectToAction("ChallengeEmailSuccess");
}
return RedirectToAction("ChallengeEmailFail");
}
protected override void OnActionExecuting(ActionExecutingContext filterContext) {
if (filterContext.HttpContext.User.Identity is WindowsIdentity) {
throw new InvalidOperationException("Windows authentication is not supported.");

View File

@@ -1,13 +1,15 @@
using System.Linq;
using System.Web.Mvc;
using JetBrains.Annotations;
using Orchard.ContentManagement;
using Orchard.Localization;
using Orchard.Security;
using Orchard.Settings;
using Orchard.UI.Notify;
using Orchard.Users.Drivers;
using Orchard.Users.Models;
using Orchard.Users.Services;
using Orchard.Users.ViewModels;
using Orchard.Mvc.Extensions;
namespace Orchard.Users.Controllers {
[ValidateInput(false)]
@@ -27,6 +29,7 @@ namespace Orchard.Users.Controllers {
public IOrchardServices Services { get; set; }
public Localizer T { get; set; }
protected virtual ISite CurrentSite { get; [UsedImplicitly] private set; }
public ActionResult Index() {
if (!Services.Authorizer.Authorize(Permissions.ManageUsers, T("Not authorized to list users")))
@@ -50,9 +53,9 @@ namespace Orchard.Users.Controllers {
if (!Services.Authorizer.Authorize(Permissions.ManageUsers, T("Not authorized to manage users")))
return new HttpUnauthorizedResult();
var user = Services.ContentManager.New<IUser>(UserPartDriver.ContentType.Name);
var user = Services.ContentManager.New<IUser>("User");
var model = new UserCreateViewModel {
User = Services.ContentManager.BuildEditorModel(user)
User = Services.ContentManager.BuildEditorShape(user)
};
return View(model);
}
@@ -62,8 +65,8 @@ namespace Orchard.Users.Controllers {
if (!Services.Authorizer.Authorize(Permissions.ManageUsers, T("Not authorized to manage users")))
return new HttpUnauthorizedResult();
var user = Services.ContentManager.New<IUser>(UserPartDriver.ContentType.Name);
model.User = Services.ContentManager.UpdateEditorModel(user, this);
var user = Services.ContentManager.New<IUser>("User");
model.User = Services.ContentManager.UpdateEditorShape(user, this);
if (!ModelState.IsValid) {
Services.TransactionManager.Cancel();
return View(model);
@@ -84,7 +87,7 @@ namespace Orchard.Users.Controllers {
model.Email,
null, null, true));
model.User = Services.ContentManager.UpdateEditorModel(user, this);
model.User = Services.ContentManager.UpdateEditorShape(user, this);
if (ModelState.IsValid == false) {
Services.TransactionManager.Cancel();
@@ -99,7 +102,7 @@ namespace Orchard.Users.Controllers {
return new HttpUnauthorizedResult();
return View(new UserEditViewModel {
User = Services.ContentManager.BuildEditorModel<UserPart>(id)
User = Services.ContentManager.BuildEditorShape<UserPart>(id)
});
}
@@ -109,7 +112,7 @@ namespace Orchard.Users.Controllers {
return new HttpUnauthorizedResult();
var model = new UserEditViewModel {
User = Services.ContentManager.UpdateEditorModel<UserPart>(id, this)
User = Services.ContentManager.UpdateEditorShape<UserPart>(id, this)
};
TryUpdateModel(model);
@@ -145,6 +148,55 @@ namespace Orchard.Users.Controllers {
return RedirectToAction("Index");
}
public ActionResult SendChallengeEmail(int id) {
if ( !Services.Authorizer.Authorize(Permissions.ManageUsers, T("Not authorized to manage users")) )
return new HttpUnauthorizedResult();
var user = Services.ContentManager.Get(id);
if ( user != null ) {
string challengeToken = _membershipService.GetEncryptedChallengeToken(user.As<UserPart>());
_membershipService.SendChallengeEmail(user.As<UserPart>(), Url.AbsoluteAction(() => Url.Action("ChallengeEmail", "Account", new {Area = "Orchard.Users", token = challengeToken})));
}
Services.Notifier.Information(T("Challenge email sent"));
return RedirectToAction("Index");
}
public ActionResult Approve(int id) {
if ( !Services.Authorizer.Authorize(Permissions.ManageUsers, T("Not authorized to manage users")) )
return new HttpUnauthorizedResult();
var user = Services.ContentManager.Get(id);
if ( user != null ) {
user.As<UserPart>().RegistrationStatus = UserStatus.Approved;
Services.Notifier.Information(T("User approved"));
}
return RedirectToAction("Index");
}
public ActionResult Moderate(int id) {
if ( !Services.Authorizer.Authorize(Permissions.ManageUsers, T("Not authorized to manage users")) )
return new HttpUnauthorizedResult();
var user = Services.ContentManager.Get(id);
if ( user != null ) {
if ( CurrentSite.SuperUser.Equals(user.As<UserPart>().UserName) ) {
Services.Notifier.Error(T("Super user can't be moderated"));
}
else {
user.As<UserPart>().RegistrationStatus = UserStatus.Pending;
Services.Notifier.Information(T("User moderated"));
}
}
return RedirectToAction("Index");
}
bool IUpdateModel.TryUpdateModel<TModel>(TModel model, string prefix, string[] includeProperties, string[] excludeProperties) {
return TryUpdateModel(model, prefix, includeProperties, excludeProperties);
}

View File

@@ -18,5 +18,25 @@ namespace Orchard.Users.DataMigrations {
return 1;
}
public int UpdateFrom1() {
// Adds registration fields to previous versions
SchemaBuilder
.AlterTable("UserPartRecord", table => table.AddColumn<string>("RegistrationStatus", c => c.WithDefault("'Approved'")))
.AlterTable("UserPartRecord", table => table.AddColumn<string>("EmailStatus", c => c.WithDefault("'Approved'")))
.AlterTable("UserPartRecord", table => table.AddColumn<string>("EmailChallengeToken"));
// Site Settings record
SchemaBuilder.CreateTable("RegistrationSettingsPartRecord", table => table
.ContentPartRecord()
.Column<bool>("UsersCanRegister", c => c.WithDefault("'0'"))
.Column<bool>("UsersMustValidateEmail", c => c.WithDefault("'0'"))
.Column<bool>("UsersAreModerated", c => c.WithDefault("'0'"))
.Column<bool>("NotifyModeration", c => c.WithDefault("'0'"))
);
return 2;
}
}
}

View File

@@ -1,35 +0,0 @@
using System.Web.Routing;
using JetBrains.Annotations;
using Orchard.ContentManagement;
using Orchard.ContentManagement.Drivers;
using Orchard.Users.Models;
namespace Orchard.Users.Drivers {
[UsedImplicitly]
public class UserPartDriver : ContentItemDriver<UserPart> {
public readonly static ContentType ContentType = new ContentType {
Name = "User",
DisplayName = "User Profile"
};
protected override bool UseDefaultTemplate { get { return true; } }
protected override ContentType GetContentType() {
return ContentType;
}
protected override string GetDisplayText(UserPart item) {
//TEMP: need a "display name" probably... showing login info likely not a best practice...
return item.UserName;
}
public override RouteValueDictionary GetEditorRouteValues(UserPart item) {
return new RouteValueDictionary {
{"Area", "Orchard.Users"},
{"Controller", "Admin"},
{"Action", "Edit"},
{"Id", item.ContentItem.Id},
};
}
}
}

View File

@@ -0,0 +1,16 @@
using Orchard.Events;
namespace Orchard.Users.Events {
public interface IUserEventHandler : IEventHandler {
/// <summary>
/// Called before a User is created
/// </summary>
void Creating(UserContext context);
/// <summary>
/// Called once a user has been created
/// </summary>
void Created(UserContext context);
}
}

View File

@@ -0,0 +1,8 @@
using Orchard.Users.Models;
namespace Orchard.Users.Events {
public class UserContext {
public UserPart User { get; set; }
public bool Cancel { get; set; }
}
}

View File

@@ -0,0 +1,38 @@
using Orchard.Messaging.Events;
using Orchard.Messaging.Models;
using Orchard.ContentManagement;
using Orchard.Users.Models;
namespace Orchard.Users.Handlers {
public class ModerationMessageAlteration : IMessageEventHandler {
private readonly IContentManager _contentManager;
public ModerationMessageAlteration(IContentManager contentManager) {
_contentManager = contentManager;
}
public void Sending(MessageContext context) {
var contentItem = _contentManager.Get(context.Recipient.Id);
if ( contentItem == null )
return;
var recipient = contentItem.As<UserPart>();
if ( recipient == null )
return;
if ( context.Type == MessageTypes.Moderation ) {
context.MailMessage.Subject = "User needs moderation";
context.MailMessage.Body = string.Format("The following user account needs to be moderated: {0}", recipient.UserName);
}
if ( context.Type == MessageTypes.Validation ) {
context.MailMessage.Subject = "User account validation";
context.MailMessage.Body = string.Format("Dear {0}, please <a href=\"{1}\">click here</a> to validate you email address.", recipient.UserName, context.Properties["ChallengeUrl"]);
}
}
public void Sent(MessageContext context) {
}
}
}

View File

@@ -0,0 +1,15 @@
using JetBrains.Annotations;
using Orchard.Data;
using Orchard.ContentManagement.Handlers;
using Orchard.Users.Models;
namespace Orchard.Users.Handlers {
[UsedImplicitly]
public class RegistrationSettingsPartHandler : ContentHandler {
public RegistrationSettingsPartHandler(IRepository<RegistrationSettingsPartRecord> repository) {
Filters.Add(new ActivatingFilter<RegistrationSettingsPart>("Site"));
Filters.Add(StorageFilter.For(repository));
Filters.Add(new TemplateFilterForRecord<RegistrationSettingsPartRecord>("RegistrationSettings", "Parts/Users.RegistrationSettings"));
}
}
}

View File

@@ -1,14 +1,13 @@
using JetBrains.Annotations;
using Orchard.Data;
using Orchard.ContentManagement.Handlers;
using Orchard.Users.Drivers;
using Orchard.Users.Models;
namespace Orchard.Users.Handlers {
[UsedImplicitly]
public class UserPartHandler : ContentHandler {
public UserPartHandler(IRepository<UserPartRecord> repository) {
Filters.Add(new ActivatingFilter<UserPart>(UserPartDriver.ContentType.Name));
Filters.Add(new ActivatingFilter<UserPart>("User"));
Filters.Add(StorageFilter.For(repository));
}
}

View File

@@ -0,0 +1,12 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace Orchard.Users.Models {
public static class MessageTypes {
public const string Moderation = "ORCHARD_USERS_MODERATION";
public const string Validation = "ORCHARD_USERS_VALIDATION";
}
}

View File

@@ -0,0 +1,27 @@
using Orchard.ContentManagement;
using System;
namespace Orchard.Users.Models {
public class RegistrationSettingsPart : ContentPart<RegistrationSettingsPartRecord> {
public bool UsersCanRegister {
get { return Record.UsersCanRegister; }
set { Record.UsersCanRegister = value; }
}
public bool UsersMustValidateEmail {
get { return Record.UsersMustValidateEmail; }
set { Record.UsersMustValidateEmail = value; }
}
public bool UsersAreModerated {
get { return Record.UsersAreModerated; }
set { Record.UsersAreModerated = value; }
}
public bool NotifyModeration {
get { return Record.NotifyModeration; }
set { Record.NotifyModeration = value; }
}
}
}

View File

@@ -0,0 +1,12 @@
using System.Net.Mail;
using Orchard.ContentManagement.Records;
using System.ComponentModel.DataAnnotations;
namespace Orchard.Users.Models {
public class RegistrationSettingsPartRecord : ContentPartRecord {
public virtual bool UsersCanRegister { get; set; }
public virtual bool UsersMustValidateEmail { get; set; }
public virtual bool UsersAreModerated { get; set; }
public virtual bool NotifyModeration { get; set; }
}
}

View File

@@ -21,5 +21,15 @@ namespace Orchard.Users.Models {
get { return Record.NormalizedUserName; }
set { Record.NormalizedUserName = value; }
}
public UserStatus RegistrationStatus {
get { return Record.RegistrationStatus; }
set { Record.RegistrationStatus = value; }
}
public UserStatus EmailStatus {
get { return Record.EmailStatus; }
set { Record.EmailStatus = value; }
}
}
}

View File

@@ -11,5 +11,9 @@ namespace Orchard.Users.Models {
public virtual MembershipPasswordFormat PasswordFormat { get; set; }
public virtual string HashAlgorithm { get; set; }
public virtual string PasswordSalt { get; set; }
public virtual UserStatus RegistrationStatus { get; set; }
public virtual UserStatus EmailStatus { get; set; }
public virtual string EmailChallengeToken { get; set; }
}
}

View File

@@ -0,0 +1,6 @@
namespace Orchard.Users.Models {
public enum UserStatus {
Pending,
Approved
}
}

View File

@@ -45,6 +45,7 @@
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="System.Security" />
<Reference Include="System.Web.ApplicationServices" />
<Reference Include="System.Web.DynamicData" />
<Reference Include="System.Web.Entity" />
@@ -68,10 +69,17 @@
<Compile Include="Controllers\AccountController.cs" />
<Compile Include="Controllers\AdminController.cs" />
<Compile Include="DataMigrations\UsersDataMigration.cs" />
<Compile Include="Drivers\UserPartDriver.cs" />
<Compile Include="Events\UserContext.cs" />
<Compile Include="Handlers\ModerationMessageAlteration.cs" />
<Compile Include="Handlers\RegistrationSettingsPartHandler.cs" />
<Compile Include="Events\IUserEventHandler.cs" />
<Compile Include="Models\MessageTypes.cs" />
<Compile Include="Models\RegistrationSettingsPart.cs" />
<Compile Include="Models\RegistrationSettingsPartRecord.cs" />
<Compile Include="Models\UserPart.cs" />
<Compile Include="Handlers\UserPartHandler.cs" />
<Compile Include="Models\UserPartRecord.cs" />
<Compile Include="Models\UserStatus.cs" />
<Compile Include="Permissions.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Services\IUserService.cs" />
@@ -84,10 +92,15 @@
<Compile Include="ViewModels\UsersIndexViewModel.cs" />
</ItemGroup>
<ItemGroup>
<Content Include="Content\Admin\images\offline.gif" />
<Content Include="Content\Admin\images\online.gif" />
<Content Include="Module.txt" />
<Content Include="Views\Account\ChangePassword.ascx" />
<Content Include="Views\Account\ChangePasswordSuccess.ascx" />
<Content Include="Views\Account\AccessDenied.ascx" />
<Content Include="Views\Account\ChallengeEmailSuccess.ascx" />
<Content Include="Views\Account\ChallengeEmailSent.ascx" />
<Content Include="Views\Account\ChallengeEmailFail.ascx" />
<Content Include="Views\Account\LogOn.ascx" />
<Content Include="Views\Account\Register.ascx" />
<Content Include="Views\Admin\Edit.aspx" />
@@ -95,6 +108,7 @@
<Content Include="Views\Admin\EditorTemplates\inputPasswordLarge.ascx" />
<Content Include="Views\Admin\EditorTemplates\inputTextLarge.ascx" />
<Content Include="Views\Admin\Index.aspx" />
<Content Include="Views\EditorTemplates\Parts\Users.RegistrationSettings.ascx" />
<Content Include="Web.config" />
<Content Include="Views\Web.config" />
</ItemGroup>

View File

@@ -1,29 +1,37 @@
using System;
using System.Globalization;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Web.Security;
using System.Xml.Linq;
using JetBrains.Annotations;
using Orchard.Data;
using Orchard.Logging;
using Orchard.ContentManagement;
using Orchard.Security;
using Orchard.Users.Drivers;
using Orchard.Users.Events;
using Orchard.Users.Models;
using Orchard.Settings;
using Orchard.Messaging.Services;
using System.Collections.Generic;
namespace Orchard.Users.Services {
[UsedImplicitly]
public class MembershipService : IMembershipService {
private static readonly TimeSpan DelayToValidate = new TimeSpan(7, 0, 0, 0); // one week to validate email
private readonly IContentManager _contentManager;
private readonly IRepository<UserPartRecord> _userRepository;
private readonly IMessageManager _messageManager;
private readonly IEnumerable<IUserEventHandler> _userEventHandlers;
public MembershipService(IContentManager contentManager, IRepository<UserPartRecord> userRepository) {
public MembershipService(IContentManager contentManager, IMessageManager messageManager, IEnumerable<IUserEventHandler> userEventHandlers) {
_contentManager = contentManager;
_userRepository = userRepository;
_messageManager = messageManager;
_userEventHandlers = userEventHandlers;
Logger = NullLogger.Instance;
}
public ILogger Logger { get; set; }
protected virtual ISite CurrentSite { get; [UsedImplicitly] private set; }
public MembershipSettings GetSettings() {
var settings = new MembershipSettings();
@@ -34,40 +42,124 @@ namespace Orchard.Users.Services {
public IUser CreateUser(CreateUserParams createUserParams) {
Logger.Information("CreateUser {0} {1}", createUserParams.Username, createUserParams.Email);
return _contentManager.Create<UserPart>(UserPartDriver.ContentType.Name, init =>
{
init.Record.UserName = createUserParams.Username;
init.Record.Email = createUserParams.Email;
init.Record.NormalizedUserName = createUserParams.Username.ToLower();
init.Record.HashAlgorithm = "SHA1";
SetPassword(init.Record, createUserParams.Password);
});
var registrationSettings = CurrentSite.As<RegistrationSettingsPart>();
var user = _contentManager.New<UserPart>("User");
user.Record.UserName = createUserParams.Username;
user.Record.Email = createUserParams.Email;
user.Record.NormalizedUserName = createUserParams.Username.ToLower();
user.Record.HashAlgorithm = "SHA1";
SetPassword(user.Record, createUserParams.Password);
if ( registrationSettings != null ) {
user.Record.RegistrationStatus = registrationSettings.UsersAreModerated ? UserStatus.Pending : UserStatus.Approved;
user.Record.EmailStatus = registrationSettings.UsersMustValidateEmail ? UserStatus.Pending : UserStatus.Approved;
}
if(createUserParams.IsApproved) {
user.Record.RegistrationStatus = UserStatus.Approved;
user.Record.EmailStatus = UserStatus.Approved;
}
var userContext = new UserContext {User = user, Cancel = false};
foreach(var userEventHandler in _userEventHandlers) {
userEventHandler.Creating(userContext);
}
if(userContext.Cancel) {
return null;
}
_contentManager.Create(user);
foreach ( var userEventHandler in _userEventHandlers ) {
userEventHandler.Created(userContext);
}
if ( registrationSettings != null && registrationSettings.UsersAreModerated && registrationSettings.NotifyModeration && !createUserParams.IsApproved ) {
var superUser = GetUser(CurrentSite.SuperUser);
if(superUser != null)
_messageManager.Send(superUser.ContentItem.Record, MessageTypes.Moderation);
}
return user;
}
public void SendChallengeEmail(IUser user, string url) {
_messageManager.Send(user.ContentItem.Record, MessageTypes.Validation, "Email", new Dictionary<string, string> { { "ChallengeUrl", url } });
}
public IUser ValidateChallengeToken(string challengeToken) {
string username;
DateTime validateByUtc;
if(!DecryptChallengeToken(challengeToken, out username, out validateByUtc)) {
return null;
}
if ( validateByUtc < DateTime.UtcNow )
return null;
var user = GetUser(username);
if ( user == null )
return null;
user.As<UserPart>().EmailStatus = UserStatus.Approved;
return user;
}
public string GetEncryptedChallengeToken(IUser user) {
var challengeToken = new XElement("Token", new XAttribute("username", user.UserName), new XAttribute("validate-by-utc", DateTime.UtcNow.Add(DelayToValidate).ToString(CultureInfo.InvariantCulture))).ToString();
var data = Encoding.UTF8.GetBytes(challengeToken);
return MachineKey.Encode(data, MachineKeyProtection.All);
}
private static bool DecryptChallengeToken(string challengeToken, out string username, out DateTime validateByUtc) {
username = null;
validateByUtc = DateTime.UtcNow;
try {
var data = MachineKey.Decode(challengeToken, MachineKeyProtection.All);
var xml = Encoding.UTF8.GetString(data);
var element = XElement.Parse(xml);
username = element.Attribute("username").Value;
validateByUtc = DateTime.Parse(element.Attribute("validate-by-utc").Value, CultureInfo.InvariantCulture);
return true;
}
catch {
return false;
}
}
public IUser GetUser(string username) {
var lowerName = username == null ? "" : username.ToLower();
var userRecord = _userRepository.Get(x => x.NormalizedUserName == lowerName);
if (userRecord == null) {
return null;
}
return _contentManager.Get<IUser>(userRecord.Id);
return _contentManager.Query<UserPart, UserPartRecord>().Where(u => u.NormalizedUserName == lowerName).List().FirstOrDefault();
}
public IUser ValidateUser(string userNameOrEmail, string password) {
var lowerName = userNameOrEmail == null ? "" : userNameOrEmail.ToLower();
var userRecord = _userRepository.Get(x => x.NormalizedUserName == lowerName);
if(userRecord == null)
userRecord = _userRepository.Get(x => x.Email == lowerName);
if (userRecord == null || ValidatePassword(userRecord, password) == false)
var user = _contentManager.Query<UserPart, UserPartRecord>().Where(u => u.NormalizedUserName == lowerName).List().FirstOrDefault();
if(user == null)
user = _contentManager.Query<UserPart, UserPartRecord>().Where(u => u.Email == lowerName).List().FirstOrDefault();
if ( user == null || ValidatePassword(user.As<UserPart>().Record, password) == false )
return null;
return _contentManager.Get<IUser>(userRecord.Id);
if ( user.EmailStatus != UserStatus.Approved )
return null;
if ( user.RegistrationStatus != UserStatus.Approved )
return null;
return user;
}
public void SetPassword(IUser user, string password) {
if (!user.Is<UserPart>())
throw new InvalidCastException();
@@ -93,7 +185,7 @@ namespace Orchard.Users.Services {
}
}
private bool ValidatePassword(UserPartRecord partRecord, string password) {
private static bool ValidatePassword(UserPartRecord partRecord, string password) {
// Note - the password format stored with the record is used
// otherwise changing the password format on the site would invalidate
// all logins
@@ -158,5 +250,6 @@ namespace Orchard.Users.Services {
private static bool ValidatePasswordEncrypted(UserPartRecord partRecord, string password) {
throw new NotImplementedException();
}
}
}

View File

@@ -0,0 +1,3 @@
<%@ Control Language="C#" Inherits="Orchard.Mvc.ViewUserControl<object>" %>
<h1><%: Html.TitleForPage(T("Challenge Email").ToString()) %></h1>
<p><%: T("Your email address could not be validated.") %></p>

View File

@@ -0,0 +1,3 @@
<%@ Control Language="C#" Inherits="Orchard.Mvc.ViewUserControl<object>" %>
<h1><%: Html.TitleForPage(T("Challenge Email Sent").ToString()) %></h1>
<p><%: T("An email has been sent to you. Please click on the link it contains in order to have access on this site.") %></p>

View File

@@ -0,0 +1,3 @@
<%@ Control Language="C#" Inherits="Orchard.Mvc.ViewUserControl<object>" %>
<h1><%: Html.TitleForPage(T("Challenge Email").ToString()) %></h1>
<p><%: T("Your email address has been validated.") %></p>

View File

@@ -1,4 +1,5 @@
<%@ Page Language="C#" Inherits="Orchard.Mvc.ViewPage<UsersIndexViewModel>" %>
<%@ Import Namespace="Orchard.Users.Models" %>
<%@ Import Namespace="Orchard.Users.ViewModels"%>
<h1><%: Html.TitleForPage(T("Manage Users").ToString()) %></h1>
<% using (Html.BeginFormAntiForgeryPost()) { %>
@@ -22,6 +23,12 @@
{ %>
<tr>
<td>
<% if(row.UserPart.RegistrationStatus == UserStatus.Approved) { %>
<img class="icon" src="<%=ResolveUrl("~/Modules/Orchard.Users/Content/Admin/images/online.gif") %>" alt="<%:T("Approved") %>" title="<%:T("User is approved") %>" />
<% }
else { %>
<img class="icon" src="<%=ResolveUrl("~/Modules/Orchard.Users/Content/Admin/images/offline.gif") %>" alt="<%:T("Moderated") %>" title="<%:T("User is moderated") %>" />
<% } %>
<%: row.UserPart.UserName %>
</td>
<td>
@@ -29,7 +36,11 @@
</td>
<td>
<%: Html.ActionLink(T("Edit").ToString(), "Edit", new { row.UserPart.Id })%> |
<%: Html.ActionLink(T("Remove").ToString(), "Delete", new { row.UserPart.Id })%>
<%: Html.ActionLink(T("Remove").ToString(), "Delete", new { row.UserPart.Id })%> |
<%: row.UserPart.RegistrationStatus == UserStatus.Pending ? Html.ActionLink(T("Approve").ToString(), "Approve", new { row.UserPart.Id }) : Html.ActionLink(T("Disable").ToString(), "Moderate", new { row.UserPart.Id })%>
<% if ( row.UserPart.EmailStatus == UserStatus.Pending ) { %> |
<%: Html.ActionLink(T("Challenge Email").ToString(), "SendChallengeEmail", new { row.UserPart.Id })%>
<% } %>
</td>
</tr>
<%}%>

View File

@@ -0,0 +1,25 @@
<%@ Control Language="C#" Inherits="Orchard.Mvc.ViewUserControl<RegistrationSettingsPartRecord>" %>
<%@ Import Namespace="Orchard.Users.Models"%>
<fieldset>
<legend><%: T("Users registration")%></legend>
<div>
<%: Html.EditorFor(m => m.UsersCanRegister) %>
<label class="forcheckbox" for="<%: Html.FieldIdFor( m => m.UsersCanRegister) %>"><%: T("Users can create new accounts on the site")%></label>
<%: Html.ValidationMessage("UsersCanRegister", "*")%>
</div>
<div>
<%: Html.EditorFor(m => m.UsersMustValidateEmail)%>
<label class="forcheckbox" for="<%: Html.FieldIdFor( m => m.UsersMustValidateEmail) %>"><%: T("Users must justify their email address")%></label>
<%: Html.ValidationMessage("UsersMustValidateEmail", "*")%>
</div>
<div>
<%: Html.EditorFor(m => m.UsersAreModerated)%>
<label class="forcheckbox" for="<%: Html.FieldIdFor( m => m.UsersAreModerated) %>"><%: T("Users must be approved before they can log in")%></label>
<%: Html.ValidationMessage("UsersAreModerated", "*")%>
</div>
<div data-controllerid="<%:Html.FieldIdFor(m => m.UsersAreModerated) %>">
<%: Html.EditorFor(m => m.NotifyModeration)%>
<label class="forcheckbox" for="<%: Html.FieldIdFor( m => m.NotifyModeration) %>"><%: T("Send a notification when a user needs moderation")%></label>
<%: Html.ValidationMessage("NotifyModeration", "*")%>
</div>
</fieldset>

View File

@@ -42,6 +42,8 @@
<defaultSettings timeout="00:30:00"/>
</system.transactions>
<system.web>
<machineKey validationKey="013B82F217ABB7EAB1F699E4E5B4D290030644D435994692354DAE82B06568B058BFE3C57BF199A41FFDBC84F3BC74D9C5BD96D1265F36A22D58347B591AC8DD" decryptionKey="04797035C490263D73ED991C84C5DFCD0D0206AD4F12BC3638A38FBEABEBB8C7" validation="SHA1" decryption="AES" />
<httpRuntime requestValidationMode="2.0" />
<!--
Set compilation debug="true" to insert debugging
@@ -68,33 +70,6 @@
<authentication mode="Forms">
<forms loginUrl="~/Users/Account/AccessDenied" timeout="2880"/>
</authentication>
<membership defaultProvider="OrchardMembershipProvider">
<providers>
<clear/>
<!--<add name="AspNetSqlMembershipProvider"
type="System.Web.Security.SqlMembershipProvider, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
connectionStringName="ApplicationServices"
enablePasswordRetrieval="false"
enablePasswordReset="true"
requiresQuestionAndAnswer="false"
requiresUniqueEmail="false"
passwordFormat="Hashed"
maxInvalidPasswordAttempts="5"
minRequiredPasswordLength="6"
minRequiredNonalphanumericCharacters="0"
passwordAttemptWindow="10"
passwordStrengthRegularExpression=""
applicationName="/"
/>-->
<add name="OrchardMembershipProvider" type="Orchard.Security.Providers.OrchardMembershipProvider, Orchard.Framework" applicationName="/"/>
</providers>
</membership>
<profile>
<providers>
<clear/>
<add name="AspNetSqlProfileProvider" type="System.Web.Profile.SqlProfileProvider, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" connectionStringName="ApplicationServices" applicationName="/"/>
</providers>
</profile>
<roleManager enabled="false">
<providers>
<clear/>

View File

@@ -165,26 +165,26 @@ namespace Orchard.ContentManagement {
/* Display and editor convenience extension methods */
public static ContentItemViewModel<T> BuildDisplayModel<T>(this IContentManager manager, int id, string displayType) where T : class, IContent {
public static ContentItemViewModel<T> BuildDisplayShape<T>(this IContentManager manager, int id, string displayType) where T : class, IContent {
var content = manager.Get<T>(id);
if (content == null)
return null;
return manager.BuildDisplayModel(content, displayType);
return manager.BuildDisplayShape(content, displayType);
}
public static ContentItemViewModel<T> BuildEditorModel<T>(this IContentManager manager, int id) where T : class, IContent {
public static ContentItemViewModel<T> BuildEditorShape<T>(this IContentManager manager, int id) where T : class, IContent {
var content = manager.Get<T>(id);
if (content == null)
return null;
return manager.BuildEditorModel(content);
return manager.BuildEditorShape(content);
}
public static ContentItemViewModel<T> UpdateEditorModel<T>(this IContentManager manager, int id, IUpdateModel updater) where T : class, IContent {
public static ContentItemViewModel<T> UpdateEditorShape<T>(this IContentManager manager, int id, IUpdateModel updater) where T : class, IContent {
var content = manager.Get<T>(id);
if (content == null)
return null;
return manager.UpdateEditorModel(content, updater);
return manager.UpdateEditorShape(content, updater);
}

View File

@@ -380,37 +380,47 @@ namespace Orchard.ContentManagement {
};
foreach (var handler in Handlers) {
handler.GetContentItemMetadata(context);
//-- was - from ContentItemDriver --
//void IContentItemDriver.GetContentItemMetadata(GetContentItemMetadataContext context) {
// var item = context.ContentItem.As<TContent>();
// if (item != null) {
// context.Metadata.DisplayText = GetDisplayText(item) ?? context.Metadata.DisplayText;
// context.Metadata.DisplayRouteValues = GetDisplayRouteValues(item) ?? context.Metadata.DisplayRouteValues;
// context.Metadata.EditorRouteValues = GetEditorRouteValues(item) ?? context.Metadata.EditorRouteValues;
// context.Metadata.CreateRouteValues = GetCreateRouteValues(item) ?? context.Metadata.CreateRouteValues;
// }
//}
}
return context.Metadata;
}
public ContentItemViewModel<TContentPart> BuildDisplayModel<TContentPart>(TContentPart content, string displayType) where TContentPart : IContent {
public ContentItemViewModel<TContentPart> BuildDisplayShape<TContentPart>(TContentPart content, string displayType) where TContentPart : IContent {
if (content == null)
return null;
var displayModel = new ContentItemViewModel<TContentPart>(content);
var context = new BuildDisplayModelContext(displayModel, displayType);
foreach (var handler in Handlers) {
handler.BuildDisplayModel(context);
handler.BuildDisplayShape(context);
}
return displayModel;
}
public ContentItemViewModel<TContentPart> BuildEditorModel<TContentPart>(TContentPart content) where TContentPart : IContent {
public ContentItemViewModel<TContentPart> BuildEditorShape<TContentPart>(TContentPart content) where TContentPart : IContent {
var editorModel = new ContentItemViewModel<TContentPart>(content);
var context = new BuildEditorModelContext(editorModel);
foreach (var handler in Handlers) {
handler.BuildEditorModel(context);
handler.BuildEditorShape(context);
}
return editorModel;
}
public ContentItemViewModel<TContentPart> UpdateEditorModel<TContentPart>(TContentPart content, IUpdateModel updater) where TContentPart : IContent {
public ContentItemViewModel<TContentPart> UpdateEditorShape<TContentPart>(TContentPart content, IUpdateModel updater) where TContentPart : IContent {
var editorModel = new ContentItemViewModel<TContentPart>(content);
var context = new UpdateEditorModelContext(editorModel, updater);
foreach (var handler in Handlers) {
handler.UpdateEditorModel(context);
handler.UpdateEditorShape(context);
}
return editorModel;
}

View File

@@ -9,15 +9,15 @@ namespace Orchard.ContentManagement.Drivers {
protected virtual string Prefix { get { return ""; } }
protected virtual string Zone { get { return "body"; } }
DriverResult IContentFieldDriver.BuildDisplayModel(BuildDisplayModelContext context) {
DriverResult IContentFieldDriver.BuildDisplayShape(BuildDisplayModelContext context) {
return Process(context.ContentItem, (part, field) => Display(part, field, context.DisplayType));
}
DriverResult IContentFieldDriver.BuildEditorModel(BuildEditorModelContext context) {
DriverResult IContentFieldDriver.BuildEditorShape(BuildEditorModelContext context) {
return Process(context.ContentItem, Editor);
}
DriverResult IContentFieldDriver.UpdateEditorModel(UpdateEditorModelContext context) {
DriverResult IContentFieldDriver.UpdateEditorShape(UpdateEditorModelContext context) {
return Process(context.ContentItem, (part, field) => Editor(part, field, context.Updater));
}

View File

@@ -1,87 +0,0 @@
using System.Collections.Generic;
using System.Linq;
using System.Web.Routing;
using Orchard.ContentManagement.Handlers;
using Orchard.Mvc.ViewModels;
namespace Orchard.ContentManagement.Drivers {
public abstract class ContentItemDriver<TContent> : ContentPartDriver<TContent>, IContentItemDriver where TContent : ContentPart, new() {
private readonly ContentType _contentType;
protected virtual bool UseDefaultTemplate { get { return false; } }
public ContentItemDriver() {
}
public ContentItemDriver(ContentType contentType) {
_contentType = contentType;
}
IEnumerable<ContentType> IContentItemDriver.GetContentTypes() {
var contentType = GetContentType();
return contentType != null ? new[] { contentType } : Enumerable.Empty<ContentType>();
}
void IContentItemDriver.GetContentItemMetadata(GetContentItemMetadataContext context) {
var item = context.ContentItem.As<TContent>();
if (item != null) {
context.Metadata.DisplayText = GetDisplayText(item) ?? context.Metadata.DisplayText;
context.Metadata.DisplayRouteValues = GetDisplayRouteValues(item) ?? context.Metadata.DisplayRouteValues;
context.Metadata.EditorRouteValues = GetEditorRouteValues(item) ?? context.Metadata.EditorRouteValues;
context.Metadata.CreateRouteValues = GetCreateRouteValues(item) ?? context.Metadata.CreateRouteValues;
}
}
DriverResult IContentItemDriver.BuildDisplayModel(BuildDisplayModelContext context) {
var part = context.ContentItem.As<TContent>();
if (part == null) {
return null;
}
if (context.ViewModel.GetType() != typeof(ContentItemViewModel<TContent>)) {
return Display(new ContentItemViewModel<TContent>(context.ViewModel), context.DisplayType);
}
return Display((ContentItemViewModel<TContent>)context.ViewModel, context.DisplayType);
}
DriverResult IContentItemDriver.BuildEditorModel(BuildEditorModelContext context) {
var part = context.ContentItem.As<TContent>();
if (part == null) {
return null;
}
if (context.ViewModel.GetType() != typeof(ContentItemViewModel<TContent>)) {
return Editor(new ContentItemViewModel<TContent>(context.ViewModel));
}
return Editor((ContentItemViewModel<TContent>)context.ViewModel);
}
DriverResult IContentItemDriver.UpdateEditorModel(UpdateEditorModelContext context) {
var part = context.ContentItem.As<TContent>();
if (part == null) {
return null;
}
if (context.ViewModel.GetType() != typeof(ContentItemViewModel<TContent>)) {
return Editor(new ContentItemViewModel<TContent>(context.ViewModel), context.Updater);
}
return Editor((ContentItemViewModel<TContent>)context.ViewModel, context.Updater);
}
protected virtual ContentType GetContentType() { return _contentType; }
protected virtual string GetDisplayText(TContent item) { return null; }
public virtual RouteValueDictionary GetDisplayRouteValues(TContent item) { return null; }
public virtual RouteValueDictionary GetEditorRouteValues(TContent item) { return null; }
public virtual RouteValueDictionary GetCreateRouteValues(TContent item) { return null; }
protected virtual DriverResult Display(ContentItemViewModel<TContent> viewModel, string displayType) { return GetDefaultItemTemplate(); }
protected virtual DriverResult Editor(ContentItemViewModel<TContent> viewModel) { return GetDefaultItemTemplate(); }
protected virtual DriverResult Editor(ContentItemViewModel<TContent> viewModel, IUpdateModel updater) { return GetDefaultItemTemplate(); }
public ContentItemTemplateResult<TContent> ContentItemTemplate(string templateName) {
return new ContentItemTemplateResult<TContent>(templateName);
}
private DriverResult GetDefaultItemTemplate() {
return UseDefaultTemplate
? ContentItemTemplate("Items/ContentItem")
: null;
}
}
}

View File

@@ -7,17 +7,17 @@ namespace Orchard.ContentManagement.Drivers {
protected virtual string Prefix { get { return ""; } }
protected virtual string Zone { get { return "body"; } }
DriverResult IContentPartDriver.BuildDisplayModel(BuildDisplayModelContext context) {
DriverResult IContentPartDriver.BuildDisplayShape(BuildDisplayModelContext context) {
var part = context.ContentItem.As<TContent>();
return part == null ? null : Display(part, context.DisplayType);
}
DriverResult IContentPartDriver.BuildEditorModel(BuildEditorModelContext context) {
DriverResult IContentPartDriver.BuildEditorShape(BuildEditorModelContext context) {
var part = context.ContentItem.As<TContent>();
return part == null ? null : Editor(part);
}
DriverResult IContentPartDriver.UpdateEditorModel(UpdateEditorModelContext context) {
DriverResult IContentPartDriver.UpdateEditorShape(UpdateEditorModelContext context) {
var part = context.ContentItem.As<TContent>();
return part == null ? null : Editor(part, context.Updater);
}

View File

@@ -29,35 +29,35 @@ namespace Orchard.ContentManagement.Drivers.Coordinators {
var fieldTypeName = partFieldDefinition.FieldDefinition.Name;
var fieldInfo = fieldInfos.FirstOrDefault(x => x.FieldTypeName == fieldTypeName);
if (fieldInfo != null) {
var storage = _fieldStorageProviderSelector
var storage = _fieldStorageProviderSelector
.GetProvider(partFieldDefinition)
.BindStorage(contentPart, partFieldDefinition);
var field = fieldInfo.Factory(partFieldDefinition, storage);
contentPart.Weld(field);
var field = fieldInfo.Factory(partFieldDefinition, storage);
contentPart.Weld(field);
}
}
}
}
public override void BuildDisplayModel(BuildDisplayModelContext context) {
public override void BuildDisplayShape(BuildDisplayModelContext context) {
_drivers.Invoke(driver => {
var result = driver.BuildDisplayModel(context);
var result = driver.BuildDisplayShape(context);
if (result != null)
result.Apply(context);
}, Logger);
}
public override void BuildEditorModel(BuildEditorModelContext context) {
public override void BuildEditorShape(BuildEditorModelContext context) {
_drivers.Invoke(driver => {
var result = driver.BuildEditorModel(context);
var result = driver.BuildEditorShape(context);
if (result != null)
result.Apply(context);
}, Logger);
}
public override void UpdateEditorModel(UpdateEditorModelContext context) {
public override void UpdateEditorShape(UpdateEditorModelContext context) {
_drivers.Invoke(driver => {
var result = driver.UpdateEditorModel(context);
var result = driver.UpdateEditorShape(context);
if (result != null)
result.Apply(context);
}, Logger);

View File

@@ -1,52 +0,0 @@
using System.Collections.Generic;
using JetBrains.Annotations;
using Orchard.ContentManagement.Handlers;
using Orchard.Logging;
namespace Orchard.ContentManagement.Drivers.Coordinators {
[UsedImplicitly]
public class ContentItemDriverCoordinator : ContentHandlerBase {
private readonly IEnumerable<IContentItemDriver> _drivers;
public ContentItemDriverCoordinator(IEnumerable<IContentItemDriver> drivers) {
_drivers = drivers;
Logger = NullLogger.Instance;
}
public ILogger Logger { get; set; }
public override IEnumerable<ContentType> GetContentTypes() {
var contentTypes = new List<ContentType>();
_drivers.Invoke(driver=>contentTypes.AddRange(driver.GetContentTypes()), Logger);
return contentTypes;
}
public override void GetContentItemMetadata(GetContentItemMetadataContext context) {
_drivers.Invoke(driver => driver.GetContentItemMetadata(context), Logger);
}
public override void BuildDisplayModel(BuildDisplayModelContext context) {
_drivers.Invoke(driver => {
var result = driver.BuildDisplayModel(context);
if (result != null)
result.Apply(context);
}, Logger);
}
public override void BuildEditorModel(BuildEditorModelContext context) {
_drivers.Invoke(driver => {
var result = driver.BuildEditorModel(context);
if (result != null)
result.Apply(context);
}, Logger);
}
public override void UpdateEditorModel(UpdateEditorModelContext context) {
_drivers.Invoke(driver => {
var result = driver.UpdateEditorModel(context);
if (result != null)
result.Apply(context);
}, Logger);
}
}
}

View File

@@ -36,25 +36,25 @@ namespace Orchard.ContentManagement.Drivers.Coordinators {
}
}
public override void BuildDisplayModel(BuildDisplayModelContext context) {
public override void BuildDisplayShape(BuildDisplayModelContext context) {
_drivers.Invoke(driver => {
var result = driver.BuildDisplayModel(context);
var result = driver.BuildDisplayShape(context);
if (result != null)
result.Apply(context);
}, Logger);
}
public override void BuildEditorModel(BuildEditorModelContext context) {
public override void BuildEditorShape(BuildEditorModelContext context) {
_drivers.Invoke(driver => {
var result = driver.BuildEditorModel(context);
var result = driver.BuildEditorShape(context);
if (result != null)
result.Apply(context);
}, Logger);
}
public override void UpdateEditorModel(UpdateEditorModelContext context) {
public override void UpdateEditorShape(UpdateEditorModelContext context) {
_drivers.Invoke(driver => {
var result = driver.UpdateEditorModel(context);
var result = driver.UpdateEditorShape(context);
if (result != null)
result.Apply(context);
}, Logger);

View File

@@ -4,9 +4,9 @@ using Orchard.ContentManagement.MetaData;
namespace Orchard.ContentManagement.Drivers {
public interface IContentFieldDriver : IEvents {
DriverResult BuildDisplayModel(BuildDisplayModelContext context);
DriverResult BuildEditorModel(BuildEditorModelContext context);
DriverResult UpdateEditorModel(UpdateEditorModelContext context);
DriverResult BuildDisplayShape(BuildDisplayModelContext context);
DriverResult BuildEditorShape(BuildEditorModelContext context);
DriverResult UpdateEditorShape(UpdateEditorModelContext context);
IEnumerable<ContentFieldInfo> GetFieldInfo();
}

View File

@@ -1,13 +0,0 @@
using System.Collections.Generic;
using Orchard.ContentManagement.Handlers;
namespace Orchard.ContentManagement.Drivers {
public interface IContentItemDriver : IEvents {
IEnumerable<ContentType> GetContentTypes();
void GetContentItemMetadata(GetContentItemMetadataContext context);
DriverResult BuildDisplayModel(BuildDisplayModelContext context);
DriverResult BuildEditorModel(BuildEditorModelContext context);
DriverResult UpdateEditorModel(UpdateEditorModelContext context);
}
}

View File

@@ -4,9 +4,9 @@ using Orchard.ContentManagement.MetaData;
namespace Orchard.ContentManagement.Drivers {
public interface IContentPartDriver : IEvents {
DriverResult BuildDisplayModel(BuildDisplayModelContext context);
DriverResult BuildEditorModel(BuildEditorModelContext context);
DriverResult UpdateEditorModel(UpdateEditorModelContext context);
DriverResult BuildDisplayShape(BuildDisplayModelContext context);
DriverResult BuildEditorShape(BuildEditorModelContext context);
DriverResult UpdateEditorShape(UpdateEditorModelContext context);
IEnumerable<ContentPartInfo> GetPartInfo();
}

View File

@@ -80,16 +80,16 @@ namespace Orchard.ContentManagement.Handlers {
protected void OnGetContentItemMetadata<TPart>(Action<GetContentItemMetadataContext, TPart> handler) where TPart : class, IContent {
Filters.Add(new InlineTemplateFilter<TPart> { OnGetItemMetadata = handler });
}
protected void OnGetDisplayViewModel<TPart>(Action<BuildDisplayModelContext, TPart> handler) where TPart : class, IContent {
Filters.Add(new InlineTemplateFilter<TPart> { OnGetDisplayViewModel = handler });
protected void OnGetDisplayShape<TPart>(Action<BuildDisplayModelContext, TPart> handler) where TPart : class, IContent {
Filters.Add(new InlineTemplateFilter<TPart> { OnGetDisplayShape = handler });
}
protected void OnGetEditorViewModel<TPart>(Action<BuildEditorModelContext, TPart> handler) where TPart : class, IContent {
Filters.Add(new InlineTemplateFilter<TPart> { OnGetEditorViewModel = handler });
protected void OnGetEditorShape<TPart>(Action<BuildEditorModelContext, TPart> handler) where TPart : class, IContent {
Filters.Add(new InlineTemplateFilter<TPart> { OnGetEditorShape = handler });
}
protected void OnUpdateEditorViewModel<TPart>(Action<UpdateEditorModelContext, TPart> handler) where TPart : class, IContent {
Filters.Add(new InlineTemplateFilter<TPart> { OnUpdateEditorViewModel = handler });
protected void OnUpdateEditorShape<TPart>(Action<UpdateEditorModelContext, TPart> handler) where TPart : class, IContent {
Filters.Add(new InlineTemplateFilter<TPart> { OnUpdateEditorShape = handler });
}
class InlineStorageFilter<TPart> : StorageFilterBase<TPart> where TPart : class, IContent {
@@ -164,20 +164,20 @@ namespace Orchard.ContentManagement.Handlers {
class InlineTemplateFilter<TPart> : TemplateFilterBase<TPart> where TPart : class, IContent {
public Action<GetContentItemMetadataContext, TPart> OnGetItemMetadata { get; set; }
public Action<BuildDisplayModelContext, TPart> OnGetDisplayViewModel { get; set; }
public Action<BuildEditorModelContext, TPart> OnGetEditorViewModel { get; set; }
public Action<UpdateEditorModelContext, TPart> OnUpdateEditorViewModel { get; set; }
public Action<BuildDisplayModelContext, TPart> OnGetDisplayShape { get; set; }
public Action<BuildEditorModelContext, TPart> OnGetEditorShape { get; set; }
public Action<UpdateEditorModelContext, TPart> OnUpdateEditorShape { get; set; }
protected override void GetContentItemMetadata(GetContentItemMetadataContext context, TPart instance) {
if (OnGetItemMetadata != null) OnGetItemMetadata(context, instance);
}
protected override void BuildDisplayModel(BuildDisplayModelContext context, TPart instance) {
if (OnGetDisplayViewModel != null) OnGetDisplayViewModel(context, instance);
protected override void BuildDisplayShape(BuildDisplayModelContext context, TPart instance) {
if (OnGetDisplayShape != null) OnGetDisplayShape(context, instance);
}
protected override void BuildEditorModel(BuildEditorModelContext context, TPart instance) {
if (OnGetEditorViewModel != null) OnGetEditorViewModel(context, instance);
protected override void BuildEditorShape(BuildEditorModelContext context, TPart instance) {
if (OnGetEditorShape != null) OnGetEditorShape(context, instance);
}
protected override void UpdateEditorModel(UpdateEditorModelContext context, TPart instance) {
if (OnUpdateEditorViewModel != null) OnUpdateEditorViewModel(context, instance);
protected override void UpdateEditorShape(UpdateEditorModelContext context, TPart instance) {
if (OnUpdateEditorShape != null) OnUpdateEditorShape(context, instance);
}
}
@@ -292,20 +292,20 @@ namespace Orchard.ContentManagement.Handlers {
filter.GetContentItemMetadata(context);
GetItemMetadata(context);
}
void IContentHandler.BuildDisplayModel(BuildDisplayModelContext context) {
void IContentHandler.BuildDisplayShape(BuildDisplayModelContext context) {
foreach (var filter in Filters.OfType<IContentTemplateFilter>())
filter.BuildDisplayModel(context);
BuildDisplayModel(context);
filter.BuildDisplayShape(context);
BuildDisplayShape(context);
}
void IContentHandler.BuildEditorModel(BuildEditorModelContext context) {
void IContentHandler.BuildEditorShape(BuildEditorModelContext context) {
foreach (var filter in Filters.OfType<IContentTemplateFilter>())
filter.BuildEditorModel(context);
BuildEditorModel(context);
filter.BuildEditorShape(context);
BuildEditorShape(context);
}
void IContentHandler.UpdateEditorModel(UpdateEditorModelContext context) {
void IContentHandler.UpdateEditorShape(UpdateEditorModelContext context) {
foreach (var filter in Filters.OfType<IContentTemplateFilter>())
filter.UpdateEditorModel(context);
UpdateEditorModel(context);
filter.UpdateEditorShape(context);
UpdateEditorShape(context);
}
protected virtual void Activating(ActivatingContentContext context) { }
@@ -335,8 +335,8 @@ namespace Orchard.ContentManagement.Handlers {
protected virtual void Indexed(IndexContentContext context) { }
protected virtual void GetItemMetadata(GetContentItemMetadataContext context) { }
protected virtual void BuildDisplayModel(BuildDisplayModelContext context) { }
protected virtual void BuildEditorModel(BuildEditorModelContext context) { }
protected virtual void UpdateEditorModel(UpdateEditorModelContext context) { }
protected virtual void BuildDisplayShape(BuildDisplayModelContext context) { }
protected virtual void BuildEditorShape(BuildEditorModelContext context) { }
protected virtual void UpdateEditorShape(UpdateEditorModelContext context) { }
}
}

View File

@@ -7,67 +7,27 @@ namespace Orchard.ContentManagement.Handlers {
return Enumerable.Empty<ContentType>();
}
public virtual void Activating(ActivatingContentContext context) {
}
public virtual void Activating(ActivatingContentContext context) {}
public virtual void Activated(ActivatedContentContext context) {}
public virtual void Initializing(InitializingContentContext context) {}
public virtual void Creating(CreateContentContext context) {}
public virtual void Created(CreateContentContext context) {}
public virtual void Saving(SaveContentContext context) {}
public virtual void Saved(SaveContentContext context) {}
public virtual void Loading(LoadContentContext context) {}
public virtual void Loaded(LoadContentContext context) {}
public virtual void Versioning(VersionContentContext context) {}
public virtual void Versioned(VersionContentContext context) {}
public virtual void Publishing(PublishContentContext context) {}
public virtual void Published(PublishContentContext context) {}
public virtual void Removing(RemoveContentContext context) {}
public virtual void Removed(RemoveContentContext context) {}
public virtual void Indexing(IndexContentContext context) {}
public virtual void Indexed(IndexContentContext context) {}
public virtual void Activated(ActivatedContentContext context) {
}
public virtual void Initializing(InitializingContentContext context) {
}
public virtual void Creating(CreateContentContext context) {
}
public virtual void Created(CreateContentContext context) {
}
public virtual void Saving(SaveContentContext context) {
}
public virtual void Saved(SaveContentContext context) {
}
public virtual void Loading(LoadContentContext context) {
}
public virtual void Loaded(LoadContentContext context) {
}
public virtual void Versioning(VersionContentContext context) {
}
public virtual void Versioned(VersionContentContext context) {
}
public virtual void Publishing(PublishContentContext context) {
}
public virtual void Published(PublishContentContext context) {
}
public virtual void Removing(RemoveContentContext context) {
}
public virtual void Removed(RemoveContentContext context) {
}
public virtual void Indexing(IndexContentContext context) {
}
public virtual void Indexed(IndexContentContext context) {
}
public virtual void GetContentItemMetadata(GetContentItemMetadataContext context) {
}
public virtual void BuildDisplayModel(BuildDisplayModelContext context) {
}
public virtual void BuildEditorModel(BuildEditorModelContext context) {
}
public virtual void UpdateEditorModel(UpdateEditorModelContext context) {
}
public virtual void GetContentItemMetadata(GetContentItemMetadataContext context) {}
public virtual void BuildDisplayShape(BuildDisplayModelContext context) {}
public virtual void BuildEditorShape(BuildEditorModelContext context) {}
public virtual void UpdateEditorShape(UpdateEditorModelContext context) {}
}
}

View File

@@ -22,7 +22,7 @@ namespace Orchard.ContentManagement.Handlers {
_updater = (context, viewModel) => context.Updater.TryUpdateModel(viewModel, "", null, null);
}
protected override void BuildDisplayModel(BuildDisplayModelContext context, TContent instance) {
protected override void BuildDisplayShape(BuildDisplayModelContext context, TContent instance) {
context.ViewModel.TemplateName = _templateName;
var longestMatch = LongestMatch(context.DisplayType);
if (!string.IsNullOrEmpty(longestMatch))
@@ -54,7 +54,7 @@ namespace Orchard.ContentManagement.Handlers {
});
}
protected override void BuildEditorModel(BuildEditorModelContext context, TContent instance) {
protected override void BuildEditorShape(BuildEditorModelContext context, TContent instance) {
context.ViewModel.TemplateName = _templateName;
context.ViewModel.Prefix = _prefix;
if (context.ViewModel.GetType() != typeof(ContentItemViewModel<TContent>)) {
@@ -67,7 +67,7 @@ namespace Orchard.ContentManagement.Handlers {
}
}
protected override void UpdateEditorModel(UpdateEditorModelContext context, TContent instance) {
protected override void UpdateEditorShape(UpdateEditorModelContext context, TContent instance) {
if (context.ViewModel is ContentItemViewModel<TContent>)
_updater(context, (ContentItemViewModel<TContent>)context.ViewModel);
else

Some files were not shown because too many files have changed in this diff Show More