From b532569eb4817ba70ba716233f87360bd6c43939 Mon Sep 17 00:00:00 2001 From: Nathan Heskew Date: Thu, 25 Nov 2010 22:04:12 -0800 Subject: [PATCH 1/4] Unblocking the use of Html.RenderAction and Html.Action in Orchard views --HG-- branch : dev --- src/Orchard/Mvc/Html/ContainerExtensions.cs | 7 +--- src/Orchard/WorkContextExtensions.cs | 41 ++++++++++++++++----- 2 files changed, 33 insertions(+), 15 deletions(-) diff --git a/src/Orchard/Mvc/Html/ContainerExtensions.cs b/src/Orchard/Mvc/Html/ContainerExtensions.cs index 0e104904d..035947e99 100644 --- a/src/Orchard/Mvc/Html/ContainerExtensions.cs +++ b/src/Orchard/Mvc/Html/ContainerExtensions.cs @@ -9,13 +9,10 @@ namespace Orchard.Mvc.Html { /// /// himself public static TService Resolve(this HtmlHelper html) { - var workContextAccessor = html.ViewContext.RouteData.DataTokens["IWorkContextAccessor"] as IWorkContextAccessor; - if (workContextAccessor == null) - throw new ApplicationException("Unable to resolve"); + var workContext = html.ViewContext.RequestContext.GetWorkContext(); - var workContext = workContextAccessor.GetContext(html.ViewContext.HttpContext); if (workContext == null) - throw new ApplicationException("Unable to resolve"); + return default(TService); return workContext.Resolve(); } diff --git a/src/Orchard/WorkContextExtensions.cs b/src/Orchard/WorkContextExtensions.cs index 3b4956805..1c1b6d690 100644 --- a/src/Orchard/WorkContextExtensions.cs +++ b/src/Orchard/WorkContextExtensions.cs @@ -10,27 +10,48 @@ namespace Orchard { } public static WorkContext GetWorkContext(this RequestContext requestContext) { - if (requestContext == null) { + if (requestContext == null) return null; - } var routeData = requestContext.RouteData; - object value; - if (routeData == null || - routeData.DataTokens == null || - !routeData.DataTokens.TryGetValue("IWorkContextAccessor", out value) || - !(value is IWorkContextAccessor)) { + if (routeData == null || routeData.DataTokens == null) return null; + + object workContextValue; + if (!routeData.DataTokens.TryGetValue("IWorkContextAccessor", out workContextValue)) { + workContextValue = FindWorkContextInParent(routeData); } - var workContextAccessor = (IWorkContextAccessor)value; + if (!(workContextValue is IWorkContextAccessor)) + return null; + + var workContextAccessor = (IWorkContextAccessor)workContextValue; return workContextAccessor.GetContext(requestContext.HttpContext); } - public static WorkContext GetWorkContext(this ControllerContext controllerContext) { - if (controllerContext == null) { + private static object FindWorkContextInParent(RouteData routeData) { + object parentViewContextValue; + if (!routeData.DataTokens.TryGetValue("ParentActionViewContext", out parentViewContextValue) + || !(parentViewContextValue is ViewContext)) { return null; } + + var parentRouteData = ((ViewContext)parentViewContextValue).RouteData; + if (parentRouteData == null || parentRouteData.DataTokens == null) + return null; + + object workContextValue; + if (!parentRouteData.DataTokens.TryGetValue("IWorkContextAccessor", out workContextValue)) { + workContextValue = FindWorkContextInParent(parentRouteData); + } + + return workContextValue; + } + + public static WorkContext GetWorkContext(this ControllerContext controllerContext) { + if (controllerContext == null) + return null; + return WorkContextExtensions.GetWorkContext(controllerContext.RequestContext); } From 79fbacf0b683772aaa0a9cdc19dcf1318bd6a755 Mon Sep 17 00:00:00 2001 From: Nathan Heskew Date: Thu, 25 Nov 2010 22:10:07 -0800 Subject: [PATCH 2/4] Updating the RoutableHomePageProvider to use the relevant display action for the given content item. This lets unique display actions, like Blog/Item, do their own thing. In the case of the blog, its posts are once again showing up on the home page. The routing problem (where the home page'd item still is seen as having its own path) still needs to be fixed so the item on the home page can't be hit at different URLs (and so something like paging works on the home page) work item: 16720 --HG-- branch : dev --- src/Orchard.Web/Core/Feeds/Services/FeedFilter.cs | 4 ++++ .../Core/Routable/Handlers/RoutePartHandler.cs | 11 +++++++++-- .../Routable/Services/RoutableHomePageProvider.cs | 13 +++++++++---- .../Core/Routable/Views/Routable.HomePage.cshtml | 5 ++++- .../Orchard.Blogs/Handlers/BlogPartHandler.cs | 7 +++++++ src/Orchard/UI/Navigation/MenuFilter.cs | 4 ++++ src/Orchard/UI/Resources/ResourceFilter.cs | 5 ++++- 7 files changed, 41 insertions(+), 8 deletions(-) diff --git a/src/Orchard.Web/Core/Feeds/Services/FeedFilter.cs b/src/Orchard.Web/Core/Feeds/Services/FeedFilter.cs index 5af31c66c..0fc6f9621 100644 --- a/src/Orchard.Web/Core/Feeds/Services/FeedFilter.cs +++ b/src/Orchard.Web/Core/Feeds/Services/FeedFilter.cs @@ -21,6 +21,10 @@ namespace Orchard.Core.Feeds.Services { dynamic Shape { get; set; } public void OnResultExecuting(ResultExecutingContext filterContext) { + // should only run on a full view rendering result + if (!(filterContext.Result is ViewResult)) + return; + var layout = _workContextAccessor.GetContext(filterContext).Layout; var feed = Shape.Feed() .FeedManager(_feedManager); diff --git a/src/Orchard.Web/Core/Routable/Handlers/RoutePartHandler.cs b/src/Orchard.Web/Core/Routable/Handlers/RoutePartHandler.cs index 7e7ba858b..6e70fa72d 100644 --- a/src/Orchard.Web/Core/Routable/Handlers/RoutePartHandler.cs +++ b/src/Orchard.Web/Core/Routable/Handlers/RoutePartHandler.cs @@ -72,8 +72,15 @@ namespace Orchard.Core.Routable.Handlers { public class RoutePartHandlerBase : ContentHandlerBase { public override void GetContentItemMetadata(GetContentItemMetadataContext context) { var routable = context.ContentItem.As(); - if (routable != null) { - context.Metadata.DisplayText = routable.Title; + + if (routable == null) + return; + + context.Metadata.DisplayText = routable.Title; + + // set the display route values if it hasn't been set or only has been set by the Contents module. + // allows other modules to set their own display. probably not common enough to warrant some priority implemntation + if (context.Metadata.DisplayRouteValues == null || context.Metadata.DisplayRouteValues["Area"] as string == "Contents") { context.Metadata.DisplayRouteValues = new RouteValueDictionary { {"Area", "Routable"}, {"Controller", "Item"}, diff --git a/src/Orchard.Web/Core/Routable/Services/RoutableHomePageProvider.cs b/src/Orchard.Web/Core/Routable/Services/RoutableHomePageProvider.cs index 18bd86f49..bf43531b5 100644 --- a/src/Orchard.Web/Core/Routable/Services/RoutableHomePageProvider.cs +++ b/src/Orchard.Web/Core/Routable/Services/RoutableHomePageProvider.cs @@ -10,13 +10,16 @@ namespace Orchard.Core.Routable.Services { [UsedImplicitly] public class RoutableHomePageProvider : IHomePageProvider { private readonly IContentManager _contentManager; + private readonly IWorkContextAccessor _workContextAccessor; public const string Name = "RoutableHomePageProvider"; public RoutableHomePageProvider( IOrchardServices services, IContentManager contentManager, - IShapeFactory shapeFactory) { + IShapeFactory shapeFactory, + IWorkContextAccessor workContextAccessor) { _contentManager = contentManager; + _workContextAccessor = workContextAccessor; Services = services; T = NullLocalizer.Instance; Shape = shapeFactory; @@ -39,11 +42,13 @@ namespace Orchard.Core.Routable.Services { if (contentItem == null || !contentItem.Is()) return new HttpNotFoundResult(); - var model = _contentManager.BuildDisplay(contentItem); + // get the display metadata for the home page item + var displayRouteValues = _contentManager.GetItemMetadata(contentItem).DisplayRouteValues; - return new ViewResult { + var model = Shape.ViewModel(RouteValues: displayRouteValues); + return new PartialViewResult { ViewName = "Routable.HomePage", - ViewData = new ViewDataDictionary(model) + ViewData = new ViewDataDictionary(model) }; } } diff --git a/src/Orchard.Web/Core/Routable/Views/Routable.HomePage.cshtml b/src/Orchard.Web/Core/Routable/Views/Routable.HomePage.cshtml index 631e9eb0f..594797276 100644 --- a/src/Orchard.Web/Core/Routable/Views/Routable.HomePage.cshtml +++ b/src/Orchard.Web/Core/Routable/Views/Routable.HomePage.cshtml @@ -1 +1,4 @@ -@Display(Model) \ No newline at end of file +@{ + RouteValueDictionary routeValues = Model.RouteValues; + Html.RenderAction(routeValues["action"] as string, routeValues["controller"] as string, routeValues); +} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Blogs/Handlers/BlogPartHandler.cs b/src/Orchard.Web/Modules/Orchard.Blogs/Handlers/BlogPartHandler.cs index 23c9b6693..afbb78849 100644 --- a/src/Orchard.Web/Modules/Orchard.Blogs/Handlers/BlogPartHandler.cs +++ b/src/Orchard.Web/Modules/Orchard.Blogs/Handlers/BlogPartHandler.cs @@ -3,6 +3,7 @@ using JetBrains.Annotations; using Orchard.Blogs.Models; using Orchard.ContentManagement; using Orchard.ContentManagement.Handlers; +using Orchard.Core.Routable.Models; using Orchard.Data; namespace Orchard.Blogs.Handlers { @@ -23,6 +24,12 @@ namespace Orchard.Blogs.Handlers { if (blog == null) return; + context.Metadata.DisplayRouteValues = new RouteValueDictionary { + {"Area", "Orchard.Blogs"}, + {"Controller", "Blog"}, + {"Action", "Item"}, + {"blogSlug", blog.As().Slug} + }; context.Metadata.CreateRouteValues = new RouteValueDictionary { {"Area", "Orchard.Blogs"}, {"Controller", "BlogAdmin"}, diff --git a/src/Orchard/UI/Navigation/MenuFilter.cs b/src/Orchard/UI/Navigation/MenuFilter.cs index 6e2a80875..4027305c1 100644 --- a/src/Orchard/UI/Navigation/MenuFilter.cs +++ b/src/Orchard/UI/Navigation/MenuFilter.cs @@ -21,6 +21,10 @@ namespace Orchard.UI.Navigation { } public void OnResultExecuting(ResultExecutingContext filterContext) { + // should only run on a full view rendering result + if (!(filterContext.Result is ViewResult)) + return; + var workContext = _workContextAccessor.GetContext(filterContext); var menuName = "main"; diff --git a/src/Orchard/UI/Resources/ResourceFilter.cs b/src/Orchard/UI/Resources/ResourceFilter.cs index 72148a1b2..990184f1b 100644 --- a/src/Orchard/UI/Resources/ResourceFilter.cs +++ b/src/Orchard/UI/Resources/ResourceFilter.cs @@ -1,4 +1,3 @@ -using System; using System.Web.Mvc; using Orchard.DisplayManagement; using Orchard.Mvc.Filters; @@ -20,6 +19,10 @@ namespace Orchard.UI.Resources { public void OnResultExecuting(ResultExecutingContext filterContext) { + // should only run on a full view rendering result + if (!(filterContext.Result is ViewResult)) + return; + var ctx = _workContextAccessor.GetContext(); var head = ctx.Layout.Head; var tail = ctx.Layout.Tail; From b2eb5e2f668feed206163ebdb8d8c489a568bcf2 Mon Sep 17 00:00:00 2001 From: Nathan Heskew Date: Fri, 26 Nov 2010 14:46:37 -0800 Subject: [PATCH 3/4] Fixing how the default home page is configured during setup --HG-- branch : dev --- .../Modules/Orchard.Setup/Services/SetupService.cs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/Orchard.Web/Modules/Orchard.Setup/Services/SetupService.cs b/src/Orchard.Web/Modules/Orchard.Setup/Services/SetupService.cs index fe5d7a55c..55f72c3dc 100644 --- a/src/Orchard.Web/Modules/Orchard.Setup/Services/SetupService.cs +++ b/src/Orchard.Web/Modules/Orchard.Setup/Services/SetupService.cs @@ -246,13 +246,13 @@ namespace Orchard.Setup.Services { layerInitializer.CreateDefaultLayers(); // add a layer for the homepage - var homepageLayer = contentManager.Create("Layer"); + var homepageLayer = contentManager.Create("Layer", VersionOptions.Draft); homepageLayer.As().Name = "TheHomepage"; homepageLayer.As().LayerRule = "url \"~/\""; contentManager.Publish(homepageLayer); // and three more for the tripel...really need this elsewhere... - var tripelFirst = contentManager.Create("HtmlWidget"); + var tripelFirst = contentManager.Create("HtmlWidget", VersionOptions.Draft); tripelFirst.As().LayerPart = homepageLayer.As(); tripelFirst.As().Title = T("First Leader Aside").Text; tripelFirst.As().Zone = "TripelFirst"; @@ -260,7 +260,7 @@ namespace Orchard.Setup.Services { tripelFirst.As().Text = "

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur a nibh ut tortor dapibus vestibulum. Aliquam vel sem nibh. Suspendisse vel condimentum tellus.

"; contentManager.Publish(tripelFirst); - var tripelSecond = contentManager.Create("HtmlWidget"); + var tripelSecond = contentManager.Create("HtmlWidget", VersionOptions.Draft); tripelSecond.As().LayerPart = homepageLayer.As(); tripelSecond.As().Title = T("Second Leader Aside").Text; tripelSecond.As().Zone = "TripelSecond"; @@ -268,7 +268,7 @@ namespace Orchard.Setup.Services { tripelSecond.As().Text = "

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur a nibh ut tortor dapibus vestibulum. Aliquam vel sem nibh. Suspendisse vel condimentum tellus.

"; contentManager.Publish(tripelSecond); - var tripelThird = contentManager.Create("HtmlWidget"); + var tripelThird = contentManager.Create("HtmlWidget", VersionOptions.Draft); tripelThird.As().LayerPart = homepageLayer.As(); tripelThird.As().Title = T("Third Leader Aside").Text; tripelThird.As().Zone = "TripelThird"; @@ -278,8 +278,10 @@ namespace Orchard.Setup.Services { } // create a welcome page that's promoted to the home page - var page = contentManager.Create("Page"); + var page = contentManager.Create("Page", VersionOptions.Draft); page.As().Title = T("Welcome to Orchard!").Text; + page.As().Path = ""; + page.As().Slug = ""; page.As().Text = string.Format(CultureInfo.CurrentCulture, "

You’ve successfully setup your Orchard Site and this is the homepage of your new site. Here are a few things you can look at to get familiar with the application. Once you feel confident you don’t need this anymore, you can remove this by going into editing mode and replacing it with whatever you want.

First things first - You’ll probably want to manage your settings and configure Orchard to your liking. After that, you can head over to manage themes to change or install new themes and really make it your own. Once you’re happy with a look and feel, it’s time for some content. You can start creating new custom content types or start with some built-in ones by adding a page, creating a blog or managing your menus.

Finally, Orchard has been designed to be extended. It comes with a few built-in modules such as pages and blogs or themes. If you’re looking to add additional functionality, you can do so by creating your own module or installing a new one that someone has made. Modules are created by other users of Orchard just like you so if you feel up to it, please consider participating. XOXO – The Orchard Team

", page.Id); contentManager.Publish(page); From 4631207f51dad7da18ed473529f29377d7da9266 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Ros?= Date: Fri, 26 Nov 2010 17:02:22 -0800 Subject: [PATCH 4/4] Adding UI to change password - new Lost Password link in LogOng view - sends a reset link by mail Work Item: 16341 --HG-- branch : dev --- .../Controllers/AccountController.cs | 83 +++++++------- .../Controllers/AdminController.cs | 4 +- .../Handlers/ModerationMessageAlteration.cs | 7 +- .../Orchard.Users/Models/MessageTypes.cs | 1 + .../Orchard.Users/Orchard.Users.csproj | 3 + .../Orchard.Users/Services/IUserService.cs | 10 ++ .../Services/MembershipService.cs | 53 +-------- .../Orchard.Users/Services/UserService.cs | 101 +++++++++++++++++- .../Views/Account/ChangePassword.cshtml | 5 - .../Orchard.Users/Views/Account/LogOn.cshtml | 8 +- .../Views/Account/LostPassword.cshtml | 15 +++ src/Orchard/Security/IMembershipService.cs | 3 - 12 files changed, 191 insertions(+), 102 deletions(-) create mode 100644 src/Orchard.Web/Modules/Orchard.Users/Views/Account/LostPassword.cshtml diff --git a/src/Orchard.Web/Modules/Orchard.Users/Controllers/AccountController.cs b/src/Orchard.Web/Modules/Orchard.Users/Controllers/AccountController.cs index bfab4c451..4c199a891 100644 --- a/src/Orchard.Web/Modules/Orchard.Users/Controllers/AccountController.cs +++ b/src/Orchard.Web/Modules/Orchard.Users/Controllers/AccountController.cs @@ -12,6 +12,7 @@ using Orchard.Users.Services; using Orchard.Users.ViewModels; using Orchard.ContentManagement; using Orchard.Users.Models; +using Orchard.UI.Notify; namespace Orchard.Users.Controllers { [HandleError, Themed] @@ -119,8 +120,8 @@ namespace Orchard.Users.Controllers { if (user != null) { if ( user.As().EmailStatus == UserStatus.Pending ) { - string challengeToken = _membershipService.GetEncryptedChallengeToken(user.As()); - _membershipService.SendChallengeEmail(user.As(), Url.AbsoluteAction(() => Url.Action("ChallengeEmail", "Account", new { Area = "Orchard.Users", token = challengeToken }))); + string challengeToken = _userService.GetNonce(user.As()); + _userService.SendChallengeEmail(user.As(), Url.AbsoluteAction(() => Url.Action("ChallengeEmail", "Account", new { Area = "Orchard.Users", token = challengeToken }))); return RedirectToAction("ChallengeEmailSent"); } @@ -141,6 +142,36 @@ namespace Orchard.Users.Controllers { return Register(); } + public ActionResult LostPassword() { + return View(); + } + + [HttpPost] + public ActionResult LostPassword(string username) { + + if(String.IsNullOrWhiteSpace(username)){ + _orchardServices.Notifier.Error(T("Invalid username or E-mail")); + return View(); + } + + _userService.SendLostPasswordEmail(username, nonce => Url.AbsoluteAction(() => Url.Action("ValidateLostPassword", "Account", new { Area = "Orchard.Users", nonce = nonce }))); + + _orchardServices.Notifier.Information(T("Check your e-mail for the confirmation link.")); + + return RedirectToAction("LogOn"); + } + + public ActionResult ValidateLostPassword(string nonce) { + IUser user; + if (null != (user = _userService.ValidateLostPassword(nonce))) { + _authenticationService.SignIn(user, false); + return RedirectToAction("ChangePassword"); + } + else { + return new RedirectResult("~/"); + } + } + [Authorize] public ActionResult ChangePassword() { ViewData["PasswordLength"] = MinPasswordLength; @@ -150,32 +181,23 @@ namespace Orchard.Users.Controllers { [Authorize] [HttpPost] - [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", - Justification = "Exceptions result in password not being changed.")] public ActionResult ChangePassword(string currentPassword, string newPassword, string confirmPassword) { ViewData["PasswordLength"] = MinPasswordLength; - if (!ValidateChangePassword(currentPassword, newPassword, confirmPassword)) { + if (newPassword == null || newPassword.Length < MinPasswordLength) { + ModelState.AddModelError("newPassword", T("You must specify a new password of {0} or more characters.", MinPasswordLength)); + } + + if (!String.Equals(newPassword, confirmPassword, StringComparison.Ordinal)) { + ModelState.AddModelError("_FORM", T("The new password and confirmation password do not match.")); + } + + if (!ModelState.IsValid) { return View(); } - try { - var validated = _membershipService.ValidateUser(User.Identity.Name, currentPassword); - - if (validated != null) { - _membershipService.SetPassword(validated, newPassword); - return RedirectToAction("ChangePasswordSuccess"); - } - else { - ModelState.AddModelError("_FORM", - T("The current password is incorrect or the new password is invalid.")); - return ChangePassword(); - } - } - catch { - ModelState.AddModelError("_FORM", T("The current password is incorrect or the new password is invalid.")); - return ChangePassword(); - } + _membershipService.SetPassword(_orchardServices.WorkContext.CurrentUser, newPassword); + return RedirectToAction("ChangePasswordSuccess"); } public ActionResult RegistrationPending() { @@ -199,7 +221,7 @@ namespace Orchard.Users.Controllers { } public ActionResult ChallengeEmail(string token) { - var user = _membershipService.ValidateChallengeToken(token); + var user = _userService.ValidateChallenge(token); if ( user != null ) { _authenticationService.SignIn(user, false /* createPersistentCookie */); @@ -217,21 +239,6 @@ namespace Orchard.Users.Controllers { #region Validation Methods - private bool ValidateChangePassword(string currentPassword, string newPassword, string confirmPassword) { - if (String.IsNullOrEmpty(currentPassword)) { - ModelState.AddModelError("currentPassword", T("You must specify a current password.")); - } - if (newPassword == null || newPassword.Length < MinPasswordLength) { - ModelState.AddModelError("newPassword", T("You must specify a new password of {0} or more characters.", MinPasswordLength)); - } - - if (!String.Equals(newPassword, confirmPassword, StringComparison.Ordinal)) { - ModelState.AddModelError("_FORM", T("The new password and confirmation password do not match.")); - } - - return ModelState.IsValid; - } - private IUser ValidateLogOn(string userNameOrEmail, string password) { bool validate = true; diff --git a/src/Orchard.Web/Modules/Orchard.Users/Controllers/AdminController.cs b/src/Orchard.Web/Modules/Orchard.Users/Controllers/AdminController.cs index 324e41672..96f8d3c05 100644 --- a/src/Orchard.Web/Modules/Orchard.Users/Controllers/AdminController.cs +++ b/src/Orchard.Web/Modules/Orchard.Users/Controllers/AdminController.cs @@ -197,8 +197,8 @@ namespace Orchard.Users.Controllers { var user = Services.ContentManager.Get(id); if ( user != null ) { - string challengeToken = _membershipService.GetEncryptedChallengeToken(user.As()); - _membershipService.SendChallengeEmail(user.As(), Url.AbsoluteAction(() => Url.Action("ChallengeEmail", "Account", new {Area = "Orchard.Users", token = challengeToken}))); + string challengeToken = _userService.GetNonce(user.As()); + _userService.SendChallengeEmail(user.As(), Url.AbsoluteAction(() => Url.Action("ChallengeEmail", "Account", new {Area = "Orchard.Users", token = challengeToken}))); } Services.Notifier.Information(T("Challenge email sent")); diff --git a/src/Orchard.Web/Modules/Orchard.Users/Handlers/ModerationMessageAlteration.cs b/src/Orchard.Web/Modules/Orchard.Users/Handlers/ModerationMessageAlteration.cs index 596a80ca6..932e4eacf 100644 --- a/src/Orchard.Web/Modules/Orchard.Users/Handlers/ModerationMessageAlteration.cs +++ b/src/Orchard.Web/Modules/Orchard.Users/Handlers/ModerationMessageAlteration.cs @@ -29,11 +29,16 @@ namespace Orchard.Users.Handlers { context.MailMessage.Body = T("The following user account needs to be moderated: {0}", recipient.UserName).Text; } - if ( context.Type == MessageTypes.Validation ) { + if (context.Type == MessageTypes.Validation) { context.MailMessage.Subject = T("User account validation").Text; context.MailMessage.Body = T("Dear {0}, please click here to validate you email address.", recipient.UserName, context.Properties["ChallengeUrl"]).Text; } + if (context.Type == MessageTypes.LostPassword) { + context.MailMessage.Subject = T("Lost password").Text; + context.MailMessage.Body = T("Dear {0}, please click here to change your password.", recipient.UserName, context.Properties["LostPasswordUrl"]).Text; + } + } public void Sent(MessageContext context) { diff --git a/src/Orchard.Web/Modules/Orchard.Users/Models/MessageTypes.cs b/src/Orchard.Web/Modules/Orchard.Users/Models/MessageTypes.cs index e63e44887..ee78118ba 100644 --- a/src/Orchard.Web/Modules/Orchard.Users/Models/MessageTypes.cs +++ b/src/Orchard.Web/Modules/Orchard.Users/Models/MessageTypes.cs @@ -7,6 +7,7 @@ namespace Orchard.Users.Models { public static class MessageTypes { public const string Moderation = "ORCHARD_USERS_MODERATION"; public const string Validation = "ORCHARD_USERS_VALIDATION"; + public const string LostPassword = "ORCHARD_USERS_RESETPASSWORD"; } } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Users/Orchard.Users.csproj b/src/Orchard.Web/Modules/Orchard.Users/Orchard.Users.csproj index 8099ad4df..73a4fa092 100644 --- a/src/Orchard.Web/Modules/Orchard.Users/Orchard.Users.csproj +++ b/src/Orchard.Web/Modules/Orchard.Users/Orchard.Users.csproj @@ -123,6 +123,9 @@ + + +