--HG--
branch : dev
This commit is contained in:
Renaud Paquay
2010-11-26 18:10:18 -08:00
22 changed files with 272 additions and 130 deletions

View File

@@ -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);

View File

@@ -72,8 +72,15 @@ namespace Orchard.Core.Routable.Handlers {
public class RoutePartHandlerBase : ContentHandlerBase {
public override void GetContentItemMetadata(GetContentItemMetadataContext context) {
var routable = context.ContentItem.As<RoutePart>();
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"},

View File

@@ -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<RoutePart>())
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<dynamic>(model)
ViewData = new ViewDataDictionary<object>(model)
};
}
}

View File

@@ -1 +1,4 @@
@Display(Model)
@{
RouteValueDictionary routeValues = Model.RouteValues;
Html.RenderAction(routeValues["action"] as string, routeValues["controller"] as string, routeValues);
}

View File

@@ -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<RoutePart>().Slug}
};
context.Metadata.CreateRouteValues = new RouteValueDictionary {
{"Area", "Orchard.Blogs"},
{"Controller", "BlogAdmin"},

View File

@@ -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<LayerPart>().Name = "TheHomepage";
homepageLayer.As<LayerPart>().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<WidgetPart>().LayerPart = homepageLayer.As<LayerPart>();
tripelFirst.As<WidgetPart>().Title = T("First Leader Aside").Text;
tripelFirst.As<WidgetPart>().Zone = "TripelFirst";
@@ -260,7 +260,7 @@ namespace Orchard.Setup.Services {
tripelFirst.As<BodyPart>().Text = "<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur a nibh ut tortor dapibus vestibulum. Aliquam vel sem nibh. Suspendisse vel condimentum tellus.</p>";
contentManager.Publish(tripelFirst);
var tripelSecond = contentManager.Create("HtmlWidget");
var tripelSecond = contentManager.Create("HtmlWidget", VersionOptions.Draft);
tripelSecond.As<WidgetPart>().LayerPart = homepageLayer.As<LayerPart>();
tripelSecond.As<WidgetPart>().Title = T("Second Leader Aside").Text;
tripelSecond.As<WidgetPart>().Zone = "TripelSecond";
@@ -268,7 +268,7 @@ namespace Orchard.Setup.Services {
tripelSecond.As<BodyPart>().Text = "<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur a nibh ut tortor dapibus vestibulum. Aliquam vel sem nibh. Suspendisse vel condimentum tellus.</p>";
contentManager.Publish(tripelSecond);
var tripelThird = contentManager.Create("HtmlWidget");
var tripelThird = contentManager.Create("HtmlWidget", VersionOptions.Draft);
tripelThird.As<WidgetPart>().LayerPart = homepageLayer.As<LayerPart>();
tripelThird.As<WidgetPart>().Title = T("Third Leader Aside").Text;
tripelThird.As<WidgetPart>().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<RoutePart>().Title = T("Welcome to Orchard!").Text;
page.As<RoutePart>().Path = "";
page.As<RoutePart>().Slug = "";
page.As<BodyPart>().Text = string.Format(CultureInfo.CurrentCulture, "<p>Youve 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 dont need this anymore, you can <a href=\"Admin/Contents/Edit/{0}\">remove this by going into editing mode</a> and replacing it with whatever you want.</p><p>First things first - Youll probably want to <a href=\"Admin/Settings\">manage your settings</a> and configure Orchard to your liking. After that, you can head over to <a href=\"Admin/Themes\">manage themes to change or install new themes</a> and really make it your own. Once youre happy with a look and feel, its time for some content. You can start creating new custom content types or start with some built-in ones by <a href=\"Admin/Pages/Create\">adding a page</a>, <a href=\"Admin/Blogs/Create\">creating a blog</a> or <a href=\"Admin/Navigation\">managing your menus.</a></p><p>Finally, Orchard has been designed to be extended. It comes with a few built-in modules such as pages and blogs or themes. If youre 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, <a href=\"http://www.orchardproject.net/\">please consider participating</a>. XOXO The Orchard Team </p>", page.Id);
contentManager.Publish(page);

View File

@@ -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<UserPart>().EmailStatus == UserStatus.Pending ) {
string challengeToken = _membershipService.GetEncryptedChallengeToken(user.As<UserPart>());
_membershipService.SendChallengeEmail(user.As<UserPart>(), Url.AbsoluteAction(() => Url.Action("ChallengeEmail", "Account", new { Area = "Orchard.Users", token = challengeToken })));
string challengeToken = _userService.GetNonce(user.As<UserPart>());
_userService.SendChallengeEmail(user.As<UserPart>(), 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;

View File

@@ -197,8 +197,8 @@ namespace Orchard.Users.Controllers {
var user = Services.ContentManager.Get(id);
if ( user != null ) {
string challengeToken = _membershipService.GetEncryptedChallengeToken(user.As<UserPart>());
_membershipService.SendChallengeEmail(user.As<UserPart>(), Url.AbsoluteAction(() => Url.Action("ChallengeEmail", "Account", new {Area = "Orchard.Users", token = challengeToken})));
string challengeToken = _userService.GetNonce(user.As<UserPart>());
_userService.SendChallengeEmail(user.As<UserPart>(), Url.AbsoluteAction(() => Url.Action("ChallengeEmail", "Account", new {Area = "Orchard.Users", token = challengeToken})));
}
Services.Notifier.Information(T("Challenge email sent"));

View File

@@ -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 <a href=\"{1}\">click here</a> 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 <a href=\"{1}\">click here</a> to change your password.", recipient.UserName, context.Properties["LostPasswordUrl"]).Text;
}
}
public void Sent(MessageContext context) {

View File

@@ -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";
}
}

View File

@@ -123,6 +123,9 @@
<Content Include="Views\EditorTemplates\Parts\User.Edit.cshtml" />
<Content Include="Views\EditorTemplates\Parts\User.Create.cshtml" />
</ItemGroup>
<ItemGroup>
<Content Include="Views\Account\LostPassword.cshtml" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v10.0\WebApplications\Microsoft.WebApplication.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.

View File

@@ -1,6 +1,16 @@
using Orchard.Security;
using System;
namespace Orchard.Users.Services {
public interface IUserService : IDependency {
string VerifyUserUnicity(string userName, string email);
string VerifyUserUnicity(int id, string userName, string email);
void SendChallengeEmail(IUser user, string url);
IUser ValidateChallenge(string challengeToken);
bool SendLostPasswordEmail(string usernameOrEmail, Func<string, string> createUrl);
IUser ValidateLostPassword(string nonce);
string GetNonce(IUser user);
}
}

View File

@@ -14,6 +14,7 @@ using Orchard.Users.Events;
using Orchard.Users.Models;
using Orchard.Messaging.Services;
using System.Collections.Generic;
using Orchard.Services;
namespace Orchard.Users.Services {
[UsedImplicitly]
@@ -22,11 +23,13 @@ namespace Orchard.Users.Services {
private readonly IOrchardServices _orchardServices;
private readonly IMessageManager _messageManager;
private readonly IEnumerable<IUserEventHandler> _userEventHandlers;
private readonly IClock _clock;
public MembershipService(IOrchardServices orchardServices, IMessageManager messageManager, IEnumerable<IUserEventHandler> userEventHandlers) {
public MembershipService(IOrchardServices orchardServices, IMessageManager messageManager, IEnumerable<IUserEventHandler> userEventHandlers, IClock clock) {
_orchardServices = orchardServices;
_messageManager = messageManager;
_userEventHandlers = userEventHandlers;
_clock = clock;
Logger = NullLogger.Instance;
T = NullLocalizer.Instance;
}
@@ -87,54 +90,6 @@ namespace Orchard.Users.Services {
return user;
}
public void SendChallengeEmail(IUser user, string url) {
_messageManager.Send(user.ContentItem.Record, MessageTypes.Validation, "email", new Dictionary<string, string> { { "ChallengeUrl", url } });
}
public IUser ValidateChallengeToken(string challengeToken) {
string username;
DateTime validateByUtc;
if(!DecryptChallengeToken(challengeToken, out username, out validateByUtc)) {
return null;
}
if ( validateByUtc < DateTime.UtcNow )
return null;
var user = GetUser(username);
if ( user == null )
return null;
user.As<UserPart>().EmailStatus = UserStatus.Approved;
return user;
}
public string GetEncryptedChallengeToken(IUser user) {
var challengeToken = new XElement("Token", new XAttribute("username", user.UserName), new XAttribute("validate-by-utc", DateTime.UtcNow.Add(DelayToValidate).ToString(CultureInfo.InvariantCulture))).ToString();
var data = Encoding.UTF8.GetBytes(challengeToken);
return MachineKey.Encode(data, MachineKeyProtection.All);
}
private static bool DecryptChallengeToken(string challengeToken, out string username, out DateTime validateByUtc) {
username = null;
validateByUtc = DateTime.UtcNow;
try {
var data = MachineKey.Decode(challengeToken, MachineKeyProtection.All);
var xml = Encoding.UTF8.GetString(data);
var element = XElement.Parse(xml);
username = element.Attribute("username").Value;
validateByUtc = DateTime.Parse(element.Attribute("validate-by-utc").Value, CultureInfo.InvariantCulture);
return true;
}
catch {
return false;
}
}
public IUser GetUser(string username) {
var lowerName = username == null ? "" : username.ToLower();

View File

@@ -1,17 +1,33 @@
using System;
using System.Linq;
using System.Collections.Generic;
using JetBrains.Annotations;
using Orchard.Logging;
using Orchard.ContentManagement;
using Orchard.Users.Models;
using Orchard.Security;
using System.Xml.Linq;
using Orchard.Services;
using System.Globalization;
using System.Text;
using System.Web.Security;
using Orchard.Messaging.Services;
namespace Orchard.Users.Services {
[UsedImplicitly]
public class UserService : IUserService {
private readonly IContentManager _contentManager;
private static readonly TimeSpan DelayToValidate = new TimeSpan(7, 0, 0, 0); // one week to validate email
public UserService(IContentManager contentManager) {
private readonly IContentManager _contentManager;
private readonly IMembershipService _membershipService;
private readonly IClock _clock;
private readonly IMessageManager _messageManager;
public UserService(IContentManager contentManager, IMembershipService membershipService, IClock clock, IMessageManager messageManager) {
_contentManager = contentManager;
_membershipService = membershipService;
_clock = clock;
_messageManager = messageManager;
Logger = NullLogger.Instance;
}
@@ -46,5 +62,86 @@ namespace Orchard.Users.Services {
}
return null;
}
public string GetNonce(IUser user) {
var challengeToken = new XElement("Token", new XAttribute("username", user.UserName), new XAttribute("validate-by-utc", _clock.UtcNow.Add(DelayToValidate).ToString(CultureInfo.InvariantCulture))).ToString();
var data = Encoding.UTF8.GetBytes(challengeToken);
return MachineKey.Encode(data, MachineKeyProtection.All);
}
private bool DecryptNonce(string challengeToken, out string username, out DateTime validateByUtc) {
username = null;
validateByUtc = _clock.UtcNow;
try {
var data = MachineKey.Decode(challengeToken, MachineKeyProtection.All);
var xml = Encoding.UTF8.GetString(data);
var element = XElement.Parse(xml);
username = element.Attribute("username").Value;
validateByUtc = DateTime.Parse(element.Attribute("validate-by-utc").Value, CultureInfo.InvariantCulture);
return true;
}
catch {
return false;
}
}
public IUser ValidateChallenge(string nonce) {
string username;
DateTime validateByUtc;
if (!DecryptNonce(nonce, out username, out validateByUtc)) {
return null;
}
if (validateByUtc < _clock.UtcNow)
return null;
var user = _membershipService.GetUser(username);
if (user == null)
return null;
user.As<UserPart>().EmailStatus = UserStatus.Approved;
return user;
}
public void SendChallengeEmail(IUser user, string url) {
_messageManager.Send(user.ContentItem.Record, MessageTypes.Validation, "email", new Dictionary<string, string> { { "ChallengeUrl", url } });
}
public bool SendLostPasswordEmail(string usernameOrEmail, Func<string, string> createUrl) {
var lowerName = usernameOrEmail.ToLower();
var user = _contentManager.Query<UserPart, UserPartRecord>().Where(u => u.NormalizedUserName == lowerName || u.Email == lowerName).List().FirstOrDefault();
if (user != null) {
string nonce = GetNonce(user);
string url = createUrl(nonce);
_messageManager.Send(user.ContentItem.Record, MessageTypes.LostPassword, "email", new Dictionary<string, string> { { "LostPasswordUrl", url } });
return true;
}
return false;
}
public IUser ValidateLostPassword(string nonce) {
string username;
DateTime validateByUtc;
if (!DecryptNonce(nonce, out username, out validateByUtc)) {
return null;
}
if (validateByUtc < _clock.UtcNow)
return null;
var user = _membershipService.GetUser(username);
if (user == null)
return null;
return user;
}
}
}

View File

@@ -6,11 +6,6 @@
@using (Html.BeginFormAntiForgeryPost()) {
<fieldset>
<legend>@T("Account Information")</legend>
<div>
<label for="currentPassword">@T("Current password:")</label>
@Html.Password("currentPassword")
@Html.ValidationMessage("currentPassword")
</div>
<div>
<label for="newPassword">@T("New password:")</label>
@Html.Password("newPassword")

View File

@@ -6,10 +6,14 @@
}
<h1 class="page-title">@Html.TitleForPage(Model.Title)</h1>
<p>@T("Please enter your username and password.") @if(userCanRegister) { <text> </text> @Html.ActionLink("Register", "Register") @T(" if you don't have an account.") }</p>
<p>
@T("Please enter your username and password.")
@if(userCanRegister) { @Html.ActionLink(T("Register").Text, "Register") @T(" if you don't have an account.") }
@Html.ActionLink(T("Lost your Password?").Text, "LostPassword")
</p>
@Html.ValidationSummary(T("Login was unsuccessful. Please correct the errors and try again.").ToString())
@using (Html.BeginFormAntiForgeryPost(Url.Action("LogOn", new {ReturnUrl = Request.QueryString["ReturnUrl"]}))) {
@using (Html.BeginFormAntiForgeryPost(Url.Action("LogOn", new { ReturnUrl = Request.QueryString["ReturnUrl"] }))) {
<fieldset class="login-form group">
<legend>@T("Account Information")</legend>
<ol>

View File

@@ -0,0 +1,15 @@
<h1>@Html.TitleForPage(T("Lost Password").ToString())</h1>
<p>@T("Please enter your username or email address. You will receive a link to create a new password via email.")</p>
@using (Html.BeginFormAntiForgeryPost()) {
<fieldset>
<legend>@T("Account Information")</legend>
<div>
<label for="username">@T("Username or E-mail:")</label>
@Html.TextBox("username")
@Html.ValidationMessage("username")
</div>
<div>
<button class="primaryAction" type="submit">@T("Send Request")</button>
</div>
</fieldset>
}

View File

@@ -9,13 +9,10 @@ namespace Orchard.Mvc.Html {
/// <see cref="http://en.wikipedia.org/wiki/Harry_Houdini"/>
/// <returns>himself</returns>
public static TService Resolve<TService>(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<TService>();
}

View File

@@ -8,8 +8,5 @@
IUser ValidateUser(string userNameOrEmail, string password);
void SetPassword(IUser user, string password);
IUser ValidateChallengeToken(string challengeToken);
void SendChallengeEmail(IUser user, string url);
string GetEncryptedChallengeToken(IUser user);
}
}

View File

@@ -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";

View File

@@ -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;

View File

@@ -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);
}