diff --git a/AzurePackage.proj b/AzurePackage.proj index 1155e34c4..0a876e275 100644 --- a/AzurePackage.proj +++ b/AzurePackage.proj @@ -99,6 +99,14 @@ XPath="/configuration/system.web/compilation/@debug" Value="false" /> + + + + diff --git a/Orchard.proj b/Orchard.proj index 00e76724f..84644851d 100644 --- a/Orchard.proj +++ b/Orchard.proj @@ -170,6 +170,14 @@ XPath="/configuration/system.web/compilation/@debug" Value="false" /> + + + + diff --git a/src/Orchard.Azure/Orchard.Azure.Web/Web.Debug.config b/src/Orchard.Azure/Orchard.Azure.Web/Web.Debug.config index 1ae4a73f1..5b18590d2 100644 --- a/src/Orchard.Azure/Orchard.Azure.Web/Web.Debug.config +++ b/src/Orchard.Azure/Orchard.Azure.Web/Web.Debug.config @@ -2,7 +2,8 @@ - + + \ No newline at end of file diff --git a/src/Orchard.Azure/Orchard.Azure.Web/Web.Release.config b/src/Orchard.Azure/Orchard.Azure.Web/Web.Release.config index 1ae4a73f1..5b18590d2 100644 --- a/src/Orchard.Azure/Orchard.Azure.Web/Web.Release.config +++ b/src/Orchard.Azure/Orchard.Azure.Web/Web.Release.config @@ -2,7 +2,8 @@ - + + \ No newline at end of file diff --git a/src/Orchard.Azure/Orchard.Azure.Web/Web.config b/src/Orchard.Azure/Orchard.Azure.Web/Web.config index 46814700e..d2cee7743 100644 --- a/src/Orchard.Azure/Orchard.Azure.Web/Web.config +++ b/src/Orchard.Azure/Orchard.Azure.Web/Web.config @@ -19,6 +19,7 @@ + + + + + + + + + + + + + + + + diff --git a/src/Orchard.Web/Core/Navigation/Controllers/AdminController.cs b/src/Orchard.Web/Core/Navigation/Controllers/AdminController.cs index bc3cbaa8a..ace752671 100644 --- a/src/Orchard.Web/Core/Navigation/Controllers/AdminController.cs +++ b/src/Orchard.Web/Core/Navigation/Controllers/AdminController.cs @@ -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(MenuItemPartDriver.ContentType.Name); - model.MenuItem = _services.ContentManager.UpdateEditorModel(menuPart, this); + var menuPart = _services.ContentManager.New("MenuItem"); + model.MenuItem = _services.ContentManager.UpdateEditorShape(menuPart, this); if (!ModelState.IsValid) { _services.TransactionManager.Cancel(); diff --git a/src/Orchard.Web/Core/Navigation/Drivers/MenuItemPartDriver.cs b/src/Orchard.Web/Core/Navigation/Drivers/MenuItemPartDriver.cs index ce483d2bf..b9364f8cd 100644 --- a/src/Orchard.Web/Core/Navigation/Drivers/MenuItemPartDriver.cs +++ b/src/Orchard.Web/Core/Navigation/Drivers/MenuItemPartDriver.cs @@ -6,32 +6,20 @@ using Orchard.Security; namespace Orchard.Core.Navigation.Drivers { [UsedImplicitly] - public class MenuItemPartDriver : ContentItemDriver { + public class MenuItemPartDriver : ContentPartDriver { 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); diff --git a/src/Orchard.Web/Core/Navigation/Handlers/MenuItemPartHandler.cs b/src/Orchard.Web/Core/Navigation/Handlers/MenuItemPartHandler.cs index 54d9bf791..d4c6bfcb3 100644 --- a/src/Orchard.Web/Core/Navigation/Handlers/MenuItemPartHandler.cs +++ b/src/Orchard.Web/Core/Navigation/Handlers/MenuItemPartHandler.cs @@ -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 repository) { - Filters.Add(new ActivatingFilter(MenuItemPartDriver.ContentType.Name)); + Filters.Add(new ActivatingFilter("MenuItem")); Filters.Add(StorageFilter.For(repository)); } } diff --git a/src/Orchard.Web/Core/Orchard.Core.csproj b/src/Orchard.Web/Core/Orchard.Core.csproj index 875b453e4..dab4ff1ae 100644 --- a/src/Orchard.Web/Core/Orchard.Core.csproj +++ b/src/Orchard.Web/Core/Orchard.Core.csproj @@ -82,7 +82,6 @@ - @@ -91,6 +90,13 @@ + + + + + + + @@ -196,7 +202,6 @@ - @@ -248,6 +253,8 @@ + + @@ -366,6 +373,7 @@ + diff --git a/src/Orchard.Web/Core/Routable/Controllers/ItemController.cs b/src/Orchard.Web/Core/Routable/Controllers/ItemController.cs index 5b9b29a4a..a70a26d69 100644 --- a/src/Orchard.Web/Core/Routable/Controllers/ItemController.cs +++ b/src/Orchard.Web/Core/Routable/Controllers/ItemController.cs @@ -40,7 +40,7 @@ namespace Orchard.Core.Routable.Controllers { throw new ApplicationException("Ambiguous content"); } var model = new RoutableDisplayViewModel { - Routable = _contentManager.BuildDisplayModel(hits.Single(), "Detail") + Routable = _contentManager.BuildDisplayShape(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().Slug ?? slug); diff --git a/src/Orchard.Web/Core/Routable/Services/RoutableHomePageProvider.cs b/src/Orchard.Web/Core/Routable/Services/RoutableHomePageProvider.cs index 3b0fb653d..d63d3f32a 100644 --- a/src/Orchard.Web/Core/Routable/Services/RoutableHomePageProvider.cs +++ b/src/Orchard.Web/Core/Routable/Services/RoutableHomePageProvider.cs @@ -37,7 +37,7 @@ namespace Orchard.Core.Routable.Services { return new NotFoundResult(); var model = new RoutableDisplayViewModel { - Routable = _contentManager.BuildDisplayModel(contentItem.As(), "Detail") + Routable = _contentManager.BuildDisplayShape(contentItem.As(), "Detail") }; return new ViewResult { diff --git a/src/Orchard.Web/Core/Settings/Controllers/AdminController.cs b/src/Orchard.Web/Core/Settings/Controllers/AdminController.cs index 60fdad4bf..0e357e4c7 100644 --- a/src/Orchard.Web/Core/Settings/Controllers/AdminController.cs +++ b/src/Orchard.Web/Core/Settings/Controllers/AdminController.cs @@ -33,7 +33,7 @@ namespace Orchard.Core.Settings.Controllers { Site = _siteService.GetSiteSettings().As(), 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() }; - viewModel.ViewModel = Services.ContentManager.UpdateEditorModel(viewModel.Site.ContentItem, this); + viewModel.ViewModel = Services.ContentManager.UpdateEditorShape(viewModel.Site.ContentItem, this); if (!TryUpdateModel(viewModel)) { return View(viewModel); diff --git a/src/Orchard.Web/Core/Settings/Drivers/SiteSettingsPartDriver.cs b/src/Orchard.Web/Core/Settings/Drivers/SiteSettingsPartDriver.cs deleted file mode 100644 index ca7a62f60..000000000 --- a/src/Orchard.Web/Core/Settings/Drivers/SiteSettingsPartDriver.cs +++ /dev/null @@ -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 { - 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"); - } - } -} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.DevTools/Controllers/ContentController.cs b/src/Orchard.Web/Modules/Orchard.DevTools/Controllers/ContentController.cs index d180c2cbb..0bbc3c75b 100644 --- a/src/Orchard.Web/Modules/Orchard.DevTools/Controllers/ContentController.cs +++ b/src/Orchard.Web/Modules/Orchard.DevTools/Controllers/ContentController.cs @@ -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); } diff --git a/src/Orchard.Web/Modules/Orchard.DevTools/Handlers/DebugLinkHandler.cs b/src/Orchard.Web/Modules/Orchard.DevTools/Handlers/DebugLinkHandler.cs index 1348ce75f..9162d5c4c 100644 --- a/src/Orchard.Web/Modules/Orchard.DevTools/Handlers/DebugLinkHandler.cs +++ b/src/Orchard.Web/Modules/Orchard.DevTools/Handlers/DebugLinkHandler.cs @@ -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(); 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(); if (devToolsSettings.ShowDebugLinks) context.AddEditor(new TemplateViewModel(new ShowDebugLink { ContentItem = context.ContentItem }) { TemplateName = "Parts/DevTools.ShowDebugLink", ZoneName = "recap", Position = "9999" }); diff --git a/src/Orchard.Web/Modules/Orchard.Email/DataMigrations/EmailDataMigration.cs b/src/Orchard.Web/Modules/Orchard.Email/DataMigrations/EmailDataMigration.cs new file mode 100644 index 000000000..e60fb7e6a --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Email/DataMigrations/EmailDataMigration.cs @@ -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("Address") + .Column("Host") + .Column("Port") + .Column("EnableSsl") + .Column("RequireCredentials") + .Column("UserName") + .Column("Password") + ); + + return 1; + } + } +} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Email/Drivers/SmtpSettingsPartDriver.cs b/src/Orchard.Web/Modules/Orchard.Email/Drivers/SmtpSettingsPartDriver.cs new file mode 100644 index 000000000..eb936c5ad --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Email/Drivers/SmtpSettingsPartDriver.cs @@ -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 { + 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); + } + } +} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Email/Handlers/SmtpSettingsPartHandler.cs b/src/Orchard.Web/Modules/Orchard.Email/Handlers/SmtpSettingsPartHandler.cs new file mode 100644 index 000000000..dda95b909 --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Email/Handlers/SmtpSettingsPartHandler.cs @@ -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 repository) { + Filters.Add(new ActivatingFilter("Site")); + Filters.Add(StorageFilter.For(repository)); + } + } +} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Email/Models/SmtpSettingsPart.cs b/src/Orchard.Web/Modules/Orchard.Email/Models/SmtpSettingsPart.cs new file mode 100644 index 000000000..964d022df --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Email/Models/SmtpSettingsPart.cs @@ -0,0 +1,49 @@ +using System.Text; +using System.Web.Security; +using Orchard.ContentManagement; +using System; + +namespace Orchard.Email.Models { + public class SmtpSettingsPart : ContentPart { + 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); } + } + } +} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Email/Models/SmtpSettingsPartRecord.cs b/src/Orchard.Web/Modules/Orchard.Email/Models/SmtpSettingsPartRecord.cs new file mode 100644 index 000000000..a9d3950e6 --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Email/Models/SmtpSettingsPartRecord.cs @@ -0,0 +1,48 @@ +using System.Net.Mail; +using Orchard.ContentManagement.Records; +using System.ComponentModel.DataAnnotations; + +namespace Orchard.Email.Models { + public class SmtpSettingsPartRecord : ContentPartRecord { + /// + /// From address in the mail message + /// + public virtual string Address { get; set; } + + /// + /// Server name hosting the SMTP service + /// + public virtual string Host { get; set; } + + /// + /// Port number on which SMTP service runs + /// + public virtual int Port { get; set; } + + /// + /// Whether to enable SSL communications with the server + /// + public virtual bool EnableSsl { get; set; } + + /// + /// Whether specific credentials should be used + /// + public virtual bool RequireCredentials { get; set; } + + /// + /// The username to connect to the SMTP server if DefaultCredentials is False + /// + public virtual string UserName { get; set; } + + /// + /// The password to connect to the SMTP server if DefaultCredentials is False + /// + public virtual string Password { get; set; } + + public SmtpSettingsPartRecord() { + Port = 25; + RequireCredentials = false; + EnableSsl = false; + } + } +} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Email/Module.txt b/src/Orchard.Web/Modules/Orchard.Email/Module.txt new file mode 100644 index 000000000..6c7d3a8f3 --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Email/Module.txt @@ -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 diff --git a/src/Orchard.Web/Modules/Orchard.Email/Orchard.Email.csproj b/src/Orchard.Web/Modules/Orchard.Email/Orchard.Email.csproj new file mode 100644 index 000000000..5848e615c --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Email/Orchard.Email.csproj @@ -0,0 +1,142 @@ + + + + Debug + AnyCPU + 9.0.30729 + 2.0 + {05660F47-D649-48BD-9DED-DF4E01E7CFF9} + {F85E285D-A4E0-4152-9332-AB1D724D3325};{349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc} + Library + Properties + Orchard.Email + Orchard.Email + v4.0 + false + + + 3.5 + + + + + true + full + false + bin\ + DEBUG;TRACE + prompt + 4 + AllRules.ruleset + + + pdbonly + true + bin\ + TRACE + prompt + 4 + AllRules.ruleset + + + + + + 3.5 + + + + + + + + False + ..\..\..\..\lib\aspnetmvc\System.Web.Mvc.dll + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {2D1D92BB-4555-4CBE-8D0E-63563D6CE4C6} + Orchard.Framework + + + {9916839C-39FC-4CEB-A5AF-89CA7E87119F} + Orchard.Core + + + {79AED36E-ABD0-4747-93D3-8722B042454B} + Orchard.Users + + + + + + + + + $(ProjectDir)\..\Manifests + + + + + + + + + + + + False + True + 45979 + / + + + False + True + http://orchard.codeplex.com + False + + + + + \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Email/Properties/AssemblyInfo.cs b/src/Orchard.Web/Modules/Orchard.Email/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..ea6abdcf2 --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Email/Properties/AssemblyInfo.cs @@ -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")] diff --git a/src/Orchard.Web/Modules/Orchard.Email/Services/EmailMessageEventHandler.cs b/src/Orchard.Web/Modules/Orchard.Email/Services/EmailMessageEventHandler.cs new file mode 100644 index 000000000..e67ace915 --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Email/Services/EmailMessageEventHandler.cs @@ -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(); + if ( recipient == null ) + return; + + context.MailMessage.To.Add(recipient.Email); + } + + public void Sent(MessageContext context) { + } + } +} diff --git a/src/Orchard.Web/Modules/Orchard.Email/Services/EmailMessagingChannel.cs b/src/Orchard.Web/Modules/Orchard.Email/Services/EmailMessagingChannel.cs new file mode 100644 index 000000000..ddff31e2a --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Email/Services/EmailMessagingChannel.cs @@ -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(); + + // 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 GetAvailableServices() { + return new[] {EmailService}; + } + } +} diff --git a/src/Orchard.Web/Modules/Orchard.Email/Services/MissingSettingsBanner.cs b/src/Orchard.Web/Modules/Orchard.Email/Services/MissingSettingsBanner.cs new file mode 100644 index 000000000..d35cbe328 --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Email/Services/MissingSettingsBanner.cs @@ -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 GetNotifications() { + + var smtpSettings = CurrentSite.As(); + + 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().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 }; + } + } + } +} diff --git a/src/Orchard.Web/Modules/Orchard.Email/Views/EditorTemplates/Parts/Smtp.SiteSettings.ascx b/src/Orchard.Web/Modules/Orchard.Email/Views/EditorTemplates/Parts/Smtp.SiteSettings.ascx new file mode 100644 index 000000000..a6ac4e3f6 --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Email/Views/EditorTemplates/Parts/Smtp.SiteSettings.ascx @@ -0,0 +1,43 @@ +<%@ Control Language="C#" Inherits="Orchard.Mvc.ViewUserControl" %> +<%@ Import Namespace="Orchard.Email.Models"%> +<%@ Import Namespace="System.Net.Mail" %> +
+ <%: T("SMTP")%> +
+ + <%: Html.EditorFor(m => m.Address)%> + <%: Html.ValidationMessage("Address", "*")%> +
+
+ + <%: Html.EditorFor(m => m.Host)%> + <%: Html.ValidationMessage("Host", "*")%> +
+
+ + <%: Html.EditorFor(m => m.Port)%> + <%: Html.ValidationMessage("Port", "*")%> +
+
+ <%: Html.EditorFor(m => m.EnableSsl)%> + + <%: Html.ValidationMessage("EnableSsl", "*")%> +
+
+ <%: Html.EditorFor(m => m.RequireCredentials)%> + + <%: Html.ValidationMessage("RequireCredentials", "*")%> +
+
+
+ + <%: Html.EditorFor(m => m.UserName)%> + <%: Html.ValidationMessage("UserName", "*")%> +
+
+ + <%: Html.PasswordFor(m => m.Password)%> + <%: Html.ValidationMessage("Password", "*")%> +
+
+
\ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Email/Views/Web.config b/src/Orchard.Web/Modules/Orchard.Email/Views/Web.config new file mode 100644 index 000000000..e065d8735 --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Email/Views/Web.config @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Orchard.Web/Modules/Orchard.Email/Web.config b/src/Orchard.Web/Modules/Orchard.Email/Web.config new file mode 100644 index 000000000..31fcd0c21 --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Email/Web.config @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Orchard.Web/Modules/Orchard.Setup/Controllers/SetupController.cs b/src/Orchard.Web/Modules/Orchard.Setup/Controllers/SetupController.cs index e901b031a..5e37f7e4e 100644 --- a/src/Orchard.Web/Modules/Orchard.Setup/Controllers/SetupController.cs +++ b/src/Orchard.Web/Modules/Orchard.Setup/Controllers/SetupController.cs @@ -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 ", 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); } diff --git a/src/Orchard.Web/Modules/Orchard.Setup/Services/SetupService.cs b/src/Orchard.Web/Modules/Orchard.Setup/Services/SetupService.cs index 0edc9c573..7c413db23 100644 --- a/src/Orchard.Web/Modules/Orchard.Setup/Services/SetupService.cs +++ b/src/Orchard.Web/Modules/Orchard.Setup/Services/SetupService.cs @@ -77,6 +77,7 @@ namespace Orchard.Setup.Services { "Routable", "Settings", //"XmlRpc", + "Messaging", "Orchard.Users", "Orchard.Roles", //"TinyMce", diff --git a/src/Orchard.Web/Modules/Orchard.Users/Content/Admin/images/offline.gif b/src/Orchard.Web/Modules/Orchard.Users/Content/Admin/images/offline.gif new file mode 100644 index 000000000..42c8bde22 Binary files /dev/null and b/src/Orchard.Web/Modules/Orchard.Users/Content/Admin/images/offline.gif differ diff --git a/src/Orchard.Web/Modules/Orchard.Users/Content/Admin/images/online.gif b/src/Orchard.Web/Modules/Orchard.Users/Content/Admin/images/online.gif new file mode 100644 index 000000000..f55c73a2f Binary files /dev/null and b/src/Orchard.Web/Modules/Orchard.Users/Content/Admin/images/online.gif differ diff --git a/src/Orchard.Web/Modules/Orchard.Users/Controllers/AccountController.cs b/src/Orchard.Web/Modules/Orchard.Users/Controllers/AccountController.cs index 6432ce1c0..a6057bd1f 100644 --- a/src/Orchard.Web/Modules/Orchard.Users/Controllers/AccountController.cs +++ b/src/Orchard.Web/Modules/Orchard.Users/Controllers/AccountController.cs @@ -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(); + 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(); + 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().EmailStatus == UserStatus.Pending ) { + string challengeToken = _membershipService.GetEncryptedChallengeToken(user.As()); + _membershipService.SendChallengeEmail(user.As(), 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."); diff --git a/src/Orchard.Web/Modules/Orchard.Users/Controllers/AdminController.cs b/src/Orchard.Web/Modules/Orchard.Users/Controllers/AdminController.cs index ab768eab5..ae8ddd258 100644 --- a/src/Orchard.Web/Modules/Orchard.Users/Controllers/AdminController.cs +++ b/src/Orchard.Web/Modules/Orchard.Users/Controllers/AdminController.cs @@ -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(UserPartDriver.ContentType.Name); + var user = Services.ContentManager.New("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(UserPartDriver.ContentType.Name); - model.User = Services.ContentManager.UpdateEditorModel(user, this); + var user = Services.ContentManager.New("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(id) + User = Services.ContentManager.BuildEditorShape(id) }); } @@ -109,7 +112,7 @@ namespace Orchard.Users.Controllers { return new HttpUnauthorizedResult(); var model = new UserEditViewModel { - User = Services.ContentManager.UpdateEditorModel(id, this) + User = Services.ContentManager.UpdateEditorShape(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()); + _membershipService.SendChallengeEmail(user.As(), 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().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().UserName) ) { + Services.Notifier.Error(T("Super user can't be moderated")); + } + else { + user.As().RegistrationStatus = UserStatus.Pending; + Services.Notifier.Information(T("User moderated")); + } + } + + return RedirectToAction("Index"); + } + bool IUpdateModel.TryUpdateModel(TModel model, string prefix, string[] includeProperties, string[] excludeProperties) { return TryUpdateModel(model, prefix, includeProperties, excludeProperties); } diff --git a/src/Orchard.Web/Modules/Orchard.Users/DataMigrations/UsersDataMigration.cs b/src/Orchard.Web/Modules/Orchard.Users/DataMigrations/UsersDataMigration.cs index f3fdeeed5..95b725ffb 100644 --- a/src/Orchard.Web/Modules/Orchard.Users/DataMigrations/UsersDataMigration.cs +++ b/src/Orchard.Web/Modules/Orchard.Users/DataMigrations/UsersDataMigration.cs @@ -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("RegistrationStatus", c => c.WithDefault("'Approved'"))) + .AlterTable("UserPartRecord", table => table.AddColumn("EmailStatus", c => c.WithDefault("'Approved'"))) + .AlterTable("UserPartRecord", table => table.AddColumn("EmailChallengeToken")); + + // Site Settings record + SchemaBuilder.CreateTable("RegistrationSettingsPartRecord", table => table + .ContentPartRecord() + .Column("UsersCanRegister", c => c.WithDefault("'0'")) + .Column("UsersMustValidateEmail", c => c.WithDefault("'0'")) + .Column("UsersAreModerated", c => c.WithDefault("'0'")) + .Column("NotifyModeration", c => c.WithDefault("'0'")) + ); + + return 2; + } } } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Users/Drivers/UserPartDriver.cs b/src/Orchard.Web/Modules/Orchard.Users/Drivers/UserPartDriver.cs deleted file mode 100644 index aa3d73366..000000000 --- a/src/Orchard.Web/Modules/Orchard.Users/Drivers/UserPartDriver.cs +++ /dev/null @@ -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 { - 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}, - }; - } - } -} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Users/Events/IUserEventHandler.cs b/src/Orchard.Web/Modules/Orchard.Users/Events/IUserEventHandler.cs new file mode 100644 index 000000000..79b0962ed --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Users/Events/IUserEventHandler.cs @@ -0,0 +1,16 @@ +using Orchard.Events; + +namespace Orchard.Users.Events { + public interface IUserEventHandler : IEventHandler { + /// + /// Called before a User is created + /// + void Creating(UserContext context); + + /// + /// Called once a user has been created + /// + void Created(UserContext context); + } +} + diff --git a/src/Orchard.Web/Modules/Orchard.Users/Events/UserContext.cs b/src/Orchard.Web/Modules/Orchard.Users/Events/UserContext.cs new file mode 100644 index 000000000..9ae60fae2 --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Users/Events/UserContext.cs @@ -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; } + } +} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Users/Handlers/ModerationMessageAlteration.cs b/src/Orchard.Web/Modules/Orchard.Users/Handlers/ModerationMessageAlteration.cs new file mode 100644 index 000000000..ac2b0d46a --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Users/Handlers/ModerationMessageAlteration.cs @@ -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(); + 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 click here to validate you email address.", recipient.UserName, context.Properties["ChallengeUrl"]); + } + + } + + public void Sent(MessageContext context) { + } + } +} diff --git a/src/Orchard.Web/Modules/Orchard.Users/Handlers/RegistrationSettingsPartHandler.cs b/src/Orchard.Web/Modules/Orchard.Users/Handlers/RegistrationSettingsPartHandler.cs new file mode 100644 index 000000000..7d9997758 --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Users/Handlers/RegistrationSettingsPartHandler.cs @@ -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 repository) { + Filters.Add(new ActivatingFilter("Site")); + Filters.Add(StorageFilter.For(repository)); + Filters.Add(new TemplateFilterForRecord("RegistrationSettings", "Parts/Users.RegistrationSettings")); + } + } +} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Users/Handlers/UserPartHandler.cs b/src/Orchard.Web/Modules/Orchard.Users/Handlers/UserPartHandler.cs index 125ef34fa..aa85d108f 100644 --- a/src/Orchard.Web/Modules/Orchard.Users/Handlers/UserPartHandler.cs +++ b/src/Orchard.Web/Modules/Orchard.Users/Handlers/UserPartHandler.cs @@ -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 repository) { - Filters.Add(new ActivatingFilter(UserPartDriver.ContentType.Name)); + Filters.Add(new ActivatingFilter("User")); Filters.Add(StorageFilter.For(repository)); } } diff --git a/src/Orchard.Web/Modules/Orchard.Users/Models/MessageTypes.cs b/src/Orchard.Web/Modules/Orchard.Users/Models/MessageTypes.cs new file mode 100644 index 000000000..e63e44887 --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Users/Models/MessageTypes.cs @@ -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"; + + } +} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Users/Models/RegistrationSettingsPart.cs b/src/Orchard.Web/Modules/Orchard.Users/Models/RegistrationSettingsPart.cs new file mode 100644 index 000000000..2992b1d2a --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Users/Models/RegistrationSettingsPart.cs @@ -0,0 +1,27 @@ +using Orchard.ContentManagement; +using System; + +namespace Orchard.Users.Models { + public class RegistrationSettingsPart : ContentPart { + 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; } + } + + } +} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Users/Models/RegistrationSettingsPartRecord.cs b/src/Orchard.Web/Modules/Orchard.Users/Models/RegistrationSettingsPartRecord.cs new file mode 100644 index 000000000..3a2c5d3f2 --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Users/Models/RegistrationSettingsPartRecord.cs @@ -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; } + } +} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Users/Models/UserPart.cs b/src/Orchard.Web/Modules/Orchard.Users/Models/UserPart.cs index 99ed50bed..097e4a209 100644 --- a/src/Orchard.Web/Modules/Orchard.Users/Models/UserPart.cs +++ b/src/Orchard.Web/Modules/Orchard.Users/Models/UserPart.cs @@ -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; } + } } } diff --git a/src/Orchard.Web/Modules/Orchard.Users/Models/UserPartRecord.cs b/src/Orchard.Web/Modules/Orchard.Users/Models/UserPartRecord.cs index 459081fdf..c6c8c2cff 100644 --- a/src/Orchard.Web/Modules/Orchard.Users/Models/UserPartRecord.cs +++ b/src/Orchard.Web/Modules/Orchard.Users/Models/UserPartRecord.cs @@ -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; } } } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Users/Models/UserStatus.cs b/src/Orchard.Web/Modules/Orchard.Users/Models/UserStatus.cs new file mode 100644 index 000000000..a41b43964 --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Users/Models/UserStatus.cs @@ -0,0 +1,6 @@ +namespace Orchard.Users.Models { + public enum UserStatus { + Pending, + Approved + } +} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Users/Orchard.Users.csproj b/src/Orchard.Web/Modules/Orchard.Users/Orchard.Users.csproj index e5f254eef..e5aab7b6d 100644 --- a/src/Orchard.Web/Modules/Orchard.Users/Orchard.Users.csproj +++ b/src/Orchard.Web/Modules/Orchard.Users/Orchard.Users.csproj @@ -45,6 +45,7 @@ 3.5 + @@ -68,10 +69,17 @@ - + + + + + + + + @@ -84,10 +92,15 @@ + + + + + @@ -95,6 +108,7 @@ + diff --git a/src/Orchard.Web/Modules/Orchard.Users/Services/MembershipService.cs b/src/Orchard.Web/Modules/Orchard.Users/Services/MembershipService.cs index 9c432b86a..5d65b1212 100644 --- a/src/Orchard.Web/Modules/Orchard.Users/Services/MembershipService.cs +++ b/src/Orchard.Web/Modules/Orchard.Users/Services/MembershipService.cs @@ -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 _userRepository; + private readonly IMessageManager _messageManager; + private readonly IEnumerable _userEventHandlers; - public MembershipService(IContentManager contentManager, IRepository userRepository) { + public MembershipService(IContentManager contentManager, IMessageManager messageManager, IEnumerable 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(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(); + + var user = _contentManager.New("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 { { "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().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(userRecord.Id); + return _contentManager.Query().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().Where(u => u.NormalizedUserName == lowerName).List().FirstOrDefault(); + + if(user == null) + user = _contentManager.Query().Where(u => u.Email == lowerName).List().FirstOrDefault(); + + if ( user == null || ValidatePassword(user.As().Record, password) == false ) return null; - return _contentManager.Get(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()) 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 @@ -147,7 +239,7 @@ namespace Orchard.Users.Services { var hashAlgorithm = HashAlgorithm.Create(partRecord.HashAlgorithm); var hashBytes = hashAlgorithm.ComputeHash(combinedBytes); - + return partRecord.Password == Convert.ToBase64String(hashBytes); } @@ -158,5 +250,6 @@ namespace Orchard.Users.Services { private static bool ValidatePasswordEncrypted(UserPartRecord partRecord, string password) { throw new NotImplementedException(); } + } } diff --git a/src/Orchard.Web/Modules/Orchard.Users/Views/Account/ChallengeEmailFail.ascx b/src/Orchard.Web/Modules/Orchard.Users/Views/Account/ChallengeEmailFail.ascx new file mode 100644 index 000000000..647e83954 --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Users/Views/Account/ChallengeEmailFail.ascx @@ -0,0 +1,3 @@ +<%@ Control Language="C#" Inherits="Orchard.Mvc.ViewUserControl" %> +

<%: Html.TitleForPage(T("Challenge Email").ToString()) %>

+

<%: T("Your email address could not be validated.") %>

diff --git a/src/Orchard.Web/Modules/Orchard.Users/Views/Account/ChallengeEmailSent.ascx b/src/Orchard.Web/Modules/Orchard.Users/Views/Account/ChallengeEmailSent.ascx new file mode 100644 index 000000000..1f4c973ea --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Users/Views/Account/ChallengeEmailSent.ascx @@ -0,0 +1,3 @@ +<%@ Control Language="C#" Inherits="Orchard.Mvc.ViewUserControl" %> +

<%: Html.TitleForPage(T("Challenge Email Sent").ToString()) %>

+

<%: T("An email has been sent to you. Please click on the link it contains in order to have access on this site.") %>

diff --git a/src/Orchard.Web/Modules/Orchard.Users/Views/Account/ChallengeEmailSuccess.ascx b/src/Orchard.Web/Modules/Orchard.Users/Views/Account/ChallengeEmailSuccess.ascx new file mode 100644 index 000000000..d7b8a4d1a --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Users/Views/Account/ChallengeEmailSuccess.ascx @@ -0,0 +1,3 @@ +<%@ Control Language="C#" Inherits="Orchard.Mvc.ViewUserControl" %> +

<%: Html.TitleForPage(T("Challenge Email").ToString()) %>

+

<%: T("Your email address has been validated.") %>

diff --git a/src/Orchard.Web/Modules/Orchard.Users/Views/Admin/Index.aspx b/src/Orchard.Web/Modules/Orchard.Users/Views/Admin/Index.aspx index 41cd5b2ed..1ae630b13 100644 --- a/src/Orchard.Web/Modules/Orchard.Users/Views/Admin/Index.aspx +++ b/src/Orchard.Web/Modules/Orchard.Users/Views/Admin/Index.aspx @@ -1,4 +1,5 @@ <%@ Page Language="C#" Inherits="Orchard.Mvc.ViewPage" %> +<%@ Import Namespace="Orchard.Users.Models" %> <%@ Import Namespace="Orchard.Users.ViewModels"%>

<%: Html.TitleForPage(T("Manage Users").ToString()) %>

<% using (Html.BeginFormAntiForgeryPost()) { %> @@ -22,6 +23,12 @@ { %> + <% if(row.UserPart.RegistrationStatus == UserStatus.Approved) { %> + " alt="<%:T("Approved") %>" title="<%:T("User is approved") %>" /> + <% } + else { %> + " alt="<%:T("Moderated") %>" title="<%:T("User is moderated") %>" /> + <% } %> <%: row.UserPart.UserName %> @@ -29,7 +36,11 @@ <%: 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 })%> + <% } %> <%}%> diff --git a/src/Orchard.Web/Modules/Orchard.Users/Views/EditorTemplates/Parts/Users.RegistrationSettings.ascx b/src/Orchard.Web/Modules/Orchard.Users/Views/EditorTemplates/Parts/Users.RegistrationSettings.ascx new file mode 100644 index 000000000..0b2ed2f7f --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Users/Views/EditorTemplates/Parts/Users.RegistrationSettings.ascx @@ -0,0 +1,25 @@ +<%@ Control Language="C#" Inherits="Orchard.Mvc.ViewUserControl" %> +<%@ Import Namespace="Orchard.Users.Models"%> +
+ <%: T("Users registration")%> +
+ <%: Html.EditorFor(m => m.UsersCanRegister) %> + + <%: Html.ValidationMessage("UsersCanRegister", "*")%> +
+
+ <%: Html.EditorFor(m => m.UsersMustValidateEmail)%> + + <%: Html.ValidationMessage("UsersMustValidateEmail", "*")%> +
+
+ <%: Html.EditorFor(m => m.UsersAreModerated)%> + + <%: Html.ValidationMessage("UsersAreModerated", "*")%> +
+
+ <%: Html.EditorFor(m => m.NotifyModeration)%> + + <%: Html.ValidationMessage("NotifyModeration", "*")%> +
+
\ No newline at end of file diff --git a/src/Orchard.Web/Web.config b/src/Orchard.Web/Web.config index 56ab3731f..0d8683f45 100644 --- a/src/Orchard.Web/Web.config +++ b/src/Orchard.Web/Web.config @@ -42,6 +42,8 @@ + + - - - - - - - - - diff --git a/src/Orchard/ContentManagement/ContentExtensions.cs b/src/Orchard/ContentManagement/ContentExtensions.cs index 1449c2aa4..bb061a598 100644 --- a/src/Orchard/ContentManagement/ContentExtensions.cs +++ b/src/Orchard/ContentManagement/ContentExtensions.cs @@ -165,26 +165,26 @@ namespace Orchard.ContentManagement { /* Display and editor convenience extension methods */ - public static ContentItemViewModel BuildDisplayModel(this IContentManager manager, int id, string displayType) where T : class, IContent { + public static ContentItemViewModel BuildDisplayShape(this IContentManager manager, int id, string displayType) where T : class, IContent { var content = manager.Get(id); if (content == null) return null; - return manager.BuildDisplayModel(content, displayType); + return manager.BuildDisplayShape(content, displayType); } - public static ContentItemViewModel BuildEditorModel(this IContentManager manager, int id) where T : class, IContent { + public static ContentItemViewModel BuildEditorShape(this IContentManager manager, int id) where T : class, IContent { var content = manager.Get(id); if (content == null) return null; - return manager.BuildEditorModel(content); + return manager.BuildEditorShape(content); } - public static ContentItemViewModel UpdateEditorModel(this IContentManager manager, int id, IUpdateModel updater) where T : class, IContent { + public static ContentItemViewModel UpdateEditorShape(this IContentManager manager, int id, IUpdateModel updater) where T : class, IContent { var content = manager.Get(id); if (content == null) return null; - return manager.UpdateEditorModel(content, updater); + return manager.UpdateEditorShape(content, updater); } diff --git a/src/Orchard/ContentManagement/DefaultContentManager.cs b/src/Orchard/ContentManagement/DefaultContentManager.cs index f30e1e566..3c7743f56 100644 --- a/src/Orchard/ContentManagement/DefaultContentManager.cs +++ b/src/Orchard/ContentManagement/DefaultContentManager.cs @@ -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(); + // 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 BuildDisplayModel(TContentPart content, string displayType) where TContentPart : IContent { + public ContentItemViewModel BuildDisplayShape(TContentPart content, string displayType) where TContentPart : IContent { if (content == null) return null; var displayModel = new ContentItemViewModel(content); var context = new BuildDisplayModelContext(displayModel, displayType); foreach (var handler in Handlers) { - handler.BuildDisplayModel(context); + handler.BuildDisplayShape(context); } return displayModel; } - public ContentItemViewModel BuildEditorModel(TContentPart content) where TContentPart : IContent { + public ContentItemViewModel BuildEditorShape(TContentPart content) where TContentPart : IContent { var editorModel = new ContentItemViewModel(content); var context = new BuildEditorModelContext(editorModel); foreach (var handler in Handlers) { - handler.BuildEditorModel(context); + handler.BuildEditorShape(context); } return editorModel; } - public ContentItemViewModel UpdateEditorModel(TContentPart content, IUpdateModel updater) where TContentPart : IContent { + public ContentItemViewModel UpdateEditorShape(TContentPart content, IUpdateModel updater) where TContentPart : IContent { var editorModel = new ContentItemViewModel(content); var context = new UpdateEditorModelContext(editorModel, updater); foreach (var handler in Handlers) { - handler.UpdateEditorModel(context); + handler.UpdateEditorShape(context); } return editorModel; } diff --git a/src/Orchard/ContentManagement/Drivers/ContentFieldDriver.cs b/src/Orchard/ContentManagement/Drivers/ContentFieldDriver.cs index 9e98216be..a3d8802cc 100644 --- a/src/Orchard/ContentManagement/Drivers/ContentFieldDriver.cs +++ b/src/Orchard/ContentManagement/Drivers/ContentFieldDriver.cs @@ -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)); } diff --git a/src/Orchard/ContentManagement/Drivers/ContentItemDriver.cs b/src/Orchard/ContentManagement/Drivers/ContentItemDriver.cs deleted file mode 100644 index 78eadf1b9..000000000 --- a/src/Orchard/ContentManagement/Drivers/ContentItemDriver.cs +++ /dev/null @@ -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 : ContentPartDriver, 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 IContentItemDriver.GetContentTypes() { - var contentType = GetContentType(); - return contentType != null ? new[] { contentType } : Enumerable.Empty(); - } - - void IContentItemDriver.GetContentItemMetadata(GetContentItemMetadataContext context) { - var item = context.ContentItem.As(); - 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(); - if (part == null) { - return null; - } - if (context.ViewModel.GetType() != typeof(ContentItemViewModel)) { - return Display(new ContentItemViewModel(context.ViewModel), context.DisplayType); - } - return Display((ContentItemViewModel)context.ViewModel, context.DisplayType); - } - - DriverResult IContentItemDriver.BuildEditorModel(BuildEditorModelContext context) { - var part = context.ContentItem.As(); - if (part == null) { - return null; - } - if (context.ViewModel.GetType() != typeof(ContentItemViewModel)) { - return Editor(new ContentItemViewModel(context.ViewModel)); - } - return Editor((ContentItemViewModel)context.ViewModel); - } - - DriverResult IContentItemDriver.UpdateEditorModel(UpdateEditorModelContext context) { - var part = context.ContentItem.As(); - if (part == null) { - return null; - } - if (context.ViewModel.GetType() != typeof(ContentItemViewModel)) { - return Editor(new ContentItemViewModel(context.ViewModel), context.Updater); - } - return Editor((ContentItemViewModel)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 viewModel, string displayType) { return GetDefaultItemTemplate(); } - protected virtual DriverResult Editor(ContentItemViewModel viewModel) { return GetDefaultItemTemplate(); } - protected virtual DriverResult Editor(ContentItemViewModel viewModel, IUpdateModel updater) { return GetDefaultItemTemplate(); } - - public ContentItemTemplateResult ContentItemTemplate(string templateName) { - return new ContentItemTemplateResult(templateName); - } - - private DriverResult GetDefaultItemTemplate() { - return UseDefaultTemplate - ? ContentItemTemplate("Items/ContentItem") - : null; - } - } -} \ No newline at end of file diff --git a/src/Orchard/ContentManagement/Drivers/ContentPartDriver.cs b/src/Orchard/ContentManagement/Drivers/ContentPartDriver.cs index 7cb49de85..702dbe936 100644 --- a/src/Orchard/ContentManagement/Drivers/ContentPartDriver.cs +++ b/src/Orchard/ContentManagement/Drivers/ContentPartDriver.cs @@ -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(); return part == null ? null : Display(part, context.DisplayType); } - DriverResult IContentPartDriver.BuildEditorModel(BuildEditorModelContext context) { + DriverResult IContentPartDriver.BuildEditorShape(BuildEditorModelContext context) { var part = context.ContentItem.As(); return part == null ? null : Editor(part); } - DriverResult IContentPartDriver.UpdateEditorModel(UpdateEditorModelContext context) { + DriverResult IContentPartDriver.UpdateEditorShape(UpdateEditorModelContext context) { var part = context.ContentItem.As(); return part == null ? null : Editor(part, context.Updater); } diff --git a/src/Orchard/ContentManagement/Drivers/Coordinators/ContentFieldDriverCoordinator.cs b/src/Orchard/ContentManagement/Drivers/Coordinators/ContentFieldDriverCoordinator.cs index c6f587a61..1682bf81a 100644 --- a/src/Orchard/ContentManagement/Drivers/Coordinators/ContentFieldDriverCoordinator.cs +++ b/src/Orchard/ContentManagement/Drivers/Coordinators/ContentFieldDriverCoordinator.cs @@ -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 - .GetProvider(partFieldDefinition) - .BindStorage(contentPart, partFieldDefinition); -var field = fieldInfo.Factory(partFieldDefinition, storage); -contentPart.Weld(field); + var storage = _fieldStorageProviderSelector + .GetProvider(partFieldDefinition) + .BindStorage(contentPart, partFieldDefinition); + 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); diff --git a/src/Orchard/ContentManagement/Drivers/Coordinators/ContentItemDriverCoordinator.cs b/src/Orchard/ContentManagement/Drivers/Coordinators/ContentItemDriverCoordinator.cs deleted file mode 100644 index 52fe45307..000000000 --- a/src/Orchard/ContentManagement/Drivers/Coordinators/ContentItemDriverCoordinator.cs +++ /dev/null @@ -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 _drivers; - - public ContentItemDriverCoordinator(IEnumerable drivers) { - _drivers = drivers; - Logger = NullLogger.Instance; - } - - public ILogger Logger { get; set; } - - public override IEnumerable GetContentTypes() { - var contentTypes = new List(); - _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); - } - } -} \ No newline at end of file diff --git a/src/Orchard/ContentManagement/Drivers/Coordinators/ContentPartDriverCoordinator.cs b/src/Orchard/ContentManagement/Drivers/Coordinators/ContentPartDriverCoordinator.cs index 2bf714406..74d5e34d9 100644 --- a/src/Orchard/ContentManagement/Drivers/Coordinators/ContentPartDriverCoordinator.cs +++ b/src/Orchard/ContentManagement/Drivers/Coordinators/ContentPartDriverCoordinator.cs @@ -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); diff --git a/src/Orchard/ContentManagement/Drivers/IContentFieldDriver.cs b/src/Orchard/ContentManagement/Drivers/IContentFieldDriver.cs index a62493aac..7135275d9 100644 --- a/src/Orchard/ContentManagement/Drivers/IContentFieldDriver.cs +++ b/src/Orchard/ContentManagement/Drivers/IContentFieldDriver.cs @@ -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 GetFieldInfo(); } diff --git a/src/Orchard/ContentManagement/Drivers/IContentItemDriver.cs b/src/Orchard/ContentManagement/Drivers/IContentItemDriver.cs deleted file mode 100644 index 182c776e4..000000000 --- a/src/Orchard/ContentManagement/Drivers/IContentItemDriver.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System.Collections.Generic; -using Orchard.ContentManagement.Handlers; - -namespace Orchard.ContentManagement.Drivers { - public interface IContentItemDriver : IEvents { - IEnumerable GetContentTypes(); - void GetContentItemMetadata(GetContentItemMetadataContext context); - - DriverResult BuildDisplayModel(BuildDisplayModelContext context); - DriverResult BuildEditorModel(BuildEditorModelContext context); - DriverResult UpdateEditorModel(UpdateEditorModelContext context); - } -} \ No newline at end of file diff --git a/src/Orchard/ContentManagement/Drivers/IContentPartDriver.cs b/src/Orchard/ContentManagement/Drivers/IContentPartDriver.cs index 3db5084e6..da1e0f30a 100644 --- a/src/Orchard/ContentManagement/Drivers/IContentPartDriver.cs +++ b/src/Orchard/ContentManagement/Drivers/IContentPartDriver.cs @@ -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 GetPartInfo(); } diff --git a/src/Orchard/ContentManagement/Handlers/ContentHandler.cs b/src/Orchard/ContentManagement/Handlers/ContentHandler.cs index 374bdb68e..50a0bdc76 100644 --- a/src/Orchard/ContentManagement/Handlers/ContentHandler.cs +++ b/src/Orchard/ContentManagement/Handlers/ContentHandler.cs @@ -80,16 +80,16 @@ namespace Orchard.ContentManagement.Handlers { protected void OnGetContentItemMetadata(Action handler) where TPart : class, IContent { Filters.Add(new InlineTemplateFilter { OnGetItemMetadata = handler }); } - protected void OnGetDisplayViewModel(Action handler) where TPart : class, IContent { - Filters.Add(new InlineTemplateFilter { OnGetDisplayViewModel = handler }); + protected void OnGetDisplayShape(Action handler) where TPart : class, IContent { + Filters.Add(new InlineTemplateFilter { OnGetDisplayShape = handler }); } - protected void OnGetEditorViewModel(Action handler) where TPart : class, IContent { - Filters.Add(new InlineTemplateFilter { OnGetEditorViewModel = handler }); + protected void OnGetEditorShape(Action handler) where TPart : class, IContent { + Filters.Add(new InlineTemplateFilter { OnGetEditorShape = handler }); } - protected void OnUpdateEditorViewModel(Action handler) where TPart : class, IContent { - Filters.Add(new InlineTemplateFilter { OnUpdateEditorViewModel = handler }); + protected void OnUpdateEditorShape(Action handler) where TPart : class, IContent { + Filters.Add(new InlineTemplateFilter { OnUpdateEditorShape = handler }); } class InlineStorageFilter : StorageFilterBase where TPart : class, IContent { @@ -164,20 +164,20 @@ namespace Orchard.ContentManagement.Handlers { class InlineTemplateFilter : TemplateFilterBase where TPart : class, IContent { public Action OnGetItemMetadata { get; set; } - public Action OnGetDisplayViewModel { get; set; } - public Action OnGetEditorViewModel { get; set; } - public Action OnUpdateEditorViewModel { get; set; } + public Action OnGetDisplayShape { get; set; } + public Action OnGetEditorShape { get; set; } + public Action 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()) - 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()) - 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()) - 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) { } } } \ No newline at end of file diff --git a/src/Orchard/ContentManagement/Handlers/ContentHandlerBase.cs b/src/Orchard/ContentManagement/Handlers/ContentHandlerBase.cs index 3d36b5200..c9a988601 100644 --- a/src/Orchard/ContentManagement/Handlers/ContentHandlerBase.cs +++ b/src/Orchard/ContentManagement/Handlers/ContentHandlerBase.cs @@ -7,67 +7,27 @@ namespace Orchard.ContentManagement.Handlers { return Enumerable.Empty(); } - 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) {} } } \ No newline at end of file diff --git a/src/Orchard/ContentManagement/Handlers/ContentItemTemplates.cs b/src/Orchard/ContentManagement/Handlers/ContentItemTemplates.cs index 95dc75681..850296cd1 100644 --- a/src/Orchard/ContentManagement/Handlers/ContentItemTemplates.cs +++ b/src/Orchard/ContentManagement/Handlers/ContentItemTemplates.cs @@ -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)) { @@ -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) _updater(context, (ContentItemViewModel)context.ViewModel); else diff --git a/src/Orchard/ContentManagement/Handlers/IContentHandler.cs b/src/Orchard/ContentManagement/Handlers/IContentHandler.cs index cac4cb0fb..44440e18f 100644 --- a/src/Orchard/ContentManagement/Handlers/IContentHandler.cs +++ b/src/Orchard/ContentManagement/Handlers/IContentHandler.cs @@ -23,8 +23,8 @@ namespace Orchard.ContentManagement.Handlers { void Indexed(IndexContentContext context); void GetContentItemMetadata(GetContentItemMetadataContext context); - void BuildDisplayModel(BuildDisplayModelContext context); - void BuildEditorModel(BuildEditorModelContext context); - void UpdateEditorModel(UpdateEditorModelContext context); + void BuildDisplayShape(BuildDisplayModelContext context); + void BuildEditorShape(BuildEditorModelContext context); + void UpdateEditorShape(UpdateEditorModelContext context); } } diff --git a/src/Orchard/ContentManagement/Handlers/IContentTemplateFilter.cs b/src/Orchard/ContentManagement/Handlers/IContentTemplateFilter.cs index 7152e333d..2767491d7 100644 --- a/src/Orchard/ContentManagement/Handlers/IContentTemplateFilter.cs +++ b/src/Orchard/ContentManagement/Handlers/IContentTemplateFilter.cs @@ -1,8 +1,8 @@ namespace Orchard.ContentManagement.Handlers { interface IContentTemplateFilter : IContentFilter { void GetContentItemMetadata(GetContentItemMetadataContext context); - void BuildDisplayModel(BuildDisplayModelContext context); - void BuildEditorModel(BuildEditorModelContext context); - void UpdateEditorModel(UpdateEditorModelContext context); + void BuildDisplayShape(BuildDisplayModelContext context); + void BuildEditorShape(BuildEditorModelContext context); + void UpdateEditorShape(UpdateEditorModelContext context); } } diff --git a/src/Orchard/ContentManagement/Handlers/TemplateFilterBase.cs b/src/Orchard/ContentManagement/Handlers/TemplateFilterBase.cs index ea45fd58b..0629fca1e 100644 --- a/src/Orchard/ContentManagement/Handlers/TemplateFilterBase.cs +++ b/src/Orchard/ContentManagement/Handlers/TemplateFilterBase.cs @@ -1,28 +1,28 @@ namespace Orchard.ContentManagement.Handlers { public abstract class TemplateFilterBase : IContentTemplateFilter where TPart : class, IContent { protected virtual void GetContentItemMetadata(GetContentItemMetadataContext context, TPart instance) { } - protected virtual void BuildDisplayModel(BuildDisplayModelContext context, TPart instance) { } - protected virtual void BuildEditorModel(BuildEditorModelContext context, TPart instance) { } - protected virtual void UpdateEditorModel(UpdateEditorModelContext context, TPart instance) { } + protected virtual void BuildDisplayShape(BuildDisplayModelContext context, TPart instance) { } + protected virtual void BuildEditorShape(BuildEditorModelContext context, TPart instance) { } + protected virtual void UpdateEditorShape(UpdateEditorModelContext context, TPart instance) { } void IContentTemplateFilter.GetContentItemMetadata(GetContentItemMetadataContext context) { if (context.ContentItem.Is()) GetContentItemMetadata(context, context.ContentItem.As()); } - void IContentTemplateFilter.BuildDisplayModel(BuildDisplayModelContext context) { + void IContentTemplateFilter.BuildDisplayShape(BuildDisplayModelContext context) { if (context.ContentItem.Is()) - BuildDisplayModel(context, context.ContentItem.As()); + BuildDisplayShape(context, context.ContentItem.As()); } - void IContentTemplateFilter.BuildEditorModel(BuildEditorModelContext context) { + void IContentTemplateFilter.BuildEditorShape(BuildEditorModelContext context) { if (context.ContentItem.Is()) - BuildEditorModel(context, context.ContentItem.As()); + BuildEditorShape(context, context.ContentItem.As()); } - void IContentTemplateFilter.UpdateEditorModel(UpdateEditorModelContext context) { + void IContentTemplateFilter.UpdateEditorShape(UpdateEditorModelContext context) { if (context.ContentItem.Is()) - UpdateEditorModel(context, context.ContentItem.As()); + UpdateEditorShape(context, context.ContentItem.As()); } } } diff --git a/src/Orchard/ContentManagement/Handlers/TemplateFilterForRecord.cs b/src/Orchard/ContentManagement/Handlers/TemplateFilterForRecord.cs index 7e6d74347..81a33884d 100644 --- a/src/Orchard/ContentManagement/Handlers/TemplateFilterForRecord.cs +++ b/src/Orchard/ContentManagement/Handlers/TemplateFilterForRecord.cs @@ -17,11 +17,11 @@ namespace Orchard.ContentManagement.Handlers { return this; } - protected override void BuildEditorModel(BuildEditorModelContext context, ContentPart part) { + protected override void BuildEditorShape(BuildEditorModelContext context, ContentPart part) { context.ViewModel.Zones.AddEditorPart(_location, part.Record, _templateName, _prefix); } - protected override void UpdateEditorModel(UpdateEditorModelContext context, ContentPart part) { + protected override void UpdateEditorShape(UpdateEditorModelContext context, ContentPart part) { context.Updater.TryUpdateModel(part.Record, _prefix, null, null); context.ViewModel.Zones.AddEditorPart(_location, part.Record, _templateName, _prefix); } diff --git a/src/Orchard/ContentManagement/IContentManager.cs b/src/Orchard/ContentManagement/IContentManager.cs index ba8c704d4..e4a3c964e 100644 --- a/src/Orchard/ContentManagement/IContentManager.cs +++ b/src/Orchard/ContentManagement/IContentManager.cs @@ -26,9 +26,9 @@ namespace Orchard.ContentManagement { ContentItemMetadata GetItemMetadata(IContent contentItem); - ContentItemViewModel BuildDisplayModel(TContent content, string displayType) where TContent : IContent; - ContentItemViewModel BuildEditorModel(TContent content) where TContent : IContent; - ContentItemViewModel UpdateEditorModel(TContent content, IUpdateModel updater) where TContent : IContent; + ContentItemViewModel BuildDisplayShape(TContent content, string displayType) where TContent : IContent; + ContentItemViewModel BuildEditorShape(TContent content) where TContent : IContent; + ContentItemViewModel UpdateEditorShape(TContent content, IUpdateModel updater) where TContent : IContent; } public class VersionOptions { diff --git a/src/Orchard/Data/Migration/Schema/AlterTableCommand.cs b/src/Orchard/Data/Migration/Schema/AlterTableCommand.cs index 8c5576e3c..0b8d370e9 100644 --- a/src/Orchard/Data/Migration/Schema/AlterTableCommand.cs +++ b/src/Orchard/Data/Migration/Schema/AlterTableCommand.cs @@ -18,6 +18,11 @@ namespace Orchard.Data.Migration.Schema { TableCommands.Add(command); } + public void AddColumn(string columnName, Action column = null) { + var dbType = SchemaUtils.ToDbType(typeof(T)); + AddColumn(columnName, dbType, column); + } + public void DropColumn(string columnName) { var command = new DropColumnCommand(Name, columnName); TableCommands.Add(command); diff --git a/src/Orchard/Data/Providers/SqlCeDataServicesProvider.cs b/src/Orchard/Data/Providers/SqlCeDataServicesProvider.cs index a28cdf1b5..d372f7c21 100644 --- a/src/Orchard/Data/Providers/SqlCeDataServicesProvider.cs +++ b/src/Orchard/Data/Providers/SqlCeDataServicesProvider.cs @@ -83,7 +83,7 @@ namespace Orchard.Data.Providers { protected override void InitializeParameter(IDbDataParameter dbParam, string name, SqlType sqlType) { base.InitializeParameter(dbParam, name, sqlType); - if (sqlType.Length <= 4000) { + if ( sqlType.Length <= 4000 ) { return; } diff --git a/src/Orchard/Messaging/Events/IMessageEventHandler.cs b/src/Orchard/Messaging/Events/IMessageEventHandler.cs new file mode 100644 index 000000000..73ab95b6e --- /dev/null +++ b/src/Orchard/Messaging/Events/IMessageEventHandler.cs @@ -0,0 +1,9 @@ +using Orchard.Events; +using Orchard.Messaging.Models; + +namespace Orchard.Messaging.Events { + public interface IMessageEventHandler : IEventHandler { + void Sending(MessageContext context); + void Sent(MessageContext context); + } +} diff --git a/src/Orchard/Messaging/Models/MessageContext.cs b/src/Orchard/Messaging/Models/MessageContext.cs new file mode 100644 index 000000000..63885700f --- /dev/null +++ b/src/Orchard/Messaging/Models/MessageContext.cs @@ -0,0 +1,18 @@ +using System.Collections.Generic; +using System.Net.Mail; +using Orchard.ContentManagement.Records; + +namespace Orchard.Messaging.Models { + public class MessageContext { + public MailMessage MailMessage { get; private set; } + public string Type { get; set; } + public string Service { get; set; } + public ContentItemRecord Recipient { get; set; } + public Dictionary Properties { get; private set; } + + public MessageContext() { + Properties = new Dictionary(); + MailMessage = new MailMessage(); + } + } +} diff --git a/src/Orchard/Messaging/Services/IMessageManager.cs b/src/Orchard/Messaging/Services/IMessageManager.cs new file mode 100644 index 000000000..efcbad622 --- /dev/null +++ b/src/Orchard/Messaging/Services/IMessageManager.cs @@ -0,0 +1,21 @@ +using System.Collections.Generic; +using Orchard.ContentManagement.Records; + +namespace Orchard.Messaging.Services { + public interface IMessageManager : IDependency { + /// + /// Sends a message to a channel + /// + void Send(ContentItemRecord recipient, string type, string service = null, Dictionary properties = null); + + /// + /// Wether at least one channel is active on the current site + /// + bool HasChannels(); + + /// + /// Provides a list of all the current available channel services + /// + IEnumerable GetAvailableChannelServices(); + } +} diff --git a/src/Orchard/Messaging/Services/IMessagingChannel.cs b/src/Orchard/Messaging/Services/IMessagingChannel.cs new file mode 100644 index 000000000..e5d33ff46 --- /dev/null +++ b/src/Orchard/Messaging/Services/IMessagingChannel.cs @@ -0,0 +1,17 @@ +using System.Collections.Generic; +using Orchard.ContentManagement; +using Orchard.Messaging.Models; + +namespace Orchard.Messaging.Services { + public interface IMessagingChannel : IDependency { + /// + /// Actually sends the message though this channel + /// + void SendMessage(MessageContext message); + + /// + /// Provides all the handled services, the user can choose from when receving messages + /// + IEnumerable GetAvailableServices(); + } +} diff --git a/src/Orchard/Orchard.Framework.csproj b/src/Orchard/Orchard.Framework.csproj index c8c2368ed..6cbb4df38 100644 --- a/src/Orchard/Orchard.Framework.csproj +++ b/src/Orchard/Orchard.Framework.csproj @@ -188,12 +188,6 @@ - - Code - - - Code - Code @@ -210,9 +204,6 @@ - - Code - @@ -408,6 +399,10 @@ + + + + @@ -781,7 +776,6 @@ - diff --git a/src/Orchard/Security/IMembershipService.cs b/src/Orchard/Security/IMembershipService.cs index 0821fcdb1..5e36c7e8d 100644 --- a/src/Orchard/Security/IMembershipService.cs +++ b/src/Orchard/Security/IMembershipService.cs @@ -7,5 +7,9 @@ IUser ValidateUser(string userNameOrEmail, string password); void SetPassword(IUser user, string password); + + IUser ValidateChallengeToken(string challengeToken); + void SendChallengeEmail(IUser user, string url); + string GetEncryptedChallengeToken(IUser user); } } diff --git a/src/Orchard/Security/Providers/OrchardMembershipProvider.cs b/src/Orchard/Security/Providers/OrchardMembershipProvider.cs deleted file mode 100644 index 5f09ddb45..000000000 --- a/src/Orchard/Security/Providers/OrchardMembershipProvider.cs +++ /dev/null @@ -1,127 +0,0 @@ -using System; -using System.Web.Security; -using Orchard.Environment; - -namespace Orchard.Security.Providers { - public class OrchardMembershipProvider : MembershipProvider { - - static IMembershipService GetService() { - throw new NotImplementedException("The OrchardMemberShipProvider is not supported anymore. Use the IMembershipService interface instead."); - } - - static MembershipSettings GetSettings() { - return GetService().GetSettings(); - } - - private MembershipUser BuildMembershipUser(IUser user) { - return new MembershipUser(Name, - user.UserName, - user.Id, - user.Email, - null, - null, - true, - false, - DateTime.UtcNow, - DateTime.UtcNow, - DateTime.UtcNow, - DateTime.UtcNow, - DateTime.UtcNow); - } - - public override MembershipUser CreateUser(string username, string password, string email, string passwordQuestion, string passwordAnswer, bool isApproved, object providerUserKey, out MembershipCreateStatus status) { - var user = GetService().CreateUser(new CreateUserParams(username, password, email, passwordQuestion, passwordAnswer, isApproved)); - - if (user == null) { - status = MembershipCreateStatus.ProviderError; - return null; - } - - status = MembershipCreateStatus.Success; - return BuildMembershipUser(user); - } - - - public override bool ChangePasswordQuestionAndAnswer(string username, string password, string newPasswordQuestion, string newPasswordAnswer) { - throw new NotImplementedException(); - } - - public override string GetPassword(string username, string answer) { - throw new NotImplementedException(); - } - - public override bool ChangePassword(string username, string oldPassword, string newPassword) { - var service = GetService(); - var user = service.ValidateUser(username, oldPassword); - if (user == null) - return false; - - service.SetPassword(user, newPassword); - return true; - } - - public override string ResetPassword(string username, string answer) { - throw new NotImplementedException(); - } - - public override void UpdateUser(MembershipUser user) { - throw new NotImplementedException(); - } - - public override bool ValidateUser(string username, string password) { - return (GetService().ValidateUser(username, password) != null); - } - - public override bool UnlockUser(string userName) { - throw new NotImplementedException(); - } - - public override MembershipUser GetUser(object providerUserKey, bool userIsOnline) { - throw new NotImplementedException(); - } - - public override MembershipUser GetUser(string username, bool userIsOnline) { - throw new NotImplementedException(); - } - - public override string GetUserNameByEmail(string email) { - throw new NotImplementedException(); - } - - public override bool DeleteUser(string username, bool deleteAllRelatedData) { - throw new NotImplementedException(); - } - - public override MembershipUserCollection GetAllUsers(int pageIndex, int pageSize, out int totalRecords) { - throw new NotImplementedException(); - } - - public override int GetNumberOfUsersOnline() { - throw new NotImplementedException(); - } - - public override MembershipUserCollection FindUsersByName(string usernameToMatch, int pageIndex, int pageSize, out int totalRecords) { - throw new NotImplementedException(); - } - - public override MembershipUserCollection FindUsersByEmail(string emailToMatch, int pageIndex, int pageSize, out int totalRecords) { - throw new NotImplementedException(); - } - - public override string ApplicationName { - get { throw new NotImplementedException(); } - set { throw new NotImplementedException(); } - } - - public override bool EnablePasswordRetrieval { get { return GetSettings().EnablePasswordRetrieval; } } - public override bool EnablePasswordReset { get { return GetSettings().EnablePasswordReset; } } - public override bool RequiresQuestionAndAnswer { get { return GetSettings().RequiresQuestionAndAnswer; } } - public override int MaxInvalidPasswordAttempts { get { return GetSettings().MaxInvalidPasswordAttempts; } } - public override int PasswordAttemptWindow { get { return GetSettings().PasswordAttemptWindow; } } - public override bool RequiresUniqueEmail { get { return GetSettings().RequiresUniqueEmail; } } - public override MembershipPasswordFormat PasswordFormat { get { return GetSettings().PasswordFormat; } } - public override int MinRequiredPasswordLength { get { return GetSettings().MinRequiredPasswordLength; } } - public override int MinRequiredNonAlphanumericCharacters { get { return GetSettings().MinRequiredNonAlphanumericCharacters; } } - public override string PasswordStrengthRegularExpression { get { return GetSettings().PasswordStrengthRegularExpression; } } - } -}