diff --git a/src/Orchard.Web/Core/Messaging/DataMigrations/MessagingDataMigration.cs b/src/Orchard.Web/Core/Messaging/DataMigrations/MessagingDataMigration.cs new file mode 100644 index 000000000..5ffb35497 --- /dev/null +++ b/src/Orchard.Web/Core/Messaging/DataMigrations/MessagingDataMigration.cs @@ -0,0 +1,14 @@ +using Orchard.Data.Migration; + +namespace Orchard.Core.Messaging.DataMigrations { + public class MessagingDataMigration : DataMigrationImpl { + + public int Create() { + SchemaBuilder.CreateTable("MessageSettingsPartRecord", table => table + .ContentPartRecord() + .Column("DefaultChannelService") + ); + return 1; + } + } +} \ No newline at end of file diff --git a/src/Orchard.Web/Core/Messaging/Drivers/MessageSettingsPartDriver.cs b/src/Orchard.Web/Core/Messaging/Drivers/MessageSettingsPartDriver.cs new file mode 100644 index 000000000..5411b1765 --- /dev/null +++ b/src/Orchard.Web/Core/Messaging/Drivers/MessageSettingsPartDriver.cs @@ -0,0 +1,48 @@ +using JetBrains.Annotations; +using Orchard.ContentManagement; +using Orchard.ContentManagement.Drivers; +using Orchard.Core.ContentsLocation.Models; +using Orchard.Core.Messaging.Models; +using Orchard.Core.Messaging.Services; +using Orchard.Core.Messaging.ViewModels; +using Orchard.Localization; +using Orchard.Messaging.Services; + +namespace Orchard.Core.Messaging.Drivers { + [UsedImplicitly] + public class ContentSubscriptionPartDriver : ContentPartDriver { + private readonly IMessageManager _messageQueueManager; + public IOrchardServices Services { get; set; } + + public ContentSubscriptionPartDriver(IOrchardServices services, IMessageManager messageQueueManager) { + _messageQueueManager = messageQueueManager; + Services = services; + T = NullLocalizer.Instance; + } + + public Localizer T { get; set; } + + protected override string Prefix { get { return "MessageSettings"; } } + + protected override DriverResult Editor(MessageSettingsPart part) { + + var model = new ContentSubscriptionPartViewModel { + ChannelServices = _messageQueueManager.GetAvailableChannelServices(), + MessageSettings = part + }; + + return ContentPartTemplate(model, "Parts/Messaging.MessageSettings"); + } + + protected override DriverResult Editor(MessageSettingsPart part, IUpdateModel updater) { + var model = new ContentSubscriptionPartViewModel { + MessageSettings = part + }; + + if (updater.TryUpdateModel(model, Prefix, null, null)) { + } + + return ContentPartTemplate(model, "Parts/Messaging.MessageSettings"); + } + } +} \ No newline at end of file diff --git a/src/Orchard.Web/Core/Messaging/Handlers/MessageSettingsPartHandler.cs b/src/Orchard.Web/Core/Messaging/Handlers/MessageSettingsPartHandler.cs new file mode 100644 index 000000000..86350726c --- /dev/null +++ b/src/Orchard.Web/Core/Messaging/Handlers/MessageSettingsPartHandler.cs @@ -0,0 +1,14 @@ +using JetBrains.Annotations; +using Orchard.Core.Messaging.Models; +using Orchard.Data; +using Orchard.ContentManagement.Handlers; + +namespace Orchard.Core.Messaging.Handlers { + [UsedImplicitly] + public class SmtpSettingsPartHandler : ContentHandler { + public SmtpSettingsPartHandler(IRepository repository) { + Filters.Add(new ActivatingFilter("Site")); + Filters.Add(StorageFilter.For(repository)); + } + } +} \ No newline at end of file diff --git a/src/Orchard.Web/Core/Messaging/Models/MessageSettingsPart.cs b/src/Orchard.Web/Core/Messaging/Models/MessageSettingsPart.cs new file mode 100644 index 000000000..c624bb20d --- /dev/null +++ b/src/Orchard.Web/Core/Messaging/Models/MessageSettingsPart.cs @@ -0,0 +1,11 @@ +using Orchard.ContentManagement; + +namespace Orchard.Core.Messaging.Models { + public class MessageSettingsPart : ContentPart { + public string DefaultChannelService { + get { return Record.DefaultChannelService; } + set { Record.DefaultChannelService = value; } + } + + } +} diff --git a/src/Orchard.Web/Core/Messaging/Models/MessageSettingsPartRecord.cs b/src/Orchard.Web/Core/Messaging/Models/MessageSettingsPartRecord.cs new file mode 100644 index 000000000..7d23a9d03 --- /dev/null +++ b/src/Orchard.Web/Core/Messaging/Models/MessageSettingsPartRecord.cs @@ -0,0 +1,11 @@ +using Orchard.ContentManagement.Records; + +namespace Orchard.Core.Messaging.Models { + public class MessageSettingsPartRecord : ContentPartRecord { + /// + /// Default service used for messages + /// + public virtual string DefaultChannelService { get; set; } + + } +} \ No newline at end of file diff --git a/src/Orchard.Web/Core/Messaging/Module.txt b/src/Orchard.Web/Core/Messaging/Module.txt new file mode 100644 index 000000000..854b2823e --- /dev/null +++ b/src/Orchard.Web/Core/Messaging/Module.txt @@ -0,0 +1,12 @@ +Name: Messaging +antiforgery: enabled +author: The Orchard Team +website: http://orchardproject.net +version: 0.1.0 +orchardversion: 0.6.0 +description: The Messaging module adds messaging functionalities. +features: + Messaging: + Description: Messaging services. + Category: Messaging + Dependencies: Settings diff --git a/src/Orchard.Web/Core/Messaging/Services/DefaultMessageManager.cs b/src/Orchard.Web/Core/Messaging/Services/DefaultMessageManager.cs new file mode 100644 index 000000000..996f99e57 --- /dev/null +++ b/src/Orchard.Web/Core/Messaging/Services/DefaultMessageManager.cs @@ -0,0 +1,75 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using JetBrains.Annotations; +using Orchard.ContentManagement; +using Orchard.Core.Messaging.Models; +using Orchard.Data; +using Orchard.Logging; +using Orchard.Messaging.Events; +using Orchard.Messaging.Models; +using Orchard.Messaging.Services; +using Orchard.Settings; + +namespace Orchard.Core.Messaging.Services { + public class DefaultMessageManager : IMessageManager { + private readonly IMessageEventHandler _messageEventHandler; + private readonly IEnumerable _channels; + private readonly IRepository _messageRepository; + + protected virtual ISite CurrentSite { get; [UsedImplicitly] private set; } + public ILogger Logger { get; set; } + + public DefaultMessageManager( + IMessageEventHandler messageEventHandler, + IEnumerable channels, + IRepository messageRepository) { + _messageEventHandler = messageEventHandler; + _channels = channels; + _messageRepository = messageRepository; + } + + public void Send(Message message) { + if ( !HasChannels() ) + return; + + var messageSettings = CurrentSite.As().Record; + + if ( messageSettings == null || String.IsNullOrWhiteSpace(messageSettings.DefaultChannelService) ) { + return; + } + + Logger.Information("Sending message {0}", message.Type); + try { + + // if the service is not explicit, use the default one, as per settings configuration + if ( String.IsNullOrWhiteSpace(message.Service) ) { + message.Service = messageSettings.DefaultChannelService; + } + + var context = new MessageContext(message); + + _messageEventHandler.Sending(context); + + foreach ( var channel in _channels ) { + channel.SendMessage(context); + } + + _messageEventHandler.Sent(context); + + Logger.Information("Message {0} sent", message.Type); + } + catch ( Exception e ) { + Logger.Error(e, "An error occured while sending the message {0}", message.Type); + } + } + + public bool HasChannels() { + return _channels.Any(); + } + + public IEnumerable GetAvailableChannelServices() { + return _channels.SelectMany(c => c.GetAvailableServices()); + } + } +} diff --git a/src/Orchard.Web/Core/Messaging/ViewModels/MessageSettingsPartViewModel.cs b/src/Orchard.Web/Core/Messaging/ViewModels/MessageSettingsPartViewModel.cs new file mode 100644 index 000000000..da90402e4 --- /dev/null +++ b/src/Orchard.Web/Core/Messaging/ViewModels/MessageSettingsPartViewModel.cs @@ -0,0 +1,10 @@ +using Orchard.Core.Messaging.Models; +using Orchard.Mvc.ViewModels; +using System.Collections.Generic; + +namespace Orchard.Core.Messaging.ViewModels { + public class ContentSubscriptionPartViewModel : BaseViewModel { + public MessageSettingsPart MessageSettings { get; set; } + public IEnumerable ChannelServices { get; set; } + } +} diff --git a/src/Orchard.Web/Core/Messaging/Views/EditorTemplates/Parts/Messaging.MessageSettings.ascx b/src/Orchard.Web/Core/Messaging/Views/EditorTemplates/Parts/Messaging.MessageSettings.ascx new file mode 100644 index 000000000..2d4734df4 --- /dev/null +++ b/src/Orchard.Web/Core/Messaging/Views/EditorTemplates/Parts/Messaging.MessageSettings.ascx @@ -0,0 +1,20 @@ +<%@ Control Language="C#" Inherits="Orchard.Mvc.ViewUserControl" %> +<%@ Import Namespace="Orchard.Core.Messaging.Models"%> +<%@ Import Namespace="Orchard.Core.Messaging.ViewModels"%> +
+ <%: T("Messaging")%> +
+ + <% if ( Model.ChannelServices.Any() ) { %> + +
+
\ No newline at end of file diff --git a/src/Orchard.Web/Core/Messaging/Views/Web.config b/src/Orchard.Web/Core/Messaging/Views/Web.config new file mode 100644 index 000000000..e065d8735 --- /dev/null +++ b/src/Orchard.Web/Core/Messaging/Views/Web.config @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Orchard.Web/Core/Orchard.Core.csproj b/src/Orchard.Web/Core/Orchard.Core.csproj index ad30d94b0..9929f5132 100644 --- a/src/Orchard.Web/Core/Orchard.Core.csproj +++ b/src/Orchard.Web/Core/Orchard.Core.csproj @@ -90,6 +90,13 @@ + + + + + + + @@ -247,6 +254,8 @@ + + @@ -366,6 +375,7 @@ + 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/Handlers/SmtpSettingsPartHandler.cs b/src/Orchard.Web/Modules/Orchard.Email/Handlers/SmtpSettingsPartHandler.cs new file mode 100644 index 000000000..b24131f06 --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Email/Handlers/SmtpSettingsPartHandler.cs @@ -0,0 +1,15 @@ +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)); + Filters.Add(new TemplateFilterForRecord("SmtpSettings", "Parts/Smtp.SiteSettings")); + } + } +} \ 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..057159041 --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Email/Models/SmtpSettingsPart.cs @@ -0,0 +1,47 @@ +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 Record.Password; } + set { Record.Password = value; } + } + } +} \ 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..0c1ba7057 --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Email/Orchard.Email.csproj @@ -0,0 +1,141 @@ + + + + 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..d4b87486c --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Email/Services/EmailMessageEventHandler.cs @@ -0,0 +1,30 @@ +using Orchard.Messaging.Events; +using Orchard.Core.Messaging.Models; +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.Message.Recipient.Id); + if ( contentItem == null ) + return; + + var recipient = contentItem.As(); + if ( recipient == null ) + return; + + context.Properties.Add(EmailMessagingChannel.EmailAddress, 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..fe8bec169 --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Email/Services/EmailMessagingChannel.cs @@ -0,0 +1,93 @@ +using System; +using System.Collections.Generic; +using System.Net; +using System.Net.Mail; +using System.Web; +using System.Web.Hosting; +using JetBrains.Annotations; +using Orchard.ContentManagement; +using Orchard.Localization; +using Orchard.Logging; +using Orchard.Core.Messaging.Models; +using Orchard.Core.Messaging.Services; +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 const string EmailAddress = "EmailAddress"; + + 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.Message.Service.ToLower() != EmailService ) + 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); + } + + var emailAddress = context.Properties[EmailAddress]; + + if(String.IsNullOrWhiteSpace(emailAddress)) { + 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; + + var message = new MailMessage { + From = new MailAddress(smtpSettings.Address), + Subject = context.Message.Subject ?? "", + Body = context.Message.Body ?? "", + IsBodyHtml = context.Message.Body != null && context.Message.Body.Contains("<") && context.Message.Body.Contains(">") + }; + + message.To.Add(emailAddress); + + try { + smtpClient.Send(message); + Logger.Debug("Message sent to {0}: {1}", emailAddress, context.Message.Subject); + } + catch(Exception e) { + Logger.Error(e, "An unexpected error while sending a message to {0}: {1}", emailAddress, context.Message.Subject); + } + } + + public bool IsRecipientValidated(ContentItem contentItem) { + return false; + } + + public void ValidateRecipient(ContentItem contentItem) { + var context = new MessageContext(new Message { Recipient = contentItem.Record, Body = "Please validate your account", Service = "email", Subject = "Validate your account" } ); + SendMessage(context); + } + + 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..d9cdefe8e --- /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/Services/SetupService.cs b/src/Orchard.Web/Modules/Orchard.Setup/Services/SetupService.cs index b0d160831..f639cbc0e 100644 --- a/src/Orchard.Web/Modules/Orchard.Setup/Services/SetupService.cs +++ b/src/Orchard.Web/Modules/Orchard.Setup/Services/SetupService.cs @@ -80,6 +80,7 @@ namespace Orchard.Setup.Services { "Routable", "Settings", "XmlRpc", + "Messaging", "Orchard.Users", "Orchard.Roles", "TinyMce", diff --git a/src/Orchard.sln b/src/Orchard.sln index 23e4179eb..251194d5f 100644 --- a/src/Orchard.sln +++ b/src/Orchard.sln @@ -77,6 +77,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Orchard.Tests", "Tools\Orch EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Orchard.ArchiveLater", "Orchard.Web\Modules\Orchard.ArchiveLater\Orchard.ArchiveLater.csproj", "{1C981BB3-26F7-494C-9005-CC27A5144233}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Orchard.Email", "Orchard.Web\Modules\Orchard.Email\Orchard.Email.csproj", "{05660F47-D649-48BD-9DED-DF4E01E7CFF9}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -219,6 +221,10 @@ Global {1C981BB3-26F7-494C-9005-CC27A5144233}.Debug|Any CPU.Build.0 = Debug|Any CPU {1C981BB3-26F7-494C-9005-CC27A5144233}.Release|Any CPU.ActiveCfg = Release|Any CPU {1C981BB3-26F7-494C-9005-CC27A5144233}.Release|Any CPU.Build.0 = Release|Any CPU + {05660F47-D649-48BD-9DED-DF4E01E7CFF9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {05660F47-D649-48BD-9DED-DF4E01E7CFF9}.Debug|Any CPU.Build.0 = Debug|Any CPU + {05660F47-D649-48BD-9DED-DF4E01E7CFF9}.Release|Any CPU.ActiveCfg = Release|Any CPU + {05660F47-D649-48BD-9DED-DF4E01E7CFF9}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -243,6 +249,7 @@ Global {D5D447D7-EF8E-43A6-B9A4-3B025DD9F45D} = {E9C9F120-07BA-4DFB-B9C3-3AFB9D44C9D5} {DFD137A2-DDB5-4D22-BE0D-FA9AD4C8B059} = {E9C9F120-07BA-4DFB-B9C3-3AFB9D44C9D5} {1C981BB3-26F7-494C-9005-CC27A5144233} = {E9C9F120-07BA-4DFB-B9C3-3AFB9D44C9D5} + {05660F47-D649-48BD-9DED-DF4E01E7CFF9} = {E9C9F120-07BA-4DFB-B9C3-3AFB9D44C9D5} {ABC826D4-2FA1-4F2F-87DE-E6095F653810} = {74E681ED-FECC-4034-B9BD-01B0BB1BDECA} {F112851D-B023-4746-B6B1-8D2E5AD8F7AA} = {74E681ED-FECC-4034-B9BD-01B0BB1BDECA} {6CB3EB30-F725-45C0-9742-42599BA8E8D2} = {74E681ED-FECC-4034-B9BD-01B0BB1BDECA} 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/Message.cs b/src/Orchard/Messaging/Models/Message.cs new file mode 100644 index 000000000..32b37c8d5 --- /dev/null +++ b/src/Orchard/Messaging/Models/Message.cs @@ -0,0 +1,11 @@ +using Orchard.ContentManagement.Records; + +namespace Orchard.Messaging.Models { + public class Message { + public string Service { get; set; } + public string Subject { get; set; } + public string Body { get; set; } + public string Type { get; set; } + public ContentItemRecord Recipient { get; set; } + } +} diff --git a/src/Orchard/Messaging/Models/MessageContext.cs b/src/Orchard/Messaging/Models/MessageContext.cs new file mode 100644 index 000000000..e6582f2ba --- /dev/null +++ b/src/Orchard/Messaging/Models/MessageContext.cs @@ -0,0 +1,16 @@ +using System.Collections.Generic; +using System.Net.Mail; + +namespace Orchard.Messaging.Models { + public class MessageContext { + public Dictionary Properties { get; private set; } + public Message Message { get; private set; } + public MailMessage MailMessage { get; private set; } + + public MessageContext(Message message) { + Properties = new Dictionary(); + Message = message; + MailMessage = new MailMessage {Body = message.Body, Subject = message.Subject}; + } + } +} diff --git a/src/Orchard/Messaging/Services/IMessageManager.cs b/src/Orchard/Messaging/Services/IMessageManager.cs new file mode 100644 index 000000000..a71395170 --- /dev/null +++ b/src/Orchard/Messaging/Services/IMessageManager.cs @@ -0,0 +1,21 @@ +using System.Collections.Generic; +using Orchard.Messaging.Models; + +namespace Orchard.Messaging.Services { + public interface IMessageManager : IDependency { + /// + /// Sends a message without using the queue + /// + void Send(Message message); + + /// + /// 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..59db18e7d --- /dev/null +++ b/src/Orchard/Messaging/Services/IMessagingChannel.cs @@ -0,0 +1,22 @@ +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); + + /// + /// Sends a message to the recipient to validate his account + /// + void ValidateRecipient(ContentItem recipient); + + /// + /// 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 a5467f5c7..19a6caed8 100644 --- a/src/Orchard/Orchard.Framework.csproj +++ b/src/Orchard/Orchard.Framework.csproj @@ -371,6 +371,11 @@ + + + + +