diff --git a/src/Orchard.Web/Modules/Orchard.Email/Activities/EmailActivity.cs b/src/Orchard.Web/Modules/Orchard.Email/Activities/EmailActivity.cs index 3b91dc9cc..a270cbd60 100644 --- a/src/Orchard.Web/Modules/Orchard.Email/Activities/EmailActivity.cs +++ b/src/Orchard.Web/Modules/Orchard.Email/Activities/EmailActivity.cs @@ -1,19 +1,17 @@ using System; using System.Collections.Generic; -using System.Linq; using Orchard.Email.Models; using Orchard.Email.Services; using Orchard.Localization; -using Orchard.Messaging.Models; using Orchard.Messaging.Services; using Orchard.Workflows.Models; using Orchard.Workflows.Services; namespace Orchard.Email.Activities { public class EmailActivity : Task { - private readonly IMessageQueueManager _messageQueueManager; + private readonly IMessageQueueService _messageQueueManager; - public EmailActivity(IMessageQueueManager messageQueueManager) { + public EmailActivity(IMessageQueueService messageQueueManager) { _messageQueueManager = messageQueueManager; T = NullLocalizer.Instance; } @@ -43,21 +41,24 @@ namespace Orchard.Email.Activities { } public override IEnumerable Execute(WorkflowContext workflowContext, ActivityContext activityContext) { - var recipientAddresses = Split(activityContext.GetState("RecipientAddress")).ToList(); + var priority = activityContext.GetState("Priority"); + var body = activityContext.GetState("Body"); var subject = activityContext.GetState("Subject"); - var queueId = activityContext.GetState("Queue") ?? _messageQueueManager.GetDefaultQueue().Id; - var priorityId = activityContext.GetState("Priority"); - var recipients = recipientAddresses.Select(x => new MessageRecipient(x)); - var priority = _messageQueueManager.GetPriority(priorityId); - var payload = new EmailMessage(subject, body); - _messageQueueManager.Send(recipients, EmailMessageChannel.ChannelName, payload, priority, queueId); + var recipients = Split(activityContext.GetState("RecipientAddress")); + var payload = new EmailMessage { + Subject = subject, + Body = body, + Recipients = recipients + }; + + _messageQueueManager.Enqueue(SmtpMessageChannel.MessageType, payload, priority); yield return T("Queued"); } - private static IEnumerable Split(string value) { - return !String.IsNullOrWhiteSpace(value) ? value.Split(new[] { ',', ';' }, StringSplitOptions.RemoveEmptyEntries) : Enumerable.Empty(); + private static string[] Split(string value) { + return !String.IsNullOrWhiteSpace(value) ? value.Split(new[] { ',', ';' }, StringSplitOptions.RemoveEmptyEntries) : new string[0]; } } } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Email/Activities/MailActivity.cs b/src/Orchard.Web/Modules/Orchard.Email/Activities/MailActivity.cs deleted file mode 100644 index 936d6d242..000000000 --- a/src/Orchard.Web/Modules/Orchard.Email/Activities/MailActivity.cs +++ /dev/null @@ -1,140 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using Orchard.Core.Common.Models; -using Orchard.Messaging.Events; -using Orchard.Messaging.Models; -using Orchard.Messaging.Services; -using Orchard.ContentManagement; -using Orchard.Localization; -using Orchard.Security; -using Orchard.Workflows.Models; -using Orchard.Workflows.Services; - -namespace Orchard.Email.Activities { - [Obsolete("Use the new EmailActivity instead.")] - public class MailActivity : Task { - private readonly IMessageManager _messageManager; - private readonly IOrchardServices _orchardServices; - private readonly IMembershipService _membershipService; - public const string MessageType = "ActionEmail_Deprecated"; - - public MailActivity( - IMessageManager messageManager, - IOrchardServices orchardServices, - IMembershipService membershipService) { - _messageManager = messageManager; - _orchardServices = orchardServices; - _membershipService = membershipService; - T = NullLocalizer.Instance; - } - - public Localizer T { get; set; } - - public override IEnumerable GetPossibleOutcomes(WorkflowContext workflowContext, ActivityContext activityContext) { - return new[] { T("Sent") }; - } - - public override string Form { - get { - return "ActivityActionEmail"; - } - } - - public override LocalizedString Category { - get { return T("Messaging"); } - } - - public override string Name { - get { return "SendEmailDeprecated"; } - } - - - public override LocalizedString Description { - get { return T("Sends an e-mail to a specific user (deprecated)."); } - } - - public override IEnumerable Execute(WorkflowContext workflowContext, ActivityContext activityContext) { - string recipient = activityContext.GetState("Recipient"); - - var properties = new Dictionary { - {"Body", activityContext.GetState("Body")}, - {"Subject", activityContext.GetState("Subject")}, - {"RecipientOther",activityContext.GetState("RecipientOther")} - }; - - if (recipient == "owner") { - var content = workflowContext.Content; - if (content.Has()) { - var owner = content.As().Owner; - if (owner != null && owner.ContentItem != null && owner.ContentItem.Record != null) { - _messageManager.Send(owner.ContentItem.Record, MessageType, "email", properties); - } - _messageManager.Send( - SplitEmail(owner.As().Email), MessageType, "email", properties); - } - } - else if (recipient == "author") { - var user = _orchardServices.WorkContext.CurrentUser; - - // can be null if user is anonymous - if (user != null && !String.IsNullOrWhiteSpace(user.Email)) { - _messageManager.Send(user.ContentItem.Record, MessageType, "email", properties); - } - } - else if (recipient == "admin") { - var username = _orchardServices.WorkContext.CurrentSite.SuperUser; - var user = _membershipService.GetUser(username); - - // can be null if user is no super user is defined - if (user != null && !String.IsNullOrWhiteSpace(user.Email)) { - _messageManager.Send(user.ContentItem.Record, MessageType, "email", properties); - } - } - else if (recipient == "other") { - _messageManager.Send(SplitEmail(activityContext.GetState("RecipientOther")), MessageType, "email", properties); - } - - yield return T("Sent"); - } - - private static IEnumerable SplitEmail(string commaSeparated) { - return commaSeparated.Split(new[] { ',', ';' }); - } - } - - [Obsolete] - public class MailActionsHandler : IMessageEventHandler { - public MailActionsHandler() { - T = NullLocalizer.Instance; - } - - public Localizer T { get; set; } - - public void Sending(MessageContext context) { - if (context.MessagePrepared) - return; - - if ((context.Recipients == null || !context.Recipients.Any()) && - (context.Addresses == null || !context.Addresses.Any())) { - return; - } - - switch (context.Type) { - case MailActivity.MessageType: - context.MailMessage.Subject = context.Properties["Subject"]; - context.MailMessage.Body = context.Properties["Body"]; - FormatEmailBody(context); - context.MessagePrepared = true; - break; - } - } - - private static void FormatEmailBody(MessageContext context) { - context.MailMessage.Body = "

" + context.MailMessage.Body + "

"; - } - - public void Sent(MessageContext context) { - } - } -} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Email/Forms/EmailForm.cs b/src/Orchard.Web/Modules/Orchard.Email/Forms/EmailForm.cs index 3fd3e612b..6e88303db 100644 --- a/src/Orchard.Web/Modules/Orchard.Email/Forms/EmailForm.cs +++ b/src/Orchard.Web/Modules/Orchard.Email/Forms/EmailForm.cs @@ -1,22 +1,15 @@ using System; -using System.Collections.Generic; -using System.Globalization; -using System.Linq; using System.Web.Mvc; using Orchard.DisplayManagement; using Orchard.Forms.Services; using Orchard.Localization; -using Orchard.Messaging.Models; -using Orchard.Messaging.Services; namespace Orchard.Email.Forms { public class EmailForm : Component, IFormProvider { - private readonly IMessageQueueManager _messageQueueManager; protected dynamic New { get; set; } - public EmailForm(IShapeFactory shapeFactory, IMessageQueueManager messageQueueManager) { + public EmailForm(IShapeFactory shapeFactory) { New = shapeFactory; - _messageQueueManager = messageQueueManager; } public void Describe(DescribeContext context) { @@ -46,19 +39,12 @@ namespace Orchard.Email.Forms { Id: "priority", Name: "Priority", Title: T("Priority"), - Description: ("The priority of this message."), - Items: GetPriorities()))); + Description: ("The priority of this message.") + ))); - var queues = GetQueues(); - - if (queues.Count() > 1) { - form._Queue = New.SelectList( - Id: "queue", - Name: "Queue", - Title: T("Queue"), - Description: ("The queue to add this message to."), - Items: queues); - } + form._Type._Priority.Add(new SelectListItem { Value = "-50", Text = T("Low").Text }); + form._Type._Priority.Add(new SelectListItem { Value = "0", Text = T("Normal").Text }); + form._Type._Priority.Add(new SelectListItem { Value = "50", Text = T("Hight").Text }); return form; }; @@ -66,19 +52,6 @@ namespace Orchard.Email.Forms { context.Form("EmailActivity", formFactory); } - private IEnumerable GetPriorities() { - var priorities = _messageQueueManager.GetPriorities().ToList(); - if (!priorities.Any()) - priorities = _messageQueueManager.CreateDefaultPriorities().ToList(); - return priorities.Select(x => new SelectListItem { Text = x.DisplayText, Value = x.Id.ToString(CultureInfo.InvariantCulture) }).ToList(); - } - - private IEnumerable GetQueues() { - var queues = _messageQueueManager.GetQueues().ToList(); - if (!queues.Any()) - queues = new List {_messageQueueManager.CreateDefaultQueue()}; - return queues.Select(x => new SelectListItem {Text = x.Name, Value = x.Id.ToString(CultureInfo.InvariantCulture)}).ToList(); - } } public class EmailFormValidator : IFormEventHandler { diff --git a/src/Orchard.Web/Modules/Orchard.Email/Forms/MailForms.cs b/src/Orchard.Web/Modules/Orchard.Email/Forms/MailForms.cs index 90a3db805..724cc9267 100644 --- a/src/Orchard.Web/Modules/Orchard.Email/Forms/MailForms.cs +++ b/src/Orchard.Web/Modules/Orchard.Email/Forms/MailForms.cs @@ -85,22 +85,22 @@ namespace Orchard.Email.Forms { if (context.FormName != "ActivityActionEmail") return; var recipientFormValue = context.ValueProvider.GetValue("Recipient"); - var recipient = recipientFormValue != null ? recipientFormValue.AttemptedValue : String.Empty; - - if (recipient == String.Empty) { - context.ModelState.AddModelError("Recipient", T("You must select at least one recipient").Text); - } - - if (context.ValueProvider.GetValue("Subject").AttemptedValue == String.Empty) { - context.ModelState.AddModelError("Subject", T("You must provide a Subject").Text); - } - - if (context.ValueProvider.GetValue("Body").AttemptedValue == String.Empty) { - context.ModelState.AddModelError("Body", T("You must provide a Body").Text); - } - - if (context.ValueProvider.GetValue("RecipientOther").AttemptedValue == String.Empty && recipient == "other") { - context.ModelState.AddModelError("RecipientOther", T("You must provide an e-mail address").Text); + var recipient = recipientFormValue != null ? recipientFormValue.AttemptedValue : String.Empty; + + if (recipient == String.Empty) { + context.ModelState.AddModelError("Recipient", T("You must select at least one recipient").Text); + } + + if (context.ValueProvider.GetValue("Subject").AttemptedValue == String.Empty) { + context.ModelState.AddModelError("Subject", T("You must provide a Subject").Text); + } + + if (context.ValueProvider.GetValue("Body").AttemptedValue == String.Empty) { + context.ModelState.AddModelError("Body", T("You must provide a Body").Text); + } + + if (context.ValueProvider.GetValue("RecipientOther").AttemptedValue == String.Empty && recipient == "other") { + context.ModelState.AddModelError("RecipientOther", T("You must provide an e-mail address").Text); } } diff --git a/src/Orchard.Web/Modules/Orchard.Email/Models/EmailMessage.cs b/src/Orchard.Web/Modules/Orchard.Email/Models/EmailMessage.cs index 9126f6387..7fc8a95f0 100644 --- a/src/Orchard.Web/Modules/Orchard.Email/Models/EmailMessage.cs +++ b/src/Orchard.Web/Modules/Orchard.Email/Models/EmailMessage.cs @@ -1,15 +1,7 @@ namespace Orchard.Email.Models { public class EmailMessage { - public EmailMessage() { - - } - - public EmailMessage(string subject, string body) { - Subject = subject; - Body = body; - } - public string Subject { get; set; } public string Body { get; set; } + public string[] Recipients { get; set; } } } \ 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 index 5518cf489..ac169294e 100644 --- a/src/Orchard.Web/Modules/Orchard.Email/Module.txt +++ b/src/Orchard.Web/Modules/Orchard.Email/Module.txt @@ -10,4 +10,4 @@ Features: Name: Email Messaging FeatureDescription: Email Messaging services. Category: Messaging - Dependencies: Orchard.Messaging.Queuing, Orchard.Workflows + Dependencies: Orchard.Messaging, Orchard.Workflows diff --git a/src/Orchard.Web/Modules/Orchard.Email/Orchard.Email.csproj b/src/Orchard.Web/Modules/Orchard.Email/Orchard.Email.csproj index c9eec8657..46238621a 100644 --- a/src/Orchard.Web/Modules/Orchard.Email/Orchard.Email.csproj +++ b/src/Orchard.Web/Modules/Orchard.Email/Orchard.Email.csproj @@ -49,6 +49,10 @@ + + False + ..\..\..\..\lib\newtonsoft.json\Newtonsoft.Json.dll + @@ -63,7 +67,6 @@ - @@ -75,7 +78,8 @@ - + + diff --git a/src/Orchard.Web/Modules/Orchard.Email/Rules/MailActions.cs b/src/Orchard.Web/Modules/Orchard.Email/Rules/MailActions.cs index 0a0e8c830..5022e7b35 100644 --- a/src/Orchard.Web/Modules/Orchard.Email/Rules/MailActions.cs +++ b/src/Orchard.Web/Modules/Orchard.Email/Rules/MailActions.cs @@ -16,6 +16,7 @@ namespace Orchard.Email.Rules { void Describe(dynamic describe); } + [Obsolete] public class MailActions : IActionProvider { private readonly IMessageManager _messageManager; private readonly IOrchardServices _orchardServices; @@ -85,6 +86,7 @@ namespace Orchard.Email.Rules { } } + [Obsolete] public class MailActionsHandler : IMessageEventHandler { public MailActionsHandler() { T = NullLocalizer.Instance; diff --git a/src/Orchard.Web/Modules/Orchard.Email/Services/DefaultEmailMessageChannelSelector.cs b/src/Orchard.Web/Modules/Orchard.Email/Services/DefaultEmailMessageChannelSelector.cs new file mode 100644 index 000000000..dcf3aa57d --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Email/Services/DefaultEmailMessageChannelSelector.cs @@ -0,0 +1,25 @@ +using Orchard.ContentManagement; +using Orchard.Email.Models; +using Orchard.Messaging.Services; + +namespace Orchard.Email.Services { + public class DefaultEmailMessageChannelSelector : Component, IMessageChannelSelector { + private readonly IOrchardServices _services; + public const string ChannelName = "Email"; + + public DefaultEmailMessageChannelSelector(IOrchardServices services) { + _services = services; + } + + public MessageChannelSelectorResult GetChannel(string messageType, object payload) { + if (messageType == "Email") { + return new MessageChannelSelectorResult { + Priority = 50, + MessageChannel = new SmtpMessageChannel(_services.WorkContext.CurrentSite.As()) + }; + } + + return null; + } + } +} diff --git a/src/Orchard.Web/Modules/Orchard.Email/Services/EmailMessageChannel.cs b/src/Orchard.Web/Modules/Orchard.Email/Services/EmailMessageChannel.cs deleted file mode 100644 index 6578e3cb4..000000000 --- a/src/Orchard.Web/Modules/Orchard.Email/Services/EmailMessageChannel.cs +++ /dev/null @@ -1,77 +0,0 @@ -using System; -using System.Net; -using System.Net.Mail; -using Orchard.ContentManagement; -using Orchard.Logging; -using Orchard.Email.Models; -using Orchard.Messaging.Services; -using Orchard.Messaging.Models; - -namespace Orchard.Email.Services { - public interface IEmailMessageChannel : IMessageChannel { } - - public class EmailMessageChannel : MessageChannelBase, IEmailMessageChannel { - private readonly IOrchardServices _services; - private readonly Lazy _smtpClientField; - public const string ChannelName = "Email"; - - public EmailMessageChannel(IOrchardServices services) { - _services = services; - _smtpClientField = new Lazy(CreateSmtpClient); - Logger = NullLogger.Instance; - } - - public override string Name { - get { return ChannelName; } - } - - private SmtpClient SmtpClient { - get { return _smtpClientField.Value; } - } - - protected override void Dispose(bool disposing) { - if (!disposing) return; - if (!_smtpClientField.IsValueCreated) return; - - _smtpClientField.Value.Dispose(); - } - - public override void Send(QueuedMessage message) { - var smtpSettings = _services.WorkContext.CurrentSite.As(); - if (smtpSettings == null || !smtpSettings.IsValid()) return; - - var emailPayload = message.GetPayload(); - var mailMessage = new MailMessage { - From = new MailAddress(smtpSettings.Address), - Subject = emailPayload.Subject, - Body = emailPayload.Body, - IsBodyHtml = emailPayload.Body != null && emailPayload.Body.Contains("<") && emailPayload.Body.Contains(">") - }; - - foreach (var recipient in message.Recipients) { - mailMessage.To.Add(new MailAddress(recipient.AddressOrAlias)); - } - - SmtpClient.Send(mailMessage); - } - - private SmtpClient CreateSmtpClient() { - var smtpSettings = _services.WorkContext.CurrentSite.As(); - var smtpClient = new SmtpClient { - UseDefaultCredentials = !smtpSettings.RequireCredentials - }; - - if (!smtpClient.UseDefaultCredentials && !String.IsNullOrWhiteSpace(smtpSettings.UserName)) { - smtpClient.Credentials = new NetworkCredential(smtpSettings.UserName, smtpSettings.Password); - } - - if (smtpSettings.Host != null) - smtpClient.Host = smtpSettings.Host; - - smtpClient.Port = smtpSettings.Port; - smtpClient.EnableSsl = smtpSettings.EnableSsl; - smtpClient.DeliveryMethod = SmtpDeliveryMethod.Network; - return smtpClient; - } - } -} diff --git a/src/Orchard.Web/Modules/Orchard.Email/Services/EmailMessageEventHandler.cs b/src/Orchard.Web/Modules/Orchard.Email/Services/EmailMessageEventHandler.cs index 5ead419be..bc9fa38fc 100644 --- a/src/Orchard.Web/Modules/Orchard.Email/Services/EmailMessageEventHandler.cs +++ b/src/Orchard.Web/Modules/Orchard.Email/Services/EmailMessageEventHandler.cs @@ -6,6 +6,7 @@ using Orchard.Messaging.Models; using Orchard.Security; namespace Orchard.Email.Services { + [Obsolete] public class EmailMessageEventHandler : IMessageEventHandler { private readonly IContentManager _contentManager; diff --git a/src/Orchard.Web/Modules/Orchard.Email/Services/EmailMessagingChannel.cs b/src/Orchard.Web/Modules/Orchard.Email/Services/EmailMessagingChannel.cs index aed9093bc..5b1a31b9b 100644 --- a/src/Orchard.Web/Modules/Orchard.Email/Services/EmailMessagingChannel.cs +++ b/src/Orchard.Web/Modules/Orchard.Email/Services/EmailMessagingChannel.cs @@ -10,7 +10,7 @@ using Orchard.Messaging.Services; using Orchard.Messaging.Models; namespace Orchard.Email.Services { - [Obsolete("Use EmailMessageChannel instead.")] + [Obsolete] public class EmailMessagingChannel : IMessagingChannel { private readonly IOrchardServices _orchardServices; diff --git a/src/Orchard.Web/Modules/Orchard.Email/Services/SmtpMessageChannel.cs b/src/Orchard.Web/Modules/Orchard.Email/Services/SmtpMessageChannel.cs new file mode 100644 index 000000000..b5f715943 --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Email/Services/SmtpMessageChannel.cs @@ -0,0 +1,81 @@ +using System; +using System.Net; +using System.Net.Mail; +using Newtonsoft.Json; +using Orchard.Logging; +using Orchard.Email.Models; +using Orchard.Messaging.Services; + +namespace Orchard.Email.Services { + public class SmtpMessageChannel : Component, IMessageChannel, IDisposable { + private readonly SmtpSettingsPart _smtpSettings; + private readonly Lazy _smtpClientField; + public static readonly string MessageType = "Email"; + + public SmtpMessageChannel(SmtpSettingsPart smtpSettings) { + _smtpSettings = smtpSettings; + _smtpClientField = new Lazy(CreateSmtpClient); + } + + public void Dispose() { + if (!_smtpClientField.IsValueCreated) { + return; + } + + _smtpClientField.Value.Dispose(); + } + + public void Process(string payload) { + if (!_smtpSettings.IsValid()) { + return; + } + + var emailMessage = JsonConvert.DeserializeObject(payload); + if (emailMessage == null) { + return; + } + + if (emailMessage.Recipients.Length == 0) { + Logger.Error("Email message doesn't have any recipient"); + return; + } + + var mailMessage = new MailMessage { + From = new MailAddress(_smtpSettings.Address), + Subject = emailMessage.Subject, + Body = emailMessage.Body, + IsBodyHtml = emailMessage.Body != null && emailMessage.Body.Contains("<") && emailMessage.Body.Contains(">") + }; + + try { + foreach (var recipient in emailMessage.Recipients) { + mailMessage.To.Add(new MailAddress(recipient)); + } + + _smtpClientField.Value.Send(mailMessage); + } + catch (Exception e) { + Logger.Error(e, "Could not send email"); + } + } + + private SmtpClient CreateSmtpClient() { + var smtpClient = new SmtpClient { + UseDefaultCredentials = !_smtpSettings.RequireCredentials + }; + + if (!smtpClient.UseDefaultCredentials && !String.IsNullOrWhiteSpace(_smtpSettings.UserName)) { + smtpClient.Credentials = new NetworkCredential(_smtpSettings.UserName, _smtpSettings.Password); + } + + if (_smtpSettings.Host != null) { + smtpClient.Host = _smtpSettings.Host; + } + + smtpClient.Port = _smtpSettings.Port; + smtpClient.EnableSsl = _smtpSettings.EnableSsl; + smtpClient.DeliveryMethod = SmtpDeliveryMethod.Network; + return smtpClient; + } + } +} diff --git a/src/Orchard.Web/Modules/Orchard.Messaging/AdminMenu.cs b/src/Orchard.Web/Modules/Orchard.Messaging/AdminMenu.cs index 015a52b65..22d222e37 100644 --- a/src/Orchard.Web/Modules/Orchard.Messaging/AdminMenu.cs +++ b/src/Orchard.Web/Modules/Orchard.Messaging/AdminMenu.cs @@ -1,33 +1,16 @@ -using System.Linq; -using Orchard.Environment.Extensions; -using Orchard.Messaging.Services; -using Orchard.UI.Navigation; +using Orchard.UI.Navigation; namespace Orchard.Messaging { - [OrchardFeature("Orchard.Messaging.Queuing")] public class AdminMenu : Component, INavigationProvider { - private readonly IMessageQueueManager _messageQueueManager; - - public AdminMenu(IMessageQueueManager messageQueueManager) { - _messageQueueManager = messageQueueManager; - } public string MenuName { get { return "admin"; } } public void GetNavigation(NavigationBuilder builder) { - var queues = _messageQueueManager.GetQueues().ToList(); builder .AddImageSet("messaging") - .Add(T("Messaging"), "5.0", item => { - if (queues.Count == 1) { - item.Action("List", "AdminQueue", new { area = "Orchard.Messaging", id = queues.First().Id }); - item.LinkToFirstChild(false); - } - else { - item.Action("Index", "AdminQueue", new { area = "Orchard.Messaging" }); - } - item.Add(T("Priorities"), "1.1", subItem => subItem - .Action("Index", "AdminPriority", new { area = "Orchard.Messaging" })); + .Add(T("Message Queue"), "15.0", item => { + item.Action("List", "Admin", new { area = "Orchard.Messaging" }); + item.LinkToFirstChild(false); }); } } diff --git a/src/Orchard.Web/Modules/Orchard.Messaging/Controllers/AdminController.cs b/src/Orchard.Web/Modules/Orchard.Messaging/Controllers/AdminController.cs new file mode 100644 index 000000000..91ee945ff --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Messaging/Controllers/AdminController.cs @@ -0,0 +1,90 @@ +using System.Linq; +using System.Web.Mvc; +using Orchard.ContentManagement; +using Orchard.DisplayManagement; +using Orchard.Localization; +using Orchard.Messaging.Models; +using Orchard.Messaging.Services; +using Orchard.Messaging.ViewModels; +using Orchard.Mvc; +using Orchard.UI.Admin; +using Orchard.UI.Navigation; +using Orchard.UI.Notify; + +namespace Orchard.Messaging.Controllers { + [Admin] + public class AdminController : Controller { + private readonly IMessageQueueService _messageQueueManager; + private readonly IOrchardServices _services; + private readonly IMessageQueueProcessor _messageQueueProcessor; + + public AdminController( + IMessageQueueService messageQueueManager, + IShapeFactory shapeFactory, + IOrchardServices services, + IMessageQueueProcessor messageQueueProcessor) { + _messageQueueManager = messageQueueManager; + _services = services; + _messageQueueProcessor = messageQueueProcessor; + New = shapeFactory; + T = NullLocalizer.Instance; + } + + public dynamic New { get; set; } + public Localizer T { get; set; } + public ActionResult Details(int id, string returnUrl) { + var message = _messageQueueManager.GetMessage(id); + + if (!Url.IsLocalUrl(returnUrl)) + returnUrl = Url.Action("List"); + + var model = New.ViewModel().Message(message).ReturnUrl(returnUrl); + return View(model); + } + + public ActionResult List(MessagesFilter filter, PagerParameters pagerParameters) { + var pager = new Pager(_services.WorkContext.CurrentSite, pagerParameters); + + var messageCount = _messageQueueManager.GetMessagesCount(filter.Status); + var messages = _messageQueueManager.GetMessages(filter.Status, pager.GetStartIndex(), pager.PageSize).ToList(); + var model = _services.New.ViewModel() + .Pager(_services.New.Pager(pager).TotalItemCount(messageCount)) + .MessageQueueStatus(_services.WorkContext.CurrentSite.As().Status) + .Messages(messages) + .Filter(filter); + + return View(model); + } + + [HttpPost, ActionName("List")] + [FormValueRequired("submit.Filter")] + public ActionResult Filter(QueuedMessageStatus? status) { + return RedirectToAction("List", new { status }); + } + + [HttpPost, ActionName("List")] + [FormValueRequired("submit.Resume")] + public ActionResult Resume(QueuedMessageStatus? status) { + _messageQueueManager.Resume(); + _services.Notifier.Information(T("The queue has been resumed.")); + return RedirectToAction("List", new { status }); + } + + [HttpPost, ActionName("List")] + [FormValueRequired("submit.Pause")] + public ActionResult Pause(QueuedMessageStatus? status) { + _messageQueueManager.Pause(); + _services.Notifier.Information(T("The queue has been paused.")); + return RedirectToAction("List", new { status }); + } + + [HttpPost, ActionName("List")] + [FormValueRequired("submit.Process")] + public ActionResult Process(QueuedMessageStatus? status) { + _messageQueueProcessor.ProcessQueue(); + _services.Notifier.Information(T("Processing has started.")); + return RedirectToAction("List", new { status }); + } + + } +} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Messaging/Controllers/AdminMessageController.cs b/src/Orchard.Web/Modules/Orchard.Messaging/Controllers/AdminMessageController.cs deleted file mode 100644 index f8d4176ec..000000000 --- a/src/Orchard.Web/Modules/Orchard.Messaging/Controllers/AdminMessageController.cs +++ /dev/null @@ -1,31 +0,0 @@ -using System.Web.Mvc; -using Orchard.DisplayManagement; -using Orchard.Environment.Extensions; -using Orchard.Messaging.Services; -using Orchard.UI.Admin; - -namespace Orchard.Messaging.Controllers { - [OrchardFeature("Orchard.Messaging.Queuing")] - [Admin] - public class AdminMessageController : Controller { - private readonly IMessageQueueManager _messageQueueManager; - - public AdminMessageController(IMessageQueueManager messageQueueManager, IShapeFactory shapeFactory) { - _messageQueueManager = messageQueueManager; - New = shapeFactory; - } - - public dynamic New { get; set; } - - public ActionResult Details(int id, string returnUrl) { - var message = _messageQueueManager.GetMessage(id); - - if (!Url.IsLocalUrl(returnUrl)) - returnUrl = Url.Action("List", "AdminQueue", new {message.Queue.Id}); - - var model = New.ViewModel().Message(message).ReturnUrl(returnUrl); - return View(model); - } - - } -} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Messaging/Controllers/AdminPriorityController.cs b/src/Orchard.Web/Modules/Orchard.Messaging/Controllers/AdminPriorityController.cs deleted file mode 100644 index 5af2d09ab..000000000 --- a/src/Orchard.Web/Modules/Orchard.Messaging/Controllers/AdminPriorityController.cs +++ /dev/null @@ -1,86 +0,0 @@ -using System.Linq; -using System.Web.Mvc; -using Orchard.DisplayManagement; -using Orchard.Environment.Extensions; -using Orchard.Localization; -using Orchard.Messaging.Extensions; -using Orchard.Messaging.Services; -using Orchard.Messaging.ViewModels; -using Orchard.UI.Admin; -using Orchard.UI.Notify; - -namespace Orchard.Messaging.Controllers { - [OrchardFeature("Orchard.Messaging.Queuing")] - [Admin] - public class AdminPriorityController : Controller { - private readonly IMessageQueueManager _messageQueueManager; - private readonly INotifier _notifier; - - public AdminPriorityController(IMessageQueueManager messageQueueManager, IShapeFactory shapeFactory, INotifier notifier) { - _messageQueueManager = messageQueueManager; - _notifier = notifier; - New = shapeFactory; - T = NullLocalizer.Instance; - } - - public Localizer T { get; set; } - public dynamic New { get; set; } - - public ActionResult Index() { - var priorities = _messageQueueManager.GetPriorities().ToList(); - var model = New.ViewModel().Priorities(priorities); - return View(model); - } - - [HttpPost] - public ActionResult Delete(int id) { - var priority = _messageQueueManager.GetPriority(id); - _messageQueueManager.DeletePriority(priority); - _notifier.Information(T("That priority has been deleted.")); - return RedirectToAction("Index"); - } - - public ActionResult Create() { - return View(new MessagePriorityViewModel()); - } - - [HttpPost] - public ActionResult Create(MessagePriorityViewModel model) { - if (!ModelState.IsValid) - return View(model); - - var priority = _messageQueueManager.CreatePriority(model.Name.TrimSafe(), model.DisplayText.TrimSafe(), model.Value); - _notifier.Information(T("Your Priority has been created.")); - return RedirectToAction("Edit", new { priority.Id }); - } - - public ActionResult Edit(int id) { - var priority = _messageQueueManager.GetPriority(id); - if (priority == null || priority.Archived) - return HttpNotFound(); - - var model = new MessagePriorityViewModel { - Id = priority.Id, - Name = priority.Name, - DisplayText = priority.DisplayText, - Value = priority.Value - }; - - return View(model); - } - - [HttpPost] - public ActionResult Edit(MessagePriorityViewModel model) { - if (!ModelState.IsValid) - return View(model); - - var priority = _messageQueueManager.GetPriority(model.Id); - priority.Name = model.Name.TrimSafe(); - priority.DisplayText = model.DisplayText.TrimSafe(); - priority.Value = model.Value; - - _notifier.Information(T("Your Priority has been updated.")); - return RedirectToAction("Edit", new { priority.Id }); - } - } -} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Messaging/Controllers/AdminQueueController.cs b/src/Orchard.Web/Modules/Orchard.Messaging/Controllers/AdminQueueController.cs deleted file mode 100644 index 37e7df8e3..000000000 --- a/src/Orchard.Web/Modules/Orchard.Messaging/Controllers/AdminQueueController.cs +++ /dev/null @@ -1,138 +0,0 @@ -using System.Linq; -using System.Web.Mvc; -using Orchard.Environment.Extensions; -using Orchard.Localization; -using Orchard.Messaging.Models; -using Orchard.Messaging.Services; -using Orchard.Messaging.ViewModels; -using Orchard.Mvc; -using Orchard.UI.Admin; -using Orchard.UI.Navigation; -using Orchard.UI.Notify; - -namespace Orchard.Messaging.Controllers { - [OrchardFeature("Orchard.Messaging.Queuing")] - [Admin] - public class AdminQueueController : Controller { - private readonly IMessageQueueManager _messageQueueManager; - private readonly IOrchardServices _services; - private readonly IMessageQueueProcessor _messageQueueProcessor; - - public AdminQueueController(IMessageQueueManager messageQueueManager, IOrchardServices services, IMessageQueueProcessor messageQueueProcessor) { - _messageQueueManager = messageQueueManager; - _services = services; - _messageQueueProcessor = messageQueueProcessor; - T = NullLocalizer.Instance; - } - - public Localizer T { get; set; } - - public ActionResult Index() { - var queues = _messageQueueManager.GetQueues().ToList(); - - if (queues.Count == 1) { - return RedirectToAction("List", new {id = queues.First().Id}); - } - - var queueShapes = queues.Select(x => _services.New.Queue(x) - .Pending(_messageQueueManager.CountMessages(x.Id, QueuedMessageStatus.Pending)) - .Faulted(_messageQueueManager.CountMessages(x.Id, QueuedMessageStatus.Faulted)) - .Sent(_messageQueueManager.CountMessages(x.Id, QueuedMessageStatus.Sent))).ToList(); - - var model = _services.New.ViewModel() - .Queues(queueShapes); - - return View(model); - } - - public ActionResult Edit(int id, string returnUrl) { - var queue = _messageQueueManager.GetQueue(id); - var model = new MessageQueueViewModel { - Id = queue.Id, - Name = queue.Name, - ReturnUrl = returnUrl - }; - return View(model); - } - - [HttpPost] - public ActionResult Edit(MessageQueueViewModel model) { - if (!ModelState.IsValid) - return View(model); - - CreateOrUpdateQueue(model); - _services.Notifier.Information(T("Your queue has been updated.")); - return Url.IsLocalUrl(model.ReturnUrl) ? (ActionResult) Redirect(model.ReturnUrl) : RedirectToAction("Edit", new {id = model.Id}); - } - - public ActionResult Create() { - return View(new MessageQueueViewModel()); - } - - [HttpPost] - public ActionResult Create(MessageQueueViewModel model) { - if (!ModelState.IsValid) - return View(model); - - var queue = CreateOrUpdateQueue(model); - _services.Notifier.Information(T("Your queue has been created.")); - return RedirectToAction("Edit", new { id = queue.Id }); - } - - public ActionResult List(int id, MessagesFilter filter, PagerParameters pagerParameters) { - var pager = new Pager(_services.WorkContext.CurrentSite, pagerParameters); - var queue = _messageQueueManager.GetQueue(id); - - if (queue == null) - return HttpNotFound(); - - var messageCount = _messageQueueManager.CountMessages(queue.Id, filter.Status); - var messages = _messageQueueManager.GetMessages(queue.Id, filter.Status, pager.GetStartIndex(), pager.PageSize).ToList(); - var model = _services.New.ViewModel() - .Pager(_services.New.Pager(pager).TotalItemCount(messageCount)) - .Queue(queue) - .Messages(messages) - .Filter(filter); - - return View(model); - } - - [HttpPost, ActionName("List")] - [FormValueRequired("submit.Filter")] - public ActionResult Filter(int id, QueuedMessageStatus? status) { - return RedirectToAction("List", new {id, status}); - } - - [HttpPost, ActionName("List")] - [FormValueRequired("submit.Resume")] - public ActionResult Resume(int id, QueuedMessageStatus? status) { - var queue = _messageQueueManager.GetQueue(id); - _messageQueueManager.Resume(queue); - _services.Notifier.Information(T("The queue has been resumed.")); - return RedirectToAction("List", new { id, status }); - } - - [HttpPost, ActionName("List")] - [FormValueRequired("submit.Pause")] - public ActionResult Pause(int id, QueuedMessageStatus? status) { - var queue = _messageQueueManager.GetQueue(id); - _messageQueueManager.Pause(queue); - _services.Notifier.Information(T("The queue has been paused.")); - return RedirectToAction("List", new { id, status }); - } - - [HttpPost, ActionName("List")] - [FormValueRequired("submit.Process")] - public ActionResult Process(int id, QueuedMessageStatus? status) { - _messageQueueProcessor.ProcessQueues(); - _services.Notifier.Information(T("Processing has started.")); - return RedirectToAction("List", new { id, status }); - } - - private MessageQueue CreateOrUpdateQueue(MessageQueueViewModel model) { - var queue = _messageQueueManager.GetQueue(model.Id) ?? _messageQueueManager.CreateQueue(); - queue.Name = model.Name; - return queue; - } - } -} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Messaging/Drivers/MessageSettingsPartDriver.cs b/src/Orchard.Web/Modules/Orchard.Messaging/Drivers/MessageSettingsPartDriver.cs index cbc319c69..f58270c44 100644 --- a/src/Orchard.Web/Modules/Orchard.Messaging/Drivers/MessageSettingsPartDriver.cs +++ b/src/Orchard.Web/Modules/Orchard.Messaging/Drivers/MessageSettingsPartDriver.cs @@ -3,18 +3,15 @@ using Orchard.ContentManagement; using Orchard.ContentManagement.Drivers; using Orchard.Localization; using Orchard.Messaging.Models; -using Orchard.Messaging.Services; using Orchard.Messaging.ViewModels; namespace Orchard.Messaging.Drivers { [UsedImplicitly] public class MessageSettingsPartDriver : ContentPartDriver { private const string TemplateName = "Parts/MessageSettings"; - private readonly IMessageManager _messageQueueManager; public IOrchardServices Services { get; set; } - public MessageSettingsPartDriver(IOrchardServices services, IMessageManager messageQueueManager) { - _messageQueueManager = messageQueueManager; + public MessageSettingsPartDriver(IOrchardServices services) { Services = services; T = NullLocalizer.Instance; } @@ -26,7 +23,6 @@ namespace Orchard.Messaging.Drivers { protected override DriverResult Editor(MessageSettingsPart part, dynamic shapeHelper) { var model = new MessageSettingsPartViewModel { - ChannelServices = _messageQueueManager.GetAvailableChannelServices(), MessageSettings = part }; @@ -35,7 +31,6 @@ namespace Orchard.Messaging.Drivers { protected override DriverResult Editor(MessageSettingsPart part, IUpdateModel updater, dynamic shapeHelper) { var model = new MessageSettingsPartViewModel { - ChannelServices = _messageQueueManager.GetAvailableChannelServices(), MessageSettings = part }; diff --git a/src/Orchard.Web/Modules/Orchard.Messaging/Migrations.cs b/src/Orchard.Web/Modules/Orchard.Messaging/Migrations.cs new file mode 100644 index 000000000..afea22e3b --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Messaging/Migrations.cs @@ -0,0 +1,23 @@ +using System; +using Orchard.Data.Migration; + +namespace Orchard.Messaging { + public class Migrations : DataMigrationImpl { + + public int Create() { + SchemaBuilder.CreateTable("QueuedMessageRecord", table => table + .Column("Id", c => c.Identity().PrimaryKey()) + .Column("Type", c => c.WithLength(64)) + .Column("Priority", c => c.WithDefault(0)) + .Column("Payload", c => c.Unlimited()) + .Column("Status", c => c.WithLength(64)) + .Column("Result", c => c.Unlimited()) + .Column("CreatedUtc") + .Column("StartedUtc") + .Column("CompletedUtc") + ); + + return 1; + } + } +} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Messaging/Migrations/MessagingMigrations.cs b/src/Orchard.Web/Modules/Orchard.Messaging/Migrations/MessagingMigrations.cs deleted file mode 100644 index ad1ba91f2..000000000 --- a/src/Orchard.Web/Modules/Orchard.Messaging/Migrations/MessagingMigrations.cs +++ /dev/null @@ -1,14 +0,0 @@ -using Orchard.Data.Migration; - -namespace Orchard.Messaging.Migrations { - public class MessagingMigrations : DataMigrationImpl { - - public int Create() { - SchemaBuilder.CreateTable("MessageSettingsPartRecord", table => table - .ContentPartRecord() - .Column("DefaultChannelService", c => c.WithLength(64))); - - return 1; - } - } -} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Messaging/Migrations/MessagingQueuingMigrations.cs b/src/Orchard.Web/Modules/Orchard.Messaging/Migrations/MessagingQueuingMigrations.cs deleted file mode 100644 index 82c5233f5..000000000 --- a/src/Orchard.Web/Modules/Orchard.Messaging/Migrations/MessagingQueuingMigrations.cs +++ /dev/null @@ -1,50 +0,0 @@ -using System; -using Orchard.Data.Migration; -using Orchard.Environment.Extensions; -using Orchard.Messaging.Services; - -namespace Orchard.Messaging.Migrations { - [OrchardFeature("Orchard.Messaging.Queuing")] - public class MessagingQueuingMigrations : DataMigrationImpl { - private readonly IMessageQueueManager _messageQueueManager; - - public MessagingQueuingMigrations(IMessageQueueManager messageQueueManager) { - _messageQueueManager = messageQueueManager; - } - - public int Create() { - SchemaBuilder.CreateTable("MessagePriority", table => table - .Column("Id", c => c.Identity().PrimaryKey()) - .Column("Value", c => c.NotNull()) - .Column("Name", c => c.WithLength(50)) - .Column("DisplayText", c => c.WithLength(50)) - .Column("Archived", c => c.NotNull()) - .Column("ArchivedUtc")); - - SchemaBuilder.CreateTable("MessageQueueRecord", table => table - .Column("Id", c => c.Identity().PrimaryKey()) - .Column("Name", c => c.WithLength(50)) - .Column("Status", c => c.WithLength(50)) - .Column("StartedUtc") - .Column("EndedUtc")); - - SchemaBuilder.CreateTable("QueuedMessageRecord", table => table - .Column("Id", c => c.Identity().PrimaryKey()) - .Column("QueueId", c => c.NotNull()) - .Column("Priority_Id") - .Column("ChannelName", c => c.WithLength(50)) - .Column("Recipients", c => c.Unlimited()) - .Column("Payload", c => c.Unlimited()) - .Column("Status", c => c.WithLength(50)) - .Column("CreatedUtc") - .Column("StartedUtc") - .Column("CompletedUtc") - .Column("Result", c => c.Unlimited())); - - _messageQueueManager.CreateDefaultQueue(); - _messageQueueManager.CreateDefaultPriorities(); - - return 1; - } - } -} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Messaging/Models/MessagePriority.cs b/src/Orchard.Web/Modules/Orchard.Messaging/Models/MessagePriority.cs deleted file mode 100644 index b9314fde7..000000000 --- a/src/Orchard.Web/Modules/Orchard.Messaging/Models/MessagePriority.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System; - -namespace Orchard.Messaging.Models { - public class MessagePriority { - public virtual int Id { get; set; } - public virtual int Value { get; set; } - public virtual string Name { get; set; } - public virtual string DisplayText { get; set; } - public virtual bool Archived { get; set; } - public virtual DateTime? ArchivedUtc { get; set; } - - public override string ToString() { - return String.Format("{0} - {1}", Value, Name); - } - } -} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Messaging/Models/MessageQueue.cs b/src/Orchard.Web/Modules/Orchard.Messaging/Models/MessageQueue.cs deleted file mode 100644 index b0a5e9bc5..000000000 --- a/src/Orchard.Web/Modules/Orchard.Messaging/Models/MessageQueue.cs +++ /dev/null @@ -1,39 +0,0 @@ -using System; - -namespace Orchard.Messaging.Models { - public class MessageQueue { - public MessageQueue(MessageQueueRecord record) { - Record = record; - } - - public MessageQueueRecord Record { get; private set; } - - public int Id { - get { return Record.Id; } - } - - public string Name { - get { return Record.Name; } - set { Record.Name = value; } - } - - public MessageQueueStatus Status { - get { return Record.Status; } - internal set { Record.Status = value; } - } - - public DateTime? StartedUtc { - get { return Record.StartedUtc; } - internal set { Record.StartedUtc = value; } - } - - public DateTime? EndedUtc { - get { return Record.EndedUtc; } - internal set { Record.EndedUtc = value; } - } - - public override string ToString() { - return String.Format("{0} - {1}", Name, Status); - } - } -} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Messaging/Models/MessageQueueRecord.cs b/src/Orchard.Web/Modules/Orchard.Messaging/Models/MessageQueueRecord.cs deleted file mode 100644 index 834c4d3bc..000000000 --- a/src/Orchard.Web/Modules/Orchard.Messaging/Models/MessageQueueRecord.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System; - -namespace Orchard.Messaging.Models { - public class MessageQueueRecord { - public virtual int Id { get; set; } - public virtual string Name { get; set; } - public virtual MessageQueueStatus Status { get; set; } - public virtual DateTime? StartedUtc { get; set; } - public virtual DateTime? EndedUtc { get; set; } - - public override string ToString() { - return String.Format("{0} - {1}", Name, Status); - } - } -} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Messaging/Models/MessageQueueStatus.cs b/src/Orchard.Web/Modules/Orchard.Messaging/Models/MessageQueueStatus.cs index 27c29fd5f..24b347d3d 100644 --- a/src/Orchard.Web/Modules/Orchard.Messaging/Models/MessageQueueStatus.cs +++ b/src/Orchard.Web/Modules/Orchard.Messaging/Models/MessageQueueStatus.cs @@ -1,7 +1,6 @@ namespace Orchard.Messaging.Models { public enum MessageQueueStatus { Idle, - Processing, Paused } } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Messaging/Models/MessageRecipient.cs b/src/Orchard.Web/Modules/Orchard.Messaging/Models/MessageRecipient.cs deleted file mode 100644 index 5a9b5bd97..000000000 --- a/src/Orchard.Web/Modules/Orchard.Messaging/Models/MessageRecipient.cs +++ /dev/null @@ -1,15 +0,0 @@ -namespace Orchard.Messaging.Models { - public class MessageRecipient { - public string AddressOrAlias { get; set; } - - public MessageRecipient() {} - - public MessageRecipient(string addressOrAlias) { - AddressOrAlias = addressOrAlias; - } - - public override string ToString() { - return AddressOrAlias; - } - } -} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Messaging/Models/MessageSettingsPart.cs b/src/Orchard.Web/Modules/Orchard.Messaging/Models/MessageSettingsPart.cs index 796aed4c4..69064bf4d 100644 --- a/src/Orchard.Web/Modules/Orchard.Messaging/Models/MessageSettingsPart.cs +++ b/src/Orchard.Web/Modules/Orchard.Messaging/Models/MessageSettingsPart.cs @@ -1,15 +1,11 @@ -using System.ComponentModel.DataAnnotations; -using Orchard.ContentManagement; +using Orchard.ContentManagement; namespace Orchard.Messaging.Models { public class MessageSettingsPart : ContentPart { - public const ushort DefaultChannelServiceLength = 64; - - [StringLength(DefaultChannelServiceLength)] - public string DefaultChannelService { - get { return this.Retrieve(x => x.DefaultChannelService); } - set { this.Store(x => x.DefaultChannelService, value); } + public MessageQueueStatus Status { + get { return this.Retrieve(x => x.Status); } + set { this.Store(x => x.Status, value); } } } } diff --git a/src/Orchard.Web/Modules/Orchard.Messaging/Models/QueuedMessage.cs b/src/Orchard.Web/Modules/Orchard.Messaging/Models/QueuedMessage.cs deleted file mode 100644 index 98d295234..000000000 --- a/src/Orchard.Web/Modules/Orchard.Messaging/Models/QueuedMessage.cs +++ /dev/null @@ -1,80 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using Newtonsoft.Json; -using Orchard.Messaging.Services; - -namespace Orchard.Messaging.Models { - public class QueuedMessage { - // ReSharper disable InconsistentNaming - public Lazy QueueField; - public Lazy ChannelField; - public Lazy> RecipientsField; - // ReSharper restore InconsistentNaming - - public QueuedMessage(QueuedMessageRecord record) { - Record = record; - } - - public QueuedMessageRecord Record { - get; private set; - } - - public int Id { - get { return Record.Id; } - } - - public MessagePriority Priority { - get { return Record.Priority; } - set { Record.Priority = value; } - } - - public QueuedMessageStatus Status { - get { return Record.Status; } - internal set { Record.Status = value; } - } - - public string Result { - get { return Record.Result; } - set { Record.Result = value; } - } - - public DateTime CreatedUtc { - get { return Record.CreatedUtc; } - } - - public DateTime? StartedUtc { - get { return Record.StartedUtc; } - internal set { Record.StartedUtc = value; } - } - - public DateTime? CompletedUtc { - get { return Record.CompletedUtc; } - internal set { Record.CompletedUtc = value; } - } - - public MessageQueue Queue { - get { return QueueField.Value; } - } - - public IMessageChannel Channel { - get { return ChannelField.Value; } - } - - public IEnumerable Recipients { - get { return RecipientsField.Value; } - } - - public T GetPayload() { - return Record.Payload != null ? JsonConvert.DeserializeObject(Record.Payload) : default(T); - } - - public void SetPayload(T value) { - Record.Payload = !ReferenceEquals(value, default(T)) ? JsonConvert.SerializeObject(value) : null; - } - - public override string ToString() { - return String.Format("Recipients: {0}", String.Join(", ", Recipients.Select(x => x.ToString()))); - } - } -} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Messaging/Models/QueuedMessageRecord.cs b/src/Orchard.Web/Modules/Orchard.Messaging/Models/QueuedMessageRecord.cs index 6d2474e73..44642c857 100644 --- a/src/Orchard.Web/Modules/Orchard.Messaging/Models/QueuedMessageRecord.cs +++ b/src/Orchard.Web/Modules/Orchard.Messaging/Models/QueuedMessageRecord.cs @@ -4,13 +4,9 @@ using Orchard.Data.Conventions; namespace Orchard.Messaging.Models { public class QueuedMessageRecord { public virtual int Id { get; set; } - public virtual int QueueId { get; set; } - public virtual MessagePriority Priority { get; set; } - public virtual string ChannelName { get; set; } - - [StringLengthMax] - public virtual string Recipients { get; set; } - + public virtual int Priority { get; set; } + public virtual string Type { get; set; } + [StringLengthMax] public virtual string Payload { get; set; } diff --git a/src/Orchard.Web/Modules/Orchard.Messaging/Module.txt b/src/Orchard.Web/Modules/Orchard.Messaging/Module.txt index 4d6123e48..c368f9c20 100644 --- a/src/Orchard.Web/Modules/Orchard.Messaging/Module.txt +++ b/src/Orchard.Web/Modules/Orchard.Messaging/Module.txt @@ -4,14 +4,9 @@ Author: The Orchard Team Website: http://orchardproject.net Version: 1.7.2 OrchardVersion: 1.7.2 -Description: This module provides the messaging infrastructure that modules such as Workflows can use. It is only useful as a dependency for other modules that implement specific channels, such as e-mail or Twitter. +Description: This module provides the messaging infrastructure that modules can use to send messages. Category: Messaging Features: Orchard.Messaging: - Description: Provides the messaging infrastructure that modules such as Workflows can use. It is only useful as a dependency for other modules that implement specific channels, such as e-mail or Twitter. - Dependencies: Settings - Orchard.Messaging.Queuing - Name: Message Queuing - Description: Provides message queuing facilities and APIs, enabling the queing of messages to be processed at regular intervals. Includes support for prioritized messages and templates messages using shapes. - Category: Messaging - Dependencies: Orchard.Messaging, Orchard.Forms, Orchard.Workflows, Orchard.jQuery \ No newline at end of file + Description: Provides the messaging infrastructure that modules can use to send messages. + Dependencies: Settings, Orchard.TaskLease diff --git a/src/Orchard.Web/Modules/Orchard.Messaging/Orchard.Messaging.csproj b/src/Orchard.Web/Modules/Orchard.Messaging/Orchard.Messaging.csproj index 5697a7145..6a7d412a4 100644 --- a/src/Orchard.Web/Modules/Orchard.Messaging/Orchard.Messaging.csproj +++ b/src/Orchard.Web/Modules/Orchard.Messaging/Orchard.Messaging.csproj @@ -70,32 +70,27 @@ - - - + - - + + + + + + - - - + - - - - - - + @@ -103,10 +98,6 @@ - - - submit.js - admin-messaging.css @@ -131,6 +122,10 @@ {642a49d7-8752-4177-80d6-bfbbcfad3de0} Orchard.Forms + + {3F72A4E9-7B72-4260-B010-C16EC54F9BAF} + Orchard.TaskLease + {7059493c-8251-4764-9c1e-2368b8b485bc} Orchard.Workflows @@ -139,50 +134,22 @@ - - - - - - - + - - - - + - - - - - - submit.js - - - - - - - - - - - - - - + 10.0 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) diff --git a/src/Orchard.Web/Modules/Orchard.Messaging/Scripts/submit.js b/src/Orchard.Web/Modules/Orchard.Messaging/Scripts/submit.js deleted file mode 100644 index b8787205f..000000000 --- a/src/Orchard.Web/Modules/Orchard.Messaging/Scripts/submit.js +++ /dev/null @@ -1,8 +0,0 @@ -(function($) { - $(function() { - $("#layout-content").on("click", ".submit-form", function (e) { - $(this).parents("form:first").submit(); - e.preventDefault(); - }); - }); -})(jQuery); \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Messaging/Scripts/submit.min.js b/src/Orchard.Web/Modules/Orchard.Messaging/Scripts/submit.min.js deleted file mode 100644 index 7f62cf0f0..000000000 --- a/src/Orchard.Web/Modules/Orchard.Messaging/Scripts/submit.min.js +++ /dev/null @@ -1,2 +0,0 @@ -(function(n){n(function(){n("#layout-content").on("click",".submit-form",function(t){n(this).parents("form:first").submit(),t.preventDefault()})})})(jQuery); -//# sourceMappingURL=submit.min.js.map \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Messaging/Scripts/submit.min.js.map b/src/Orchard.Web/Modules/Orchard.Messaging/Scripts/submit.min.js.map deleted file mode 100644 index adcd2c47c..000000000 --- a/src/Orchard.Web/Modules/Orchard.Messaging/Scripts/submit.min.js.map +++ /dev/null @@ -1,8 +0,0 @@ -{ -"version":3, -"file":"submit.min.js", -"lineCount":1, -"mappings":"CAAC,QAAQ,CAACA,CAAD,CAAI,CACTA,CAAC,CAAC,QAAQ,CAAA,CAAG,CACTA,CAAC,CAAC,iBAAD,CAAmBC,GAAG,CAAC,OAAO,CAAE,cAAc,CAAE,QAAS,CAACC,CAAD,CAAI,CAC1DF,CAAC,CAAC,IAAD,CAAMG,QAAQ,CAAC,YAAD,CAAcC,OAAO,CAAA,CAAE,CACtCF,CAACG,eAAe,CAAA,CAF0C,CAAvC,CADd,CAAZ,CADQ,EAOX,CAACC,MAAD,CAAQ", -"sources":["submit.js"], -"names":["$","on","e","parents","submit","preventDefault","jQuery"] -} diff --git a/src/Orchard.Web/Modules/Orchard.Messaging/Services/DefaultMessageService.cs b/src/Orchard.Web/Modules/Orchard.Messaging/Services/DefaultMessageService.cs new file mode 100644 index 000000000..5f816e7bc --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Messaging/Services/DefaultMessageService.cs @@ -0,0 +1,28 @@ +using System.Collections.Generic; +using System.Linq; +using Orchard.Logging; + +namespace Orchard.Messaging.Services { + public class DefaultMessageService : Component, IMessageService { + private readonly IEnumerable _messageChannelSelectors; + + public DefaultMessageService(IEnumerable messageChannelSelectors) { + _messageChannelSelectors = messageChannelSelectors; + } + + public void Send(string type, string payload) { + var messageChannelResult = _messageChannelSelectors + .Select(x => x.GetChannel(type, payload)) + .Where(x => x != null) + .OrderByDescending(x => x.Priority) + .FirstOrDefault(); + + if (messageChannelResult == null || messageChannelResult.MessageChannel == null) { + Logger.Information("No channels where found to process a message of type {0}", type); + return; + } + + messageChannelResult.MessageChannel.Process(payload); + } + } +} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Messaging/Services/IMessageChannel.cs b/src/Orchard.Web/Modules/Orchard.Messaging/Services/IMessageChannel.cs index 5808bd2d5..329e0e676 100644 --- a/src/Orchard.Web/Modules/Orchard.Messaging/Services/IMessageChannel.cs +++ b/src/Orchard.Web/Modules/Orchard.Messaging/Services/IMessageChannel.cs @@ -1,9 +1,5 @@ -using System; -using Orchard.Messaging.Models; - namespace Orchard.Messaging.Services { - public interface IMessageChannel : IDependency, IDisposable { - string Name { get; } - void Send(QueuedMessage message); + public interface IMessageChannel : IDependency { + void Process(string payload); } } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Messaging/Services/IMessageChannelSelector.cs b/src/Orchard.Web/Modules/Orchard.Messaging/Services/IMessageChannelSelector.cs new file mode 100644 index 000000000..1e4656aaf --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Messaging/Services/IMessageChannelSelector.cs @@ -0,0 +1,10 @@ +namespace Orchard.Messaging.Services { + public interface IMessageChannelSelector : IDependency { + MessageChannelSelectorResult GetChannel(string messageType, object payload); + } + + public class MessageChannelSelectorResult { + public int Priority { get; set; } + public IMessageChannel MessageChannel { get; set; } + } +} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Messaging/Services/IMessageQueueProcessor.cs b/src/Orchard.Web/Modules/Orchard.Messaging/Services/IMessageQueueProcessor.cs new file mode 100644 index 000000000..c03e4c57f --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Messaging/Services/IMessageQueueProcessor.cs @@ -0,0 +1,5 @@ +namespace Orchard.Messaging.Services { + public interface IMessageQueueProcessor : ISingletonDependency { + void ProcessQueue(); + } +} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Messaging/Services/IMessageQueueService.cs b/src/Orchard.Web/Modules/Orchard.Messaging/Services/IMessageQueueService.cs new file mode 100644 index 000000000..834380a87 --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Messaging/Services/IMessageQueueService.cs @@ -0,0 +1,13 @@ +using System.Collections.Generic; +using Orchard.Messaging.Models; + +namespace Orchard.Messaging.Services { + public interface IMessageQueueService : IDependency { + QueuedMessageRecord Enqueue(string type, object payload, int priority); + QueuedMessageRecord GetMessage(int id); + IEnumerable GetMessages(QueuedMessageStatus? status, int startIndex, int count); + int GetMessagesCount(QueuedMessageStatus? status = null); + void Resume(); + void Pause(); + } +} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Messaging/Services/IMessageService.cs b/src/Orchard.Web/Modules/Orchard.Messaging/Services/IMessageService.cs new file mode 100644 index 000000000..3fc80cb52 --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Messaging/Services/IMessageService.cs @@ -0,0 +1,5 @@ +namespace Orchard.Messaging.Services { + public interface IMessageService : IDependency { + void Send(string type, string payload); + } +} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Messaging/Services/MessageChannelBase.cs b/src/Orchard.Web/Modules/Orchard.Messaging/Services/MessageChannelBase.cs deleted file mode 100644 index 8479e9942..000000000 --- a/src/Orchard.Web/Modules/Orchard.Messaging/Services/MessageChannelBase.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System; -using Orchard.Messaging.Models; - -namespace Orchard.Messaging.Services { - public abstract class MessageChannelBase : Component, IMessageChannel { - ~MessageChannelBase() { - Dispose(false); - } - - public abstract string Name { get; } - public abstract void Send(QueuedMessage message); - - public void Dispose() { - Dispose(true); - GC.SuppressFinalize(this); - } - - public override string ToString() { - return Name; - } - - protected virtual void Dispose(bool disposing) { } - } -} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Messaging/Services/MessageQueueBackgroundTask.cs b/src/Orchard.Web/Modules/Orchard.Messaging/Services/MessageQueueBackgroundTask.cs index 5f4cb8b18..113e71e50 100644 --- a/src/Orchard.Web/Modules/Orchard.Messaging/Services/MessageQueueBackgroundTask.cs +++ b/src/Orchard.Web/Modules/Orchard.Messaging/Services/MessageQueueBackgroundTask.cs @@ -1,8 +1,6 @@ -using Orchard.Environment.Extensions; -using Orchard.Tasks; +using Orchard.Tasks; namespace Orchard.Messaging.Services { - [OrchardFeature("Orchard.Messaging.Queuing")] public class MessageQueueBackgroundTask : Component, IBackgroundTask { private readonly IMessageQueueProcessor _messageQueueProcessor; public MessageQueueBackgroundTask(IMessageQueueProcessor messageQueueProcessor) { @@ -10,7 +8,7 @@ namespace Orchard.Messaging.Services { } public void Sweep() { - _messageQueueProcessor.ProcessQueues(); + _messageQueueProcessor.ProcessQueue(); } } } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Messaging/Services/MessageQueueManager.cs b/src/Orchard.Web/Modules/Orchard.Messaging/Services/MessageQueueManager.cs deleted file mode 100644 index cee7e101a..000000000 --- a/src/Orchard.Web/Modules/Orchard.Messaging/Services/MessageQueueManager.cs +++ /dev/null @@ -1,284 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using Newtonsoft.Json; -using Orchard.Data; -using Orchard.Environment.Extensions; -using Orchard.Messaging.Models; -using Orchard.Services; - -namespace Orchard.Messaging.Services { - public interface IMessageQueueManager : IDependency { - QueuedMessage Send(MessageRecipient recipient, string channelName, T payload, MessagePriority priority = null, int? queueId = null); - QueuedMessage Send(IEnumerable recipients, string channelName, T payload, MessagePriority priority = null, int? queueId = null); - QueuedMessage Send(string recipient, string channelName, T payload, MessagePriority priority = null, int? queueId = null); - QueuedMessage Send(IEnumerable recipients, string channelName, T payload, MessagePriority priority = null, int? queueId = null); - MessageQueue GetQueue(int id); - MessageQueue GetDefaultQueue(); - MessagePriority GetPriority(int id); - MessagePriority GetPriority(string name); - IEnumerable GetPriorities(); - MessagePriority GetDefaultPriority(); - IEnumerable CreateDefaultPriorities(); - void DeletePriority(MessagePriority priority); - IEnumerable GetIdleQueues(); - void EnterProcessingStatus(MessageQueue queue); - void ExitProcessingStatus(MessageQueue queue); - IEnumerable GetQueues(); - int CountMessages(int queueId, QueuedMessageStatus? status = null); - IQueryable GetMessages(int queueId, QueuedMessageStatus? status = null, int startIndex = 0, int pageSize = 10); - IEnumerable GetPendingMessages(int queueId, int pageSize = 10); - QueuedMessage GetMessage(int id); - MessageQueue CreateQueue(); - MessageQueue CreateDefaultQueue(); - IMessageChannel GetChannel(string name); - IEnumerable GetChannels(); - void Resume(MessageQueue queue); - void Pause(MessageQueue queue); - MessagePriority CreatePriority(string name, string displayText, int rank); - } - - [OrchardFeature("Orchard.Messaging.Queuing")] - public class MessageQueueManager : IMessageQueueManager { - private readonly IClock _clock; - private readonly IRepository _queueRepository; - private readonly IRepository _messageRepository; - private readonly IRepository _priorityRepository; - - public MessageQueueManager( - IClock clock, - IRepository queueRepository, - IRepository messageRepository, - IRepository priorityRepository, - IEnumerable channels) { - _clock = clock; - _queueRepository = queueRepository; - _messageRepository = messageRepository; - _priorityRepository = priorityRepository; - ChannelsDictionary = channels.ToDictionary(x => x.Name); - } - - public QueuedMessage Send(MessageRecipient recipient, string channelName, T payload, MessagePriority priority = null, int? queueId = null) { - return Send(new[] {recipient}, channelName, payload, priority, queueId); - } - - public QueuedMessage Send(string recipient, string channelName, T payload, MessagePriority priority = null, int? queueId = null) { - return Send(new[] { recipient }, channelName, payload, priority, queueId); - } - - public QueuedMessage Send(IEnumerable recipients, string channelName, T payload, MessagePriority priority = null, int? queueId = null) { - return Send(recipients.Select(x => new MessageRecipient(x)), channelName, payload, priority, queueId); - } - - public QueuedMessage Send(IEnumerable recipients, string channelName, T payload, MessagePriority priority = null, int? queueId = null) { - var queue = queueId != null ? GetQueue(queueId.Value) ?? GetDefaultQueue() : GetDefaultQueue(); - - var queuedMessage = new QueuedMessageRecord { - Payload = ToJson(payload), - Recipients = ToJson(recipients.ToList()), - ChannelName = channelName, - Priority = priority ?? GetDefaultPriority(), - QueueId = queue.Id, - CreatedUtc = _clock.UtcNow, - Status = QueuedMessageStatus.Pending - }; - - _messageRepository.Create(queuedMessage); - - return ActivateMessage(queuedMessage); - } - - public IMessageChannel GetChannel(string name) { - return ChannelsDictionary[name]; - } - - public IEnumerable GetChannels() { - return ChannelsDictionary.Select(x => x.Value); - } - - public void Resume(MessageQueue queue) { - if(queue.Status != MessageQueueStatus.Paused) - throw new InvalidOperationException("Cannot resume a queue that is not paused."); - - queue.Status = MessageQueueStatus.Idle; - } - - public void Pause(MessageQueue queue) { - if (queue.Status == MessageQueueStatus.Paused) - throw new InvalidOperationException("Cannot resume a queue that is already paused."); - - queue.Status = MessageQueueStatus.Paused; - } - - public MessagePriority CreatePriority(string name, string displayText, int value) { - var priority = new MessagePriority { - Name = name, - DisplayText = displayText, - Value = value - }; - _priorityRepository.Create(priority); - return priority; - } - - public IDictionary ChannelsDictionary { get; private set; } - - public MessageQueue GetDefaultQueue() { - return ActivateQueue(_queueRepository.Table.FirstOrDefault() ?? CreateDefaultQueue()); - } - - public MessagePriority GetPriority(int id) { - return _priorityRepository.Get(id); - } - - public MessagePriority GetPriority(string name) { - return _priorityRepository.Get(x => x.Name == name); - } - - public IEnumerable GetPriorities() { - return _priorityRepository.Table.Where(x => !x.Archived).OrderBy(x => x.Value).ToList(); - } - - public MessageQueue GetQueue(int id) { - var record = _queueRepository.Get(id); - return record != null ? ActivateQueue(record) : null; - } - - public MessagePriority GetDefaultPriority() { - return _priorityRepository.Table.OrderBy(x => x.Value).FirstOrDefault() ?? CreateDefaultPriorities().First(); - } - - public IEnumerable CreateDefaultPriorities() { - var priorities = new List { - new MessagePriority { - Name = "Low", - DisplayText = "Low", - Value = 1 - }, - new MessagePriority { - Name = "Normal", - DisplayText = "Normal", - Value = 2 - }, - new MessagePriority { - Name = "High", - DisplayText = "High", - Value = 3 - }, - }; - - foreach (var priority in priorities) { - _priorityRepository.Create(priority); - } - - return priorities; - } - - public void DeletePriority(MessagePriority priority) { - priority.Archived = true; - priority.ArchivedUtc = _clock.UtcNow; - } - - public IEnumerable GetIdleQueues() { - return _queueRepository.Table.Where(x => x.Status == MessageQueueStatus.Idle).Select(x => ActivateQueue(x)); - } - - public void EnterProcessingStatus(MessageQueue queue) { - if(queue == null) throw new ArgumentNullException("queue"); - if (queue.Status == MessageQueueStatus.Paused) throw new InvalidOperationException("Cannot process a paused queue. Think about it."); - if (queue.Status == MessageQueueStatus.Processing) throw new InvalidOperationException("Cannot process an already processing queue. What's the point?"); - - queue.Status = MessageQueueStatus.Processing; - queue.StartedUtc = _clock.UtcNow; - } - - public void ExitProcessingStatus(MessageQueue queue) { - if(queue == null) throw new ArgumentNullException("queue"); - if(queue.Status == MessageQueueStatus.Paused) throw new InvalidOperationException("Cannot stop a paused queue."); - if(queue.Status == MessageQueueStatus.Idle) throw new InvalidOperationException("Only processing queues can be stopped."); - - queue.Status = MessageQueueStatus.Idle; - queue.EndedUtc = _clock.UtcNow; - } - - public IEnumerable GetQueues() { - return _queueRepository.Table.Select(ActivateQueue); - } - - public int CountMessages(int queueId, QueuedMessageStatus? status = null) { - return GetMessagesQuery(queueId, status).Count(); - } - - public IQueryable GetMessages(int queueId, QueuedMessageStatus? status = null, int startIndex = 0, int pageSize = 10) { - return GetMessagesQuery(queueId, status).Skip(startIndex).Take(pageSize).Select(ActivateMessage).AsQueryable(); - } - - public QueuedMessage GetMessage(int id) { - return ActivateMessage(_messageRepository.Get(id)); - } - - public MessageQueue CreateQueue() { - var record = new MessageQueueRecord { - Status = MessageQueueStatus.Idle - }; - _queueRepository.Create(record); - return ActivateQueue(record); - } - - MessageQueue IMessageQueueManager.CreateDefaultQueue() { - var queue = CreateQueue(); - queue.Name = "Default"; - return queue; - } - - public IQueryable GetMessagesQuery(int queueId, QueuedMessageStatus? status = null) { - var query = _messageRepository.Table.Where(x => x.QueueId == queueId); - - if (status != null) - query = query.Where(x => x.Status == status.Value); - - query = query.OrderByDescending(x => x.CreatedUtc); - - return query; - } - - public IEnumerable GetPendingMessages(int queueId, int pageSize = 10) { - return _messageRepository.Table - .Where(x => x.Status == QueuedMessageStatus.Pending && x.QueueId == queueId) - .OrderBy(x => x.Priority.Value) - .ThenBy(x => x.CreatedUtc) - .Take(pageSize) - .Select(ActivateMessage) - .ToList(); - } - - private QueuedMessage ActivateMessage(QueuedMessageRecord record) { - return new QueuedMessage(record) { - QueueField = new Lazy(() => GetQueue(record.QueueId)), - RecipientsField = new Lazy>(() => ParseRecipients(record.Recipients)), - ChannelField = new Lazy(() => GetChannel(record.ChannelName)) - }; - } - - private MessageQueue ActivateQueue(MessageQueueRecord record) { - return new MessageQueue(record); - } - - private static IEnumerable ParseRecipients(string data) { - return String.IsNullOrWhiteSpace(data) ? Enumerable.Empty() : JsonConvert.DeserializeObject>(data); - } - - private MessageQueueRecord CreateDefaultQueue() { - var queue = new MessageQueueRecord { - Name = "Default", - Status = MessageQueueStatus.Idle, - }; - - _queueRepository.Create(queue); - return queue; - } - - private static string ToJson(object value) { - return value != null ? JsonConvert.SerializeObject(value) : null; - } - } -} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Messaging/Services/MessageQueueProcessor.cs b/src/Orchard.Web/Modules/Orchard.Messaging/Services/MessageQueueProcessor.cs index bab096c90..173a52840 100644 --- a/src/Orchard.Web/Modules/Orchard.Messaging/Services/MessageQueueProcessor.cs +++ b/src/Orchard.Web/Modules/Orchard.Messaging/Services/MessageQueueProcessor.cs @@ -1,65 +1,62 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Threading; +using Orchard.Environment; using Orchard.Logging; using Orchard.Messaging.Models; using Orchard.Services; +using Orchard.TaskLease.Services; namespace Orchard.Messaging.Services { - public interface IMessageQueueProcessor : IDependency { - void ProcessQueues(); - } + public class MessageQueueProcessor : IMessageQueueProcessor { + private readonly Work _messageQueueService; + private readonly Work _messageService; + private readonly Work _clock; + private readonly Work _taskLeaseService; + private readonly ReaderWriterLockSlim _rwl = new ReaderWriterLockSlim(); - public class MessageQueueProcessor : Component, IMessageQueueProcessor { - private readonly IMessageQueueManager _manager; - private readonly IClock _clock; - - public MessageQueueProcessor(IMessageQueueManager manager, IClock clock) { - _manager = manager; + public MessageQueueProcessor( + Work messageQueueService, + Work messageService, + Work clock, + Work taskLeaseService) { + _messageQueueService = messageQueueService; + _messageService = messageService; _clock = clock; + _taskLeaseService = taskLeaseService; + Logger = NullLogger.Instance; } - public void ProcessQueues() { - var queuesToProcess = GetQueuesToProcess(); + public ILogger Logger { get; set; } + public void ProcessQueue() { + // prevent two threads on the same machine to process the message queue + if (_rwl.TryEnterWriteLock(0)) { + try { + _taskLeaseService.Value.Acquire("MessageQueueProcessor", _clock.Value.UtcNow.AddMinutes(5)); + IEnumerable messages; - foreach (var queue in queuesToProcess.AsParallel()) { - ProcessQueue(queue); - } - } - - private IEnumerable GetQueuesToProcess() { - return _manager.GetIdleQueues().ToList(); - } - - private void ProcessQueue(MessageQueue queue) { - _manager.EnterProcessingStatus(queue); - var messages = _manager.GetPendingMessages(queue.Id); - - while (messages.Any()) { - foreach (var message in messages.AsParallel()) { - ProcessMessage(message); + while ((messages = _messageQueueService.Value.GetMessages(QueuedMessageStatus.Pending, 0, 10).ToArray()).Any()) { + foreach (var message in messages.AsParallel()) { + ProcessMessage(message); + } + } + } + finally { + _rwl.ExitWriteLock(); } - messages = _manager.GetPendingMessages(queue.Id); } - - _manager.ExitProcessingStatus(queue); } - private void ProcessMessage(QueuedMessage message) { - var channel = message.Channel; + private void ProcessMessage(QueuedMessageRecord message) { - message.StartedUtc = _clock.UtcNow; + message.StartedUtc = _clock.Value.UtcNow; message.Status = QueuedMessageStatus.Sending; Logger.Debug("Sending message ID {0}.", message.Id); - if (!message.Recipients.Any()) { - message.Status = QueuedMessageStatus.Faulted; - message.Result = String.Format("Cannot send message {0} because at least on recipient is required.", message.Id); - Logger.Error(message.Result); - return; - } + try { - channel.Send(message); + _messageService.Value.Send(message.Type, message.Payload); message.Status = QueuedMessageStatus.Sent; Logger.Debug("Sent message ID {0}.", message.Id); } @@ -69,7 +66,7 @@ namespace Orchard.Messaging.Services { Logger.Error(e, "An unexpected error while sending message {0}. Error message: {1}.", message.Id, e); } finally { - message.CompletedUtc = _clock.UtcNow; + message.CompletedUtc = _clock.Value.UtcNow; } } } diff --git a/src/Orchard.Web/Modules/Orchard.Messaging/Services/MessageQueueService.cs b/src/Orchard.Web/Modules/Orchard.Messaging/Services/MessageQueueService.cs new file mode 100644 index 000000000..320b2e384 --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Messaging/Services/MessageQueueService.cs @@ -0,0 +1,80 @@ +using System.Collections.Generic; +using System.Linq; +using Newtonsoft.Json; +using Orchard.ContentManagement; +using Orchard.Data; +using Orchard.Messaging.Models; +using Orchard.Services; +using Orchard.Settings; + +namespace Orchard.Messaging.Services { + public class MessageQueueService : IMessageQueueService { + private readonly IClock _clock; + private readonly IRepository _messageRepository; + private readonly MessageSettingsPart _messageSettingsPart; + + public MessageQueueService( + IClock clock, + IRepository messageRepository, + ISiteService siteService) { + _clock = clock; + _messageRepository = messageRepository; + _messageSettingsPart = siteService.GetSiteSettings().As(); + } + + public QueuedMessageRecord Enqueue(string channelName, object payload, int priority) { + + var queuedMessage = new QueuedMessageRecord { + Payload = ToJson(payload), + Type = channelName, + CreatedUtc = _clock.UtcNow, + Status = QueuedMessageStatus.Pending + }; + + _messageRepository.Create(queuedMessage); + + return queuedMessage; + } + + public void Resume() { + _messageSettingsPart.Status = MessageQueueStatus.Idle; + } + + public void Pause() { + _messageSettingsPart.Status = MessageQueueStatus.Paused; + } + + public int GetMessagesCount(QueuedMessageStatus? status = null) { + return GetMessagesQuery(status).Count(); + } + + public IEnumerable GetMessages(QueuedMessageStatus? status, int startIndex, int pageSize) { + return GetMessagesQuery(status) + .Skip(startIndex) + .Take(pageSize) + .ToList(); + } + + public QueuedMessageRecord GetMessage(int id) { + return _messageRepository.Get(id); + } + + private IQueryable GetMessagesQuery(QueuedMessageStatus? status) { + var query = _messageRepository.Table; + + if (status != null) { + query = query.Where(x => x.Status == status.Value); + } + + query = query + .OrderByDescending(x => x.Priority) + .ThenByDescending(x => x.CreatedUtc); + + return query; + } + + private static string ToJson(object value) { + return value != null ? JsonConvert.SerializeObject(value) : null; + } + } +} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Messaging/Services/NullMessageChannelSelector.cs b/src/Orchard.Web/Modules/Orchard.Messaging/Services/NullMessageChannelSelector.cs new file mode 100644 index 000000000..84312bad7 --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Messaging/Services/NullMessageChannelSelector.cs @@ -0,0 +1,10 @@ +namespace Orchard.Messaging.Services { + /// + /// Default empty implementation of + /// + public class NullMessageChannelSelector : IMessageChannelSelector { + public MessageChannelSelectorResult GetChannel(string messageType, object payload) { + return null; + } + } +} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Messaging/Styles/menu.messaging-admin.css b/src/Orchard.Web/Modules/Orchard.Messaging/Styles/menu.messaging-admin.css index 502230cd5..bb3f137a7 100644 --- a/src/Orchard.Web/Modules/Orchard.Messaging/Styles/menu.messaging-admin.css +++ b/src/Orchard.Web/Modules/Orchard.Messaging/Styles/menu.messaging-admin.css @@ -1,7 +1,7 @@ -.navicon-messaging { +.navicon-message-queue { background-image: url(./images/menu.messaging.png) !important; } -.navicon-messaging:hover { +.navicon-message-queue:hover { background-position: 0 -30px !important; } diff --git a/src/Orchard.Web/Modules/Orchard.Messaging/Tests/MessageQueueProcessorTests.cs b/src/Orchard.Web/Modules/Orchard.Messaging/Tests/MessageQueueProcessorTests.cs index f27ec18e5..777c771f3 100644 --- a/src/Orchard.Web/Modules/Orchard.Messaging/Tests/MessageQueueProcessorTests.cs +++ b/src/Orchard.Web/Modules/Orchard.Messaging/Tests/MessageQueueProcessorTests.cs @@ -10,59 +10,49 @@ using Orchard.Tests; namespace Orchard.Messaging.Tests { [TestFixture] public class MessageQueueProcessorTests : DatabaseEnabledTestsBase { - private List _messages; + private List _messages; protected override IEnumerable DatabaseTypes { get { - yield return typeof(MessageQueueRecord); - yield return typeof(MessagePriority); yield return typeof(QueuedMessageRecord); } } public override void Register(ContainerBuilder builder) { - var messageManagerMock = new Mock(); - var queue = new MessageQueue(new MessageQueueRecord { - Name = "Default" - }); + var messageManagerMock = new Mock(); builder.RegisterInstance(messageManagerMock.Object); builder.RegisterType().As(); builder.RegisterType().As(); - var queues = new List {queue}; - _messages = new List { + _messages = new List { CreateMessage("Message 1"), CreateMessage("Message 2") }; messageManagerMock - .Setup(x => x.Send(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), null)) + .Setup(x => x.Enqueue(It.IsAny(), It.IsAny(), 0)) .Callback(() => _clock.Advance(TimeSpan.FromSeconds(1))) - .Returns(new QueuedMessage(new QueuedMessageRecord ())); - messageManagerMock.Setup(x => x.GetIdleQueues()).Returns(queues); - messageManagerMock.Setup(x => x.EnterProcessingStatus(queue)).Callback(() => { - queue.Record.Status = MessageQueueStatus.Processing; - queue.Record.StartedUtc = _clock.UtcNow; - }); + .Returns(new QueuedMessageRecord ()); + //messageManagerMock.Setup(x => x.EnterProcessingStatus()).Callback(() => { + // queue.Record.Status = MessageQueueStatus.Processing; + // queue.Record.StartedUtc = _clock.UtcNow; + //}); } [Test] public void ProcessingQueueWithEnoughTimeSendsAllMessages() { var processor = _container.Resolve(); - processor.ProcessQueues(); + processor.ProcessQueue(); foreach (var message in _messages) { Assert.That(message.Status, Is.EqualTo(QueuedMessageStatus.Sent)); } } - private QueuedMessage CreateMessage(string subject) { - return new QueuedMessage(new QueuedMessageRecord {Id = 1, Payload = "some payload data"}) { - ChannelField = new Lazy(() => _container.Resolve(new NamedParameter("simulatedProcessingTime", TimeSpan.FromSeconds(1)), new NamedParameter("clock", _clock))), - RecipientsField = new Lazy>(() => new[]{ new MessageRecipient("recipient@domain.com") }) - }; + private QueuedMessageRecord CreateMessage(string subject) { + return new QueuedMessageRecord {Id = 1, Type = "Email", Payload = "some payload data"}; } } } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Messaging/Tests/MessageQueueTests.cs b/src/Orchard.Web/Modules/Orchard.Messaging/Tests/MessageQueueTests.cs index fe2e2379d..4cee0e0f2 100644 --- a/src/Orchard.Web/Modules/Orchard.Messaging/Tests/MessageQueueTests.cs +++ b/src/Orchard.Web/Modules/Orchard.Messaging/Tests/MessageQueueTests.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Linq; using Autofac; using NUnit.Framework; using Orchard.Messaging.Models; @@ -12,51 +11,13 @@ namespace Orchard.Messaging.Tests { public class MessageQueueTests : DatabaseEnabledTestsBase { protected override IEnumerable DatabaseTypes { get { - yield return typeof(MessageQueueRecord); - yield return typeof(MessagePriority); yield return typeof(QueuedMessageRecord); } } public override void Register(ContainerBuilder builder) { - builder.RegisterType().As(); + builder.RegisterType().As(); } - [Test] - public void SendingWithoutSpecifyingQueueUsesDefaultQueue() { - var manager = _container.Resolve(); - var createdMessage = manager.Send("john.doe@live.com", "email", "This is a test subject"); - var defaultQueue = manager.GetDefaultQueue(); - Assert.That(createdMessage.Queue.Id, Is.EqualTo(defaultQueue.Id)); - } - - [Test] - public void SendingWithoutExistingPrioritiesCreatesDefaultPriorities() { - var manager = _container.Resolve(); - var createdMessage = manager.Send("john.doe@live.com", "email", "This is a test subject"); - var low = manager.GetPriority("Low"); - var normal = manager.GetPriority("Normal"); - var high = manager.GetPriority("High"); - Assert.That(low, Is.Not.Null); - Assert.That(normal, Is.Not.Null); - Assert.That(high, Is.Not.Null); - } - - [Test] - public void SendingWithoutExplicitPriorityUsesDefaultPriority() { - var manager = _container.Resolve(); - var createdMessage = manager.Send("john.doe@live.com", "email", "This is a test subject"); - var defaultPriority = manager.GetDefaultPriority(); - Assert.That(createdMessage.Priority.Id, Is.EqualTo(defaultPriority.Id)); - } - - [Test] - public void DefaultPriorityIsLowestPriority() { - var manager = _container.Resolve(); - var priorities = manager.CreateDefaultPriorities().ToList(); - var expectedPriority = priorities.OrderByDescending(x => x.Value).First(); - var actualPriority = manager.GetDefaultPriority(); - Assert.That(expectedPriority.Id, Is.EqualTo(actualPriority.Id)); - } } } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Messaging/Tests/StubMessageChannel.cs b/src/Orchard.Web/Modules/Orchard.Messaging/Tests/StubMessageChannel.cs index 7df665fcb..b9185f9c8 100644 --- a/src/Orchard.Web/Modules/Orchard.Messaging/Tests/StubMessageChannel.cs +++ b/src/Orchard.Web/Modules/Orchard.Messaging/Tests/StubMessageChannel.cs @@ -1,5 +1,4 @@ using System; -using Orchard.Messaging.Models; using Orchard.Messaging.Services; using Orchard.Tests.Stubs; @@ -17,9 +16,7 @@ namespace Orchard.Messaging.Tests { public void Dispose() { } - public string Name { get { return ChannelName; } } - - public void Send(QueuedMessage message) { + public void Process(string payload) { _clock.Advance(_simulatedProcessingTime); } } diff --git a/src/Orchard.Web/Modules/Orchard.Messaging/ViewModels/MessagePriorityViewModel.cs b/src/Orchard.Web/Modules/Orchard.Messaging/ViewModels/MessagePriorityViewModel.cs deleted file mode 100644 index d809cc74b..000000000 --- a/src/Orchard.Web/Modules/Orchard.Messaging/ViewModels/MessagePriorityViewModel.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System.ComponentModel.DataAnnotations; - -namespace Orchard.Messaging.ViewModels { - public class MessagePriorityViewModel { - public int Id { get; set; } - - [Required] - public string Name { get; set; } - - [Required] - public string DisplayText { get; set; } - public int Value { get; set; } - } -} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Messaging/ViewModels/MessageQueueViewModel.cs b/src/Orchard.Web/Modules/Orchard.Messaging/ViewModels/MessageQueueViewModel.cs deleted file mode 100644 index 6ee8b7182..000000000 --- a/src/Orchard.Web/Modules/Orchard.Messaging/ViewModels/MessageQueueViewModel.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System.ComponentModel.DataAnnotations; - -namespace Orchard.Messaging.ViewModels { - public class MessageQueueViewModel { - public int Id { get; set; } - - [Required] - public string Name { get; set; } - - public string ReturnUrl { get; set; } - } -} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Messaging/ViewModels/MessageSettingsPartViewModel.cs b/src/Orchard.Web/Modules/Orchard.Messaging/ViewModels/MessageSettingsPartViewModel.cs index 09e432e4d..d654a238a 100644 --- a/src/Orchard.Web/Modules/Orchard.Messaging/ViewModels/MessageSettingsPartViewModel.cs +++ b/src/Orchard.Web/Modules/Orchard.Messaging/ViewModels/MessageSettingsPartViewModel.cs @@ -1,9 +1,7 @@ -using System.Collections.Generic; -using Orchard.Messaging.Models; +using Orchard.Messaging.Models; namespace Orchard.Messaging.ViewModels { public class MessageSettingsPartViewModel { public MessageSettingsPart MessageSettings { get; set; } - public IEnumerable ChannelServices { get; set; } } } diff --git a/src/Orchard.Web/Modules/Orchard.Messaging/Views/Activity-SendMessage.cshtml b/src/Orchard.Web/Modules/Orchard.Messaging/Views/Activity-SendMessage.cshtml deleted file mode 100644 index c19c22d39..000000000 --- a/src/Orchard.Web/Modules/Orchard.Messaging/Views/Activity-SendMessage.cshtml +++ /dev/null @@ -1,4 +0,0 @@ -
-
-
- diff --git a/src/Orchard.Web/Modules/Orchard.Messaging/Views/AdminMessage/Details.cshtml b/src/Orchard.Web/Modules/Orchard.Messaging/Views/Admin/Details.cshtml similarity index 76% rename from src/Orchard.Web/Modules/Orchard.Messaging/Views/AdminMessage/Details.cshtml rename to src/Orchard.Web/Modules/Orchard.Messaging/Views/Admin/Details.cshtml index 17705b1e1..9951ec7c8 100644 --- a/src/Orchard.Web/Modules/Orchard.Messaging/Views/AdminMessage/Details.cshtml +++ b/src/Orchard.Web/Modules/Orchard.Messaging/Views/Admin/Details.cshtml @@ -3,7 +3,7 @@ @{ Style.Include("admin-messaging.css", "admin-messaging.min.css"); Layout.Title = T("Message Details"); - var message = (QueuedMessage)Model.Message; + var message = (QueuedMessageRecord)Model.Message; var returnUrl = (string)Model.ReturnUrl; }
@@ -22,25 +22,17 @@ @message.Priority -
  • - - @String.Join(", ", message.Recipients) -
  • @message.CreatedUtc
  • -
  • - - @message.StartedUtc -
  • @message.CompletedUtc
  • - @message.Record.Payload + @message.Payload
  • diff --git a/src/Orchard.Web/Modules/Orchard.Messaging/Views/AdminQueue/List.cshtml b/src/Orchard.Web/Modules/Orchard.Messaging/Views/Admin/List.cshtml similarity index 61% rename from src/Orchard.Web/Modules/Orchard.Messaging/Views/AdminQueue/List.cshtml rename to src/Orchard.Web/Modules/Orchard.Messaging/Views/Admin/List.cshtml index 129b7531a..e1c70af4e 100644 --- a/src/Orchard.Web/Modules/Orchard.Messaging/Views/AdminQueue/List.cshtml +++ b/src/Orchard.Web/Modules/Orchard.Messaging/Views/Admin/List.cshtml @@ -1,17 +1,19 @@ -@using Orchard.Messaging.Models +@using Orchard.Localization +@using Orchard.Messaging.Models @using Orchard.Messaging.ViewModels @using Orchard.Utility.Extensions @{ - var queue = (MessageQueue) Model.Queue; - var messages = (IEnumerable) Model.Messages; - var filter = (MessagesFilter) Model.Filter; + IEnumerable messages = Model.Messages; + MessagesFilter filter = Model.Filter; + MessageQueueStatus status = Model.MessageQueueStatus; + Layout.Title = T("Message Queue"); Style.Include("admin-messaging.css", "admin-messaging.min.css"); } @using (Html.BeginFormAntiForgeryPost()) {
    - @T("Status: {0}", queue.Status) - @if (queue.Status == MessageQueueStatus.Paused) { + @T("Status: {0}", status) + @if (status == MessageQueueStatus.Paused) { } else { @@ -44,26 +46,37 @@ else { @T("Status") @T("Priority") - @T("Recipients") - @T("Payload") + @T("Type") @T("Created") - @T("Started") @T("Completed") @T("Actions") @foreach (var message in messages) { + LocalizedString priorityName; + switch (message.Priority) { + case -50: + priorityName = T("Low"); + break; + case 0: + priorityName = T("Normal"); + break; + case 50: + priorityName = T("High"); + break; + default: + priorityName = T("None"); + break; + } @message.Status - @message.Priority.Name - @String.Join(", ", message.Recipients).Ellipsize(50) - @message.Record.Payload.Ellipsize(100, "...") - @message.CreatedUtc - @message.StartedUtc - @message.CompletedUtc + @priorityName + @message.Type + @Display.DateTimeRelative(dateTimeUtc: message.CreatedUtc) + @Display.DateTimeRelative(dateTimeUtc: message.CompletedUtc) - @T("Details") + @T("Details") } diff --git a/src/Orchard.Web/Modules/Orchard.Messaging/Views/AdminPriority/Create.cshtml b/src/Orchard.Web/Modules/Orchard.Messaging/Views/AdminPriority/Create.cshtml deleted file mode 100644 index 40e21a3d8..000000000 --- a/src/Orchard.Web/Modules/Orchard.Messaging/Views/AdminPriority/Create.cshtml +++ /dev/null @@ -1,10 +0,0 @@ -@model Orchard.Messaging.ViewModels.MessagePriorityViewModel -@{ - Layout.Title = T("Create Priority"); -} -@Html.ValidationSummary() -@using (Html.BeginFormAntiForgeryPost()) { - @Html.EditorForModel() - - @T("Cancel") -} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Messaging/Views/AdminPriority/Edit.cshtml b/src/Orchard.Web/Modules/Orchard.Messaging/Views/AdminPriority/Edit.cshtml deleted file mode 100644 index b69bc7bdf..000000000 --- a/src/Orchard.Web/Modules/Orchard.Messaging/Views/AdminPriority/Edit.cshtml +++ /dev/null @@ -1,9 +0,0 @@ -@model Orchard.Messaging.ViewModels.MessagePriorityViewModel -@{ - Layout.Title = T("Edit Priority"); -} -@using (Html.BeginFormAntiForgeryPost()) { - @Html.EditorForModel() - - @T("Back") -} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Messaging/Views/AdminPriority/Index.cshtml b/src/Orchard.Web/Modules/Orchard.Messaging/Views/AdminPriority/Index.cshtml deleted file mode 100644 index ab0c79c91..000000000 --- a/src/Orchard.Web/Modules/Orchard.Messaging/Views/AdminPriority/Index.cshtml +++ /dev/null @@ -1,40 +0,0 @@ -@{ - var priorities = (IEnumerable)Model.Priorities; - Script.Require("jQuery").AtFoot(); - Script.Include("submit.js", "submit.min.js").AtFoot(); - Style.Include("admin-messaging.css", "admin-messaging.min.css"); - Layout.Title = T("Manage Priorities"); -} -
    - @Html.ActionLink(T("Create Priority").ToString(), "Create", new { Area = "Orchard.Messaging" }, new { @class = "button primaryAction" }) -
    -@if (!priorities.Any()) { -
    @T("There are no priorities. Create a new Priority.", Url.Action("Create", "AdminPriority"))
    -} -else { - using (Html.BeginFormAntiForgeryPost()) { - - - - - - - - - - - @foreach (var priority in priorities) { - - - - - - - } - -
    @T("Name")@T("Display Text")@T("Value")
    @priority.Name@priority.DisplayText@priority.Value - @T("Edit")@T(" | ") - @T("Delete") -
    - } -} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Messaging/Views/AdminQueue/Create.cshtml b/src/Orchard.Web/Modules/Orchard.Messaging/Views/AdminQueue/Create.cshtml deleted file mode 100644 index 9a39832e2..000000000 --- a/src/Orchard.Web/Modules/Orchard.Messaging/Views/AdminQueue/Create.cshtml +++ /dev/null @@ -1,9 +0,0 @@ -@model Orchard.Messaging.ViewModels.MessageQueueViewModel -@{ - Layout.Title = T("Create Queue"); -} -@using (Html.BeginFormAntiForgeryPost()) { - @Html.EditorForModel() - - @T("Cancel") -} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Messaging/Views/AdminQueue/Edit.cshtml b/src/Orchard.Web/Modules/Orchard.Messaging/Views/AdminQueue/Edit.cshtml deleted file mode 100644 index 4672f0ce4..000000000 --- a/src/Orchard.Web/Modules/Orchard.Messaging/Views/AdminQueue/Edit.cshtml +++ /dev/null @@ -1,10 +0,0 @@ -@model Orchard.Messaging.ViewModels.MessageQueueViewModel -@{ - Layout.Title = T("Edit Queue"); - var backUrl = !String.IsNullOrWhiteSpace(Model.ReturnUrl) ? Model.ReturnUrl : Url.Action("Index"); -} -@using (Html.BeginFormAntiForgeryPost()) { - @Html.EditorForModel() - - @T("Back") -} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Messaging/Views/AdminQueue/Index.cshtml b/src/Orchard.Web/Modules/Orchard.Messaging/Views/AdminQueue/Index.cshtml deleted file mode 100644 index 15f0b7d48..000000000 --- a/src/Orchard.Web/Modules/Orchard.Messaging/Views/AdminQueue/Index.cshtml +++ /dev/null @@ -1,62 +0,0 @@ -@using Orchard.Messaging.Models -@using Orchard.Utility.Extensions -@{ - var queues = (IEnumerable) Model.Queues; - Script.Require("jQuery").AtFoot(); - Script.Include("submit.js", "submit.min.js").AtFoot(); - Style.Include("admin-messaging.css", "admin-messaging.min.css"); - Layout.Title = T("Manage Queues"); -} -
    - @Html.ActionLink(T("Create Queue").ToString(), "Create", new { Area = "Orchard.Messaging" }, new { @class = "button primaryAction" }) -
    -@if (!queues.Any()) { -
    @T("There are no queues. Create a new Queue.", Url.Action("Create", "AdminQueue"))
    -} -else { - - - - - - - - - - - - - - - - - @foreach (var queue in queues) { - - - - - - - - - - - - - } - -
    @T("Name")@T("Status")@T("Time Slice")@T("Update Interval")@T("Pending")@T("Sent")@T("Faulted")@T("Last Run")@T("Next Run")
    @queue.Name@queue.Status@queue.TimeSlice@queue.UpdateFrequency@queue.Pending@queue.Sent@queue.Faulted@queue.EndedUtc@queue.NextRun -
      -
    • - @if (queue.Status == MessageQueueStatus.Paused) { - using (Html.BeginFormAntiForgeryPost(Url.Action("Resume", new { id = queue.Id }))) { @T("Resume") } - } - @if (queue.Status == MessageQueueStatus.Idle || queue.Status == MessageQueueStatus.Processing) { - using (Html.BeginFormAntiForgeryPost(Url.Action("Pause", new { id = queue.Id }))) { @T("Pause") } - } -
    • -
    •  | @T("Properties")
    • -
    -
    -
    -} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Messaging/Views/EditorTemplates/MessagePriorityViewModel.cshtml b/src/Orchard.Web/Modules/Orchard.Messaging/Views/EditorTemplates/MessagePriorityViewModel.cshtml deleted file mode 100644 index c2e966f12..000000000 --- a/src/Orchard.Web/Modules/Orchard.Messaging/Views/EditorTemplates/MessagePriorityViewModel.cshtml +++ /dev/null @@ -1,17 +0,0 @@ -@model Orchard.Messaging.ViewModels.MessagePriorityViewModel -
    -
    - @Html.HiddenFor(m => m.Id) - @Html.LabelFor(m => m.Name) - @Html.TextBoxFor(m => m.Name, new { @class = "text medium" }) -
    -
    - @Html.LabelFor(m => m.DisplayText) - @Html.TextBoxFor(m => m.DisplayText, new { @class = "text medium" }) -
    -
    - @Html.LabelFor(m => m.Value) - @Html.TextBoxFor(m => m.Value, new { @class = "text small" }) - @T("The higher the value, the higher the priority.") -
    -
    \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Messaging/Views/EditorTemplates/Parts/MessageSettings.cshtml b/src/Orchard.Web/Modules/Orchard.Messaging/Views/EditorTemplates/Parts/MessageSettings.cshtml index e645797a6..fa92146c9 100644 --- a/src/Orchard.Web/Modules/Orchard.Messaging/Views/EditorTemplates/Parts/MessageSettings.cshtml +++ b/src/Orchard.Web/Modules/Orchard.Messaging/Views/EditorTemplates/Parts/MessageSettings.cshtml @@ -1,21 +1,9 @@ @model MessageSettingsPartViewModel -@using Orchard.Messaging.Models; @using Orchard.Messaging.ViewModels; -
    - @T("Messaging") -
    - - @if ( Model.ChannelServices.Any() ) { - - } - else { - @T("You must enable a messaging channel (e.g., Orchard.Email) before being able to send messages.") - } - - -
    -
    \ No newline at end of file +@* +
    + @T("Messaging") +
    +
    +
    +*@ \ 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 index 9adfdf6c4..f9a4526d6 100644 --- a/src/Orchard.Web/Modules/Orchard.Users/Drivers/UserPartDriver.cs +++ b/src/Orchard.Web/Modules/Orchard.Users/Drivers/UserPartDriver.cs @@ -11,29 +11,29 @@ namespace Orchard.Users.Drivers { public class UserPartDriver : ContentPartDriver { protected override void Importing(UserPart part, ContentManagement.Handlers.ImportContentContext context) { - part.Record.Email = context.Attribute(part.PartDefinition.Name, "Email"); - part.Record.EmailChallengeToken = context.Attribute(part.PartDefinition.Name, "EmailChallengeToken"); - part.Record.EmailStatus = (UserStatus)Enum.Parse(typeof(UserStatus), context.Attribute(part.PartDefinition.Name, "EmailStatus")); - part.Record.HashAlgorithm = context.Attribute(part.PartDefinition.Name, "HashAlgorithm"); - part.Record.NormalizedUserName = context.Attribute(part.PartDefinition.Name, "NormalizedUserName"); - part.Record.Password = context.Attribute(part.PartDefinition.Name, "Password"); - part.Record.PasswordFormat = (MembershipPasswordFormat)Enum.Parse(typeof(MembershipPasswordFormat), context.Attribute(part.PartDefinition.Name, "PasswordFormat")); - part.Record.PasswordSalt = context.Attribute(part.PartDefinition.Name, "PasswordSalt"); - part.Record.RegistrationStatus = (UserStatus)Enum.Parse(typeof(UserStatus), context.Attribute(part.PartDefinition.Name, "RegistrationStatus")); - part.Record.UserName = context.Attribute(part.PartDefinition.Name, "UserName"); + part.Email = context.Attribute(part.PartDefinition.Name, "Email"); + part.EmailChallengeToken = context.Attribute(part.PartDefinition.Name, "EmailChallengeToken"); + part.EmailStatus = (UserStatus)Enum.Parse(typeof(UserStatus), context.Attribute(part.PartDefinition.Name, "EmailStatus")); + part.HashAlgorithm = context.Attribute(part.PartDefinition.Name, "HashAlgorithm"); + part.NormalizedUserName = context.Attribute(part.PartDefinition.Name, "NormalizedUserName"); + part.Password = context.Attribute(part.PartDefinition.Name, "Password"); + part.PasswordFormat = (MembershipPasswordFormat)Enum.Parse(typeof(MembershipPasswordFormat), context.Attribute(part.PartDefinition.Name, "PasswordFormat")); + part.PasswordSalt = context.Attribute(part.PartDefinition.Name, "PasswordSalt"); + part.RegistrationStatus = (UserStatus)Enum.Parse(typeof(UserStatus), context.Attribute(part.PartDefinition.Name, "RegistrationStatus")); + part.UserName = context.Attribute(part.PartDefinition.Name, "UserName"); } protected override void Exporting(UserPart part, ContentManagement.Handlers.ExportContentContext context) { - context.Element(part.PartDefinition.Name).SetAttributeValue("Email", part.Record.Email); - context.Element(part.PartDefinition.Name).SetAttributeValue("EmailChallengeToken", part.Record.EmailChallengeToken); - context.Element(part.PartDefinition.Name).SetAttributeValue("EmailStatus", part.Record.EmailStatus); - context.Element(part.PartDefinition.Name).SetAttributeValue("HashAlgorithm", part.Record.HashAlgorithm); - context.Element(part.PartDefinition.Name).SetAttributeValue("NormalizedUserName", part.Record.NormalizedUserName); - context.Element(part.PartDefinition.Name).SetAttributeValue("Password", part.Record.Password); - context.Element(part.PartDefinition.Name).SetAttributeValue("PasswordFormat", part.Record.PasswordFormat); - context.Element(part.PartDefinition.Name).SetAttributeValue("PasswordSalt", part.Record.PasswordSalt); - context.Element(part.PartDefinition.Name).SetAttributeValue("RegistrationStatus", part.Record.RegistrationStatus); - context.Element(part.PartDefinition.Name).SetAttributeValue("UserName", part.Record.UserName); + context.Element(part.PartDefinition.Name).SetAttributeValue("Email", part.Email); + context.Element(part.PartDefinition.Name).SetAttributeValue("EmailChallengeToken", part.EmailChallengeToken); + context.Element(part.PartDefinition.Name).SetAttributeValue("EmailStatus", part.EmailStatus); + context.Element(part.PartDefinition.Name).SetAttributeValue("HashAlgorithm", part.HashAlgorithm); + context.Element(part.PartDefinition.Name).SetAttributeValue("NormalizedUserName", part.NormalizedUserName); + context.Element(part.PartDefinition.Name).SetAttributeValue("Password", part.Password); + context.Element(part.PartDefinition.Name).SetAttributeValue("PasswordFormat", part.PasswordFormat); + context.Element(part.PartDefinition.Name).SetAttributeValue("PasswordSalt", part.PasswordSalt); + context.Element(part.PartDefinition.Name).SetAttributeValue("RegistrationStatus", part.RegistrationStatus); + context.Element(part.PartDefinition.Name).SetAttributeValue("UserName", part.UserName); } } } \ 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 ab8e4e289..f3ab94fb4 100644 --- a/src/Orchard.Web/Modules/Orchard.Users/Models/UserPart.cs +++ b/src/Orchard.Web/Modules/Orchard.Users/Models/UserPart.cs @@ -1,4 +1,5 @@ -using Orchard.ContentManagement; +using System.Web.Security; +using Orchard.ContentManagement; using Orchard.Security; namespace Orchard.Users.Models { @@ -12,6 +13,31 @@ namespace Orchard.Users.Models { set { Store(x => x.UserName, value); } } + public string EmailChallengeToken { + get { return Retrieve(x => x.EmailChallengeToken); } + set { Store(x => x.EmailChallengeToken, value); } + } + + public string HashAlgorithm { + get { return Retrieve(x => x.HashAlgorithm); } + set { Store(x => x.HashAlgorithm, value); } + } + + public string Password { + get { return Retrieve(x => x.Password); } + set { Store(x => x.Password, value); } + } + + public MembershipPasswordFormat PasswordFormat { + get { return Retrieve(x => x.PasswordFormat); } + set { Store(x => x.PasswordFormat, value); } + } + + public string PasswordSalt { + get { return Retrieve(x => x.PasswordSalt); } + set { Store(x => x.PasswordSalt, value); } + } + public string Email { get { return Retrieve(x => x.Email); } set { Store(x => x.Email, value); } diff --git a/src/Orchard.Web/Modules/Orchard.Users/ViewModels/UserEditViewModel.cs b/src/Orchard.Web/Modules/Orchard.Users/ViewModels/UserEditViewModel.cs index 991ad0cee..99d0b2773 100644 --- a/src/Orchard.Web/Modules/Orchard.Users/ViewModels/UserEditViewModel.cs +++ b/src/Orchard.Web/Modules/Orchard.Users/ViewModels/UserEditViewModel.cs @@ -6,14 +6,14 @@ namespace Orchard.Users.ViewModels { public class UserEditViewModel { [Required] public string UserName { - get { return User.As().Record.UserName; } - set { User.As().Record.UserName = value; } + get { return User.As().UserName; } + set { User.As().UserName = value; } } [Required] public string Email { - get { return User.As().Record.Email; } - set { User.As().Record.Email = value; } + get { return User.As().Email; } + set { User.As().Email = value; } } public IContent User { get; set; } diff --git a/src/Orchard.Web/Modules/Upgrade/AdminMenu.cs b/src/Orchard.Web/Modules/Upgrade/AdminMenu.cs index 42b01722c..bc56e87e4 100644 --- a/src/Orchard.Web/Modules/Upgrade/AdminMenu.cs +++ b/src/Orchard.Web/Modules/Upgrade/AdminMenu.cs @@ -14,7 +14,8 @@ namespace Upgrade { builder .AddImageSet("upgrade") .Add(T("Upgrade to 1.8"), "0", menu => menu.Action("Index", "Route", new { area = "Upgrade" }) - .Add(T("Infoset (1.8)"), "1", item => item.Action("Index", "Infoset", new { area = "Upgrade" }).LocalNav().Permission(StandardPermissions.SiteOwner)) + .Add(T("Infoset (1.8)"), "1.0", item => item.Action("Index", "Infoset", new { area = "Upgrade" }).LocalNav().Permission(StandardPermissions.SiteOwner)) + .Add(T("Messaging (1.8)"), "1.1", item => item.Action("Index", "Messaging", new { area = "Upgrade" }).LocalNav().Permission(StandardPermissions.SiteOwner)) .Add(T("Media (1.7)"), "2", item => item.Action("Index", "Media", new { area = "Upgrade" }).LocalNav().Permission(StandardPermissions.SiteOwner)) .Add(T("Taxonomies (1.7)"), "3", item => item.Action("Index", "Taxonomy", new { area = "Upgrade" }).LocalNav().Permission(StandardPermissions.SiteOwner)) .Add(T("Content Picker (1.7)"), "4", item => item.Action("Index", "ContentPicker", new { area = "Upgrade" }).LocalNav().Permission(StandardPermissions.SiteOwner)) diff --git a/src/Orchard.Web/Modules/Upgrade/Controllers/InfosetController.cs b/src/Orchard.Web/Modules/Upgrade/Controllers/InfosetController.cs index 9bbeee587..8ec4fd371 100644 --- a/src/Orchard.Web/Modules/Upgrade/Controllers/InfosetController.cs +++ b/src/Orchard.Web/Modules/Upgrade/Controllers/InfosetController.cs @@ -211,6 +211,8 @@ namespace Upgrade.Controllers { _upgradeService.ExecuteReader("DROP TABLE " + _upgradeService.GetPrefixedTableName("Orchard_Warmup_WarmupSettingsPartRecord"), null); #endregion + // todo: user records + _orchardServices.Notifier.Information(T("Site Settings migrated successfully")); return View(); diff --git a/src/Orchard.Web/Modules/Upgrade/Controllers/MessagingController.cs b/src/Orchard.Web/Modules/Upgrade/Controllers/MessagingController.cs new file mode 100644 index 000000000..23bbb90a8 --- /dev/null +++ b/src/Orchard.Web/Modules/Upgrade/Controllers/MessagingController.cs @@ -0,0 +1,99 @@ +using System.Web.Mvc; +using Newtonsoft.Json; +using Orchard; +using Orchard.Data; +using Orchard.Email.Models; +using Orchard.Localization; +using Orchard.Security; +using Orchard.UI.Admin; +using Orchard.UI.Notify; +using Orchard.Workflows.Models; +using Upgrade.Services; + +namespace Upgrade.Controllers { + [Admin] + public class MessagingController : Controller { + private readonly IUpgradeService _upgradeService; + private readonly IOrchardServices _orchardServices; + private readonly IRepository _repository; + + public MessagingController( + IUpgradeService upgradeService, + IOrchardServices orchardServices, + IRepository repository) { + _upgradeService = upgradeService; + _orchardServices = orchardServices; + _repository = repository; + } + + public Localizer T { get; set; } + + public ActionResult Index() { + var found = false; + _upgradeService.ExecuteReader("SELECT * FROM " + _upgradeService.GetPrefixedTableName("Orchard_Workflows_ActivityRecord") + " WHERE Name = 'SendEmail'", + (reader, connection) => { + found = true; + }); + + if (!found) { + _orchardServices.Notifier.Warning(T("This step is unnecessary as no Send Email activities were found.")); + } + + return View(); + } + + [HttpPost, ActionName("Index")] + public ActionResult IndexPOST() { + if (!_orchardServices.Authorizer.Authorize(StandardPermissions.SiteOwner, T("Not allowed to upgrade."))) + return new HttpUnauthorizedResult(); + + _upgradeService.ExecuteReader("SELECT * FROM " + _upgradeService.GetPrefixedTableName("Orchard_Workflows_ActivityRecord") + " WHERE Name = 'SendEmail'", + (reader, connection) => { + var record = _repository.Get((int) reader["Id"]); + + if (record == null) { + return; + } + + var state = JsonConvert.DeserializeAnonymousType(record.State, new { + Body = "", + Subject = "", + Recipient = "", + RecipientOther = "", + }); + + var newState = new EmailMessage { + Body = state.Body, + Subject = state.Subject + }; + + if (!newState.Body.StartsWith("

    " + + newState.Body + + System.Environment.NewLine + + "

    "; + } + + if (state.Recipient == "owner") { + newState.Recipients = new [] {"{User.Current.Email}"}; + } + else if (state.Recipient == "author") { + newState.Recipients = new[] { "{Content.Author.Email}" }; + } + else if (state.Recipient == "admin") { + newState.Recipients = new[] { "{Site.SuperUser.Email}" }; + } + else if (state.Recipient == "other") { + newState.Recipients = state.RecipientOther.Split(','); + } + + record.State = JsonConvert.SerializeObject(newState); + }); + + _orchardServices.Notifier.Information(T("Email activities updated successfully")); + + return RedirectToAction("Index"); + } + } +} diff --git a/src/Orchard.Web/Modules/Upgrade/Upgrade.csproj b/src/Orchard.Web/Modules/Upgrade/Upgrade.csproj index bc059af91..224d25f89 100644 --- a/src/Orchard.Web/Modules/Upgrade/Upgrade.csproj +++ b/src/Orchard.Web/Modules/Upgrade/Upgrade.csproj @@ -44,6 +44,10 @@ + + False + ..\..\..\..\lib\newtonsoft.json\Newtonsoft.Json.dll + False ..\..\..\..\lib\nhibernate\NHibernate.dll @@ -74,6 +78,7 @@ + @@ -96,6 +101,10 @@ {66FCCD76-2761-47E3-8D11-B45D0001DDAA} Orchard.Autoroute + + {05660F47-D649-48BD-9DED-DF4E01E7CFF9} + Orchard.Email + {73a7688a-5bd3-4f7e-adfa-ce36c5a10e3b} Orchard.MediaLibrary @@ -104,6 +113,10 @@ {194D3CCC-1153-474D-8176-FDE8D7D0D0BD} Orchard.Widgets + + {7059493c-8251-4764-9c1e-2368b8b485bc} + Orchard.Workflows + @@ -136,6 +149,9 @@ + + + 10.0 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) diff --git a/src/Orchard.Web/Modules/Upgrade/Views/Messaging/Index.cshtml b/src/Orchard.Web/Modules/Upgrade/Views/Messaging/Index.cshtml new file mode 100644 index 000000000..ae19b05af --- /dev/null +++ b/src/Orchard.Web/Modules/Upgrade/Views/Messaging/Index.cshtml @@ -0,0 +1,14 @@ +@using Orchard.Utility.Extensions + +@{ Layout.Title = T("Migrate Messaging").ToString(); } + +@using (Html.BeginFormAntiForgeryPost()) { + Html.ValidationSummary(); +
    + @T("Migrating Email Activities:") + @T("This migration step will update the existing Send Email activities to use the new Message Queueing functionality.") +
    +
    + +
    +} \ No newline at end of file diff --git a/src/Orchard/Messaging/Events/IMessageEventHandler.cs b/src/Orchard/Messaging/Events/IMessageEventHandler.cs index 73ab95b6e..73ec26799 100644 --- a/src/Orchard/Messaging/Events/IMessageEventHandler.cs +++ b/src/Orchard/Messaging/Events/IMessageEventHandler.cs @@ -1,7 +1,9 @@ -using Orchard.Events; +using System; +using Orchard.Events; using Orchard.Messaging.Models; namespace Orchard.Messaging.Events { + [Obsolete] 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 index cef0284a5..8f79b821e 100644 --- a/src/Orchard/Messaging/Models/MessageContext.cs +++ b/src/Orchard/Messaging/Models/MessageContext.cs @@ -5,6 +5,7 @@ using System.Net.Mail; using Orchard.ContentManagement.Records; namespace Orchard.Messaging.Models { + [Obsolete] public class MessageContext { public MailMessage MailMessage { get; private set; } public string Type { get; set; } diff --git a/src/Orchard/Messaging/Services/DefaultMessageManager.cs b/src/Orchard/Messaging/Services/DefaultMessageManager.cs index f329a3201..8e2911857 100644 --- a/src/Orchard/Messaging/Services/DefaultMessageManager.cs +++ b/src/Orchard/Messaging/Services/DefaultMessageManager.cs @@ -7,6 +7,7 @@ using Orchard.Messaging.Models; using Orchard.ContentManagement.Records; namespace Orchard.Messaging.Services { + [Obsolete] public class DefaultMessageManager : IMessageManager { private readonly IMessageEventHandler _messageEventHandler; private readonly IEnumerable _channels; diff --git a/src/Orchard/Messaging/Services/IMessageManager.cs b/src/Orchard/Messaging/Services/IMessageManager.cs index a3b790d73..acbec9f20 100644 --- a/src/Orchard/Messaging/Services/IMessageManager.cs +++ b/src/Orchard/Messaging/Services/IMessageManager.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using Orchard.ContentManagement.Records; namespace Orchard.Messaging.Services { + [Obsolete] public interface IMessageManager : IDependency { /// /// Sends a message to a channel using a content item as the recipient diff --git a/src/Orchard/Messaging/Services/IMessagingChannel.cs b/src/Orchard/Messaging/Services/IMessagingChannel.cs index 0834679a3..7b3609f93 100644 --- a/src/Orchard/Messaging/Services/IMessagingChannel.cs +++ b/src/Orchard/Messaging/Services/IMessagingChannel.cs @@ -3,7 +3,7 @@ using System.Collections.Generic; using Orchard.Messaging.Models; namespace Orchard.Messaging.Services { - [Obsolete("Use the new IMessageChannel interface instead.")] + [Obsolete] public interface IMessagingChannel : IDependency { /// /// Actually sends the message though this channel