mirror of
https://github.com/OrchardCMS/Orchard.git
synced 2025-04-05 21:01:35 +08:00
Merge
--HG-- branch : dev
This commit is contained in:
commit
d84f4ee0db
@ -6,13 +6,18 @@ using JetBrains.Annotations;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using Orchard.ContentManagement.Aspects;
|
||||
using Orchard.Core.Common;
|
||||
using Orchard.Core.Common.Handlers;
|
||||
using Orchard.Core.Common.Models;
|
||||
using Orchard.ContentManagement;
|
||||
using Orchard.ContentManagement.Handlers;
|
||||
using Orchard.ContentManagement.Records;
|
||||
using Orchard.Localization;
|
||||
using Orchard.Security;
|
||||
using Orchard.Tests.Modules;
|
||||
using Orchard.Mvc.ViewModels;
|
||||
using Orchard.Core.Common.ViewModels;
|
||||
using System.Web.Mvc;
|
||||
|
||||
namespace Orchard.Core.Tests.Common.Providers {
|
||||
[TestFixture]
|
||||
@ -29,6 +34,7 @@ namespace Orchard.Core.Tests.Common.Providers {
|
||||
_authn = new Mock<IAuthenticationService>();
|
||||
_authz = new Mock<IAuthorizationService>();
|
||||
_membership = new Mock<IMembershipService>();
|
||||
|
||||
builder.RegisterInstance(_authn.Object);
|
||||
builder.RegisterInstance(_authz.Object);
|
||||
builder.RegisterInstance(_membership.Object);
|
||||
@ -73,7 +79,83 @@ namespace Orchard.Core.Tests.Common.Providers {
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void PublishingShouldSetPublishUtc() {
|
||||
public void PublishingShouldFailIfOwnerIsUnknown()
|
||||
{
|
||||
var contentManager = _container.Resolve<IContentManager>();
|
||||
var updateModel = new Mock<IUpdateModel>();
|
||||
|
||||
var user = contentManager.New<IUser>("user");
|
||||
_authn.Setup(x => x.GetAuthenticatedUser()).Returns(user);
|
||||
|
||||
var createUtc = _clock.UtcNow;
|
||||
var item = contentManager.Create<ICommonAspect>("test-item", VersionOptions.Draft, init => { });
|
||||
var viewModel = new OwnerEditorViewModel() { Owner = "user" };
|
||||
updateModel.Setup(x => x.TryUpdateModel(viewModel, "", null, null)).Returns(true);
|
||||
contentManager.UpdateEditorModel(item.ContentItem, updateModel.Object);
|
||||
}
|
||||
|
||||
class UpdatModelStub : IUpdateModel {
|
||||
|
||||
ModelStateDictionary _modelState = new ModelStateDictionary();
|
||||
|
||||
public ModelStateDictionary ModelErrors
|
||||
{
|
||||
get { return _modelState; }
|
||||
}
|
||||
|
||||
public string Owner { get; set; }
|
||||
|
||||
public bool TryUpdateModel<TModel>(TModel model, string prefix, string[] includeProperties, string[] excludeProperties) where TModel : class {
|
||||
(model as OwnerEditorViewModel).Owner = Owner;
|
||||
return true;
|
||||
}
|
||||
|
||||
public void AddModelError(string key, LocalizedString errorMessage) {
|
||||
_modelState.AddModelError(key, errorMessage.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void PublishingShouldNotThrowExceptionIfOwnerIsNull()
|
||||
{
|
||||
var contentManager = _container.Resolve<IContentManager>();
|
||||
|
||||
var item = contentManager.Create<ICommonAspect>("test-item", VersionOptions.Draft, init => { });
|
||||
|
||||
var user = contentManager.New<IUser>("user");
|
||||
_authn.Setup(x => x.GetAuthenticatedUser()).Returns(user);
|
||||
_authz.Setup(x => x.TryCheckAccess(Permissions.ChangeOwner, user, item)).Returns(true);
|
||||
|
||||
item.Owner = user;
|
||||
|
||||
var updater = new UpdatModelStub() { Owner = null };
|
||||
|
||||
contentManager.UpdateEditorModel(item.ContentItem, updater);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void PublishingShouldFailIfOwnerIsEmpty()
|
||||
{
|
||||
var contentManager = _container.Resolve<IContentManager>();
|
||||
|
||||
var item = contentManager.Create<ICommonAspect>("test-item", VersionOptions.Draft, init => { });
|
||||
|
||||
var user = contentManager.New<IUser>("user");
|
||||
_authn.Setup(x => x.GetAuthenticatedUser()).Returns(user);
|
||||
_authz.Setup(x => x.TryCheckAccess(Permissions.ChangeOwner, user, item)).Returns(true);
|
||||
|
||||
item.Owner = user;
|
||||
|
||||
var updater = new UpdatModelStub() {Owner = ""};
|
||||
|
||||
contentManager.UpdateEditorModel(item.ContentItem, updater);
|
||||
|
||||
Assert.That(updater.ModelErrors.ContainsKey("CommonAspect.Owner"), Is.True);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void PublishingShouldSetPublishUtc()
|
||||
{
|
||||
var contentManager = _container.Resolve<IContentManager>();
|
||||
|
||||
var createUtc = _clock.UtcNow;
|
||||
@ -81,7 +163,7 @@ namespace Orchard.Core.Tests.Common.Providers {
|
||||
|
||||
Assert.That(item.CreatedUtc, Is.EqualTo(createUtc));
|
||||
Assert.That(item.PublishedUtc, Is.Null);
|
||||
|
||||
|
||||
_clock.Advance(TimeSpan.FromMinutes(1));
|
||||
var publishUtc = _clock.UtcNow;
|
||||
|
||||
@ -91,6 +173,7 @@ namespace Orchard.Core.Tests.Common.Providers {
|
||||
Assert.That(item.PublishedUtc, Is.EqualTo(publishUtc));
|
||||
}
|
||||
|
||||
|
||||
[Test]
|
||||
public void VersioningItemShouldCreatedAndPublishedUtcValuesPerVersion() {
|
||||
var contentManager = _container.Resolve<IContentManager>();
|
||||
|
@ -10,6 +10,10 @@ using Orchard.ContentManagement.Records;
|
||||
using Orchard.Core.Common.Models;
|
||||
using Orchard.Core.Common.Services;
|
||||
using Orchard.Tests.Modules;
|
||||
using Orchard.Core.Common.Handlers;
|
||||
using System.Web.Mvc;
|
||||
using System.Web.Routing;
|
||||
using Orchard.Tests.Stubs;
|
||||
|
||||
namespace Orchard.Core.Tests.Common.Services {
|
||||
[TestFixture]
|
||||
@ -23,7 +27,13 @@ namespace Orchard.Core.Tests.Common.Services {
|
||||
public override void Register(ContainerBuilder builder) {
|
||||
builder.RegisterType<DefaultContentManager>().As<IContentManager>();
|
||||
builder.RegisterType<ThingHandler>().As<IContentHandler>();
|
||||
builder.RegisterType<StuffHandler>().As<IContentHandler>();
|
||||
builder.RegisterType<RoutableService>().As<IRoutableService>();
|
||||
|
||||
builder.RegisterType<DefaultContentQuery>().As<IContentQuery>();
|
||||
builder.RegisterInstance(new UrlHelper(new RequestContext(new StubHttpContext("~/"), new RouteData()))).As<UrlHelper>();
|
||||
builder.RegisterType<RoutableAspectHandler>().As<IContentHandler>();
|
||||
|
||||
}
|
||||
|
||||
private IRoutableService _routableService;
|
||||
@ -42,6 +52,24 @@ namespace Orchard.Core.Tests.Common.Services {
|
||||
Assert.That(thing.Slug, Is.EqualTo("please-do-not-use-any-of-the-following-characters-in-your-slugs-\"-\"-\"-\"-\"-\"-\"-\"-\"-\"-\"-\"-\"-\"-\"-\"-\"-\"-\"-\"-\"-\"-\"-\"-\"-\"-\"-\"-\"-\"-\"-\"-\"-\"-\"-\""));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void EmptySlugsShouldBeConsideredValid() {
|
||||
// so that automatic generation on Publish occurs
|
||||
Assert.That(_routableService.IsSlugValid(null), Is.True);
|
||||
Assert.That(_routableService.IsSlugValid(String.Empty), Is.True);
|
||||
Assert.That(_routableService.IsSlugValid(" "), Is.True);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void InvalidCharacterShouldBeRefusedInSlugs() {
|
||||
Assert.That(_routableService.IsSlugValid("aaaa-_aaaa"), Is.True);
|
||||
|
||||
foreach (var c in @"/:?#[]@!$&'()*+,;= ") {
|
||||
Assert.That(_routableService.IsSlugValid("a" + c + "b"), Is.False);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[Test]
|
||||
public void VeryLongStringTruncatedTo1000Chars() {
|
||||
var contentManager = _container.Resolve<IContentManager>();
|
||||
@ -111,6 +139,47 @@ namespace Orchard.Core.Tests.Common.Services {
|
||||
Assert.That(thing.Slug, Is.EqualTo("this-is-some-interesting-title"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GeneratedSlugsShouldBeUniqueAmongContentType()
|
||||
{
|
||||
var contentManager = _container.Resolve<IContentManager>();
|
||||
|
||||
var thing1 = contentManager.Create<Thing>(ThingDriver.ContentType.Name, t =>
|
||||
{
|
||||
t.As<RoutableAspect>().Record = new RoutableRecord();
|
||||
t.Title = "This Is Some Interesting Title";
|
||||
});
|
||||
|
||||
var thing2 = contentManager.Create<Thing>(ThingDriver.ContentType.Name , t =>
|
||||
{
|
||||
t.As<RoutableAspect>().Record = new RoutableRecord();
|
||||
t.Title = "This Is Some Interesting Title";
|
||||
});
|
||||
|
||||
Assert.AreNotEqual(thing1.Slug, thing2.Slug);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SlugsCanBeDuplicatedAccrossContentTypes()
|
||||
{
|
||||
var contentManager = _container.Resolve<IContentManager>();
|
||||
|
||||
var thing = contentManager.Create<Thing>(ThingDriver.ContentType.Name, t =>
|
||||
{
|
||||
t.As<RoutableAspect>().Record = new RoutableRecord();
|
||||
t.Title = "This Is Some Interesting Title";
|
||||
});
|
||||
|
||||
var stuff = contentManager.Create<Stuff>(StuffDriver.ContentType.Name, s =>
|
||||
{
|
||||
s.As<RoutableAspect>().Record = new RoutableRecord();
|
||||
s.Title = "This Is Some Interesting Title";
|
||||
});
|
||||
|
||||
Assert.AreEqual(thing.Slug, stuff.Slug);
|
||||
}
|
||||
|
||||
|
||||
protected override IEnumerable<Type> DatabaseTypes {
|
||||
get {
|
||||
return new[] {
|
||||
@ -155,5 +224,43 @@ namespace Orchard.Core.Tests.Common.Services {
|
||||
DisplayName = "Thing"
|
||||
};
|
||||
}
|
||||
|
||||
[UsedImplicitly]
|
||||
public class StuffHandler : ContentHandler
|
||||
{
|
||||
public StuffHandler()
|
||||
{
|
||||
Filters.Add(new ActivatingFilter<Stuff>(StuffDriver.ContentType.Name));
|
||||
Filters.Add(new ActivatingFilter<ContentPart<CommonVersionRecord>>(StuffDriver.ContentType.Name));
|
||||
Filters.Add(new ActivatingFilter<CommonAspect>(StuffDriver.ContentType.Name));
|
||||
Filters.Add(new ActivatingFilter<RoutableAspect>(StuffDriver.ContentType.Name));
|
||||
}
|
||||
}
|
||||
|
||||
public class Stuff : ContentPart
|
||||
{
|
||||
public int Id { get { return ContentItem.Id; } }
|
||||
|
||||
public string Title
|
||||
{
|
||||
get { return this.As<RoutableAspect>().Title; }
|
||||
set { this.As<RoutableAspect>().Title = value; }
|
||||
}
|
||||
|
||||
public string Slug
|
||||
{
|
||||
get { return this.As<RoutableAspect>().Slug; }
|
||||
set { this.As<RoutableAspect>().Slug = value; }
|
||||
}
|
||||
}
|
||||
|
||||
public class StuffDriver : ContentItemDriver<Stuff>
|
||||
{
|
||||
public readonly static ContentType ContentType = new ContentType
|
||||
{
|
||||
Name = "stuff",
|
||||
DisplayName = "Stuff"
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
@ -60,6 +60,9 @@
|
||||
<HintPath>..\..\lib\sqlite\System.Data.SQLite.DLL</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System.Web.Abstractions">
|
||||
<RequiredTargetFramework>3.5</RequiredTargetFramework>
|
||||
</Reference>
|
||||
<Reference Include="System.Web.Mvc, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\..\lib\aspnetmvc\System.Web.Mvc.dll</HintPath>
|
||||
|
@ -3,16 +3,31 @@ using Orchard.ContentManagement;
|
||||
using Orchard.ContentManagement.Drivers;
|
||||
using Orchard.Core.Common.Models;
|
||||
using Orchard.Core.Common.ViewModels;
|
||||
using Orchard.Core.Common.Services;
|
||||
using Orchard.Localization;
|
||||
using Orchard.UI.Notify;
|
||||
|
||||
namespace Orchard.Core.Common.Drivers {
|
||||
[UsedImplicitly]
|
||||
public class Routable : ContentPartDriver<RoutableAspect> {
|
||||
private const string TemplateName = "Parts/Common.Routable";
|
||||
|
||||
private readonly IOrchardServices _services;
|
||||
private readonly IRoutableService _routableService;
|
||||
private Localizer T { get; set; }
|
||||
|
||||
protected override string Prefix {
|
||||
get { return "Routable"; }
|
||||
}
|
||||
|
||||
public Routable(IOrchardServices services, IRoutableService routableService)
|
||||
{
|
||||
_services = services;
|
||||
_routableService = routableService;
|
||||
|
||||
T = NullLocalizer.Instance;
|
||||
}
|
||||
|
||||
protected override DriverResult Editor(RoutableAspect part) {
|
||||
var model = new RoutableEditorViewModel { Prefix = Prefix, RoutableAspect = part };
|
||||
return ContentPartTemplate(model, TemplateName, Prefix).Location("primary", "before.5");
|
||||
@ -21,7 +36,19 @@ namespace Orchard.Core.Common.Drivers {
|
||||
protected override DriverResult Editor(RoutableAspect part, IUpdateModel updater) {
|
||||
var model = new RoutableEditorViewModel { Prefix = Prefix, RoutableAspect = part };
|
||||
updater.TryUpdateModel(model, Prefix, null, null);
|
||||
|
||||
if (!_routableService.IsSlugValid(part.Slug)){
|
||||
updater.AddModelError("Routable.Slug", T("Please do not use any of the following characters in your slugs: \"/\", \":\", \"?\", \"#\", \"[\", \"]\", \"@\", \"!\", \"$\", \"&\", \"'\", \"(\", \")\", \"*\", \"+\", \",\", \";\", \"=\". No spaces are allowed (please use dashes or underscores instead).").ToString());
|
||||
}
|
||||
|
||||
string originalSlug = part.Slug;
|
||||
if(!_routableService.ProcessSlug(part)) {
|
||||
_services.Notifier.Warning(T("Slugs in conflict. \"{0}\" is already set for a previously created {2} so now it has the slug \"{1}\"",
|
||||
originalSlug, part.Slug, part.ContentItem.ContentType));
|
||||
}
|
||||
|
||||
return ContentPartTemplate(model, TemplateName, Prefix).Location("primary", "before.5");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -172,7 +172,7 @@ namespace Orchard.Core.Common.Handlers {
|
||||
var priorOwner = viewModel.Owner;
|
||||
context.Updater.TryUpdateModel(viewModel, "CommonAspect", null, null);
|
||||
|
||||
if (viewModel.Owner != priorOwner) {
|
||||
if (viewModel.Owner != null && viewModel.Owner != priorOwner) {
|
||||
var newOwner = _membershipService.GetUser(viewModel.Owner);
|
||||
if (newOwner == null) {
|
||||
context.Updater.AddModelError("CommonAspect.Owner", T("Invalid user name"));
|
||||
@ -181,6 +181,7 @@ namespace Orchard.Core.Common.Handlers {
|
||||
instance.Owner = newOwner;
|
||||
}
|
||||
}
|
||||
|
||||
context.AddEditor(new TemplateViewModel(viewModel, "CommonAspect") { TemplateName = "Parts/Common.Owner", ZoneName = "primary", Position = "999" });
|
||||
}
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ using Orchard.ContentManagement;
|
||||
using Orchard.ContentManagement.Drivers;
|
||||
using Orchard.ContentManagement.Handlers;
|
||||
using Orchard.Core.Common.Models;
|
||||
using Orchard.Core.Common.Services;
|
||||
using Orchard.Data;
|
||||
|
||||
namespace Orchard.Core.Common.Handlers {
|
||||
@ -14,7 +15,7 @@ namespace Orchard.Core.Common.Handlers {
|
||||
public class RoutableAspectHandler : ContentHandler {
|
||||
private readonly IEnumerable<IContentItemDriver> _contentItemDrivers;
|
||||
|
||||
public RoutableAspectHandler(IRepository<RoutableRecord> repository, IEnumerable<IContentItemDriver> contentItemDrivers, UrlHelper urlHelper) {
|
||||
public RoutableAspectHandler(IRepository<RoutableRecord> repository, IEnumerable<IContentItemDriver> contentItemDrivers, IRoutableService routableService, UrlHelper urlHelper) {
|
||||
_contentItemDrivers = contentItemDrivers;
|
||||
|
||||
Filters.Add(StorageFilter.For(repository));
|
||||
@ -32,6 +33,9 @@ namespace Orchard.Core.Common.Handlers {
|
||||
|
||||
routable.ContentItemBasePath = url;
|
||||
});
|
||||
|
||||
OnCreated<RoutableAspect>((context, ra) => routableService.ProcessSlug(ra));
|
||||
|
||||
}
|
||||
|
||||
private static RouteValueDictionary GetRouteValues(IContentItemDriver driver, ContentItem contentItem) {
|
||||
|
@ -7,5 +7,22 @@ namespace Orchard.Core.Common.Services {
|
||||
void FillSlug<TModel>(TModel model) where TModel : RoutableAspect;
|
||||
void FillSlug<TModel>(TModel model, Func<string, string> generateSlug) where TModel : RoutableAspect;
|
||||
string GenerateUniqueSlug(string slugCandidate, IEnumerable<string> existingSlugs);
|
||||
|
||||
/// <summary>
|
||||
/// Returns any content item of the specified content type with similar slugs
|
||||
/// </summary>
|
||||
string[] GetSimilarSlugs(string contentType, string slug);
|
||||
|
||||
/// <summary>
|
||||
/// Validates the given slug
|
||||
/// </summary>
|
||||
bool IsSlugValid(string slug);
|
||||
|
||||
/// <summary>
|
||||
/// Defines the slug of a RoutableAspect and validate its unicity
|
||||
/// </summary>
|
||||
/// <returns>True if the slug has been created, False if a conflict occured</returns>
|
||||
bool ProcessSlug(RoutableAspect part);
|
||||
|
||||
}
|
||||
}
|
@ -4,10 +4,19 @@ using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using JetBrains.Annotations;
|
||||
using Orchard.Core.Common.Models;
|
||||
using Orchard.ContentManagement;
|
||||
using Orchard.Localization;
|
||||
using Orchard.UI.Notify;
|
||||
|
||||
namespace Orchard.Core.Common.Services {
|
||||
[UsedImplicitly]
|
||||
public class RoutableService : IRoutableService {
|
||||
private readonly IContentManager _contentManager;
|
||||
|
||||
public RoutableService(IContentManager contentManager) {
|
||||
_contentManager = contentManager;
|
||||
}
|
||||
|
||||
public void FillSlug<TModel>(TModel model) where TModel : RoutableAspect {
|
||||
if (!string.IsNullOrEmpty(model.Slug) || string.IsNullOrEmpty(model.Title))
|
||||
return;
|
||||
@ -31,8 +40,6 @@ namespace Orchard.Core.Common.Services {
|
||||
model.Slug = generateSlug(model.Title).ToLowerInvariant();
|
||||
}
|
||||
|
||||
|
||||
|
||||
public string GenerateUniqueSlug(string slugCandidate, IEnumerable<string> existingSlugs) {
|
||||
if (existingSlugs == null || !existingSlugs.Contains(slugCandidate))
|
||||
return slugCandidate;
|
||||
@ -55,5 +62,46 @@ namespace Orchard.Core.Common.Services {
|
||||
? (int?)++v
|
||||
: null;
|
||||
}
|
||||
|
||||
public string[] GetSimilarSlugs(string contentType, string slug)
|
||||
{
|
||||
return
|
||||
_contentManager.Query(contentType).Join<RoutableRecord>()
|
||||
.List()
|
||||
.Select(i => i.As<RoutableAspect>().Slug)
|
||||
.Where(rr => rr.StartsWith(slug, StringComparison.OrdinalIgnoreCase)) // todo: for some reason the filter doesn't work within the query, even without StringComparison or StartsWith
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
public bool IsSlugValid(string slug) {
|
||||
// see http://tools.ietf.org/html/rfc3987 for prohibited chars
|
||||
return slug == null || String.IsNullOrEmpty(slug.Trim()) || Regex.IsMatch(slug, @"^[^/:?#\[\]@!$&'()*+,;=\s]+$");
|
||||
}
|
||||
|
||||
public bool ProcessSlug(RoutableAspect part)
|
||||
{
|
||||
FillSlug(part);
|
||||
|
||||
if (string.IsNullOrEmpty(part.Slug))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
var slugsLikeThis = GetSimilarSlugs(part.ContentItem.ContentType, part.Slug);
|
||||
|
||||
//todo: (heskew) need better messages
|
||||
if (slugsLikeThis.Length > 0)
|
||||
{
|
||||
var originalSlug = part.Slug;
|
||||
//todo: (heskew) make auto-uniqueness optional
|
||||
part.Slug = GenerateUniqueSlug(part.Slug, slugsLikeThis);
|
||||
|
||||
if (originalSlug != part.Slug) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
@ -27,14 +27,12 @@ namespace Orchard.Blogs.Drivers {
|
||||
private readonly IContentManager _contentManager;
|
||||
private readonly IBlogService _blogService;
|
||||
private readonly IBlogPostService _blogPostService;
|
||||
private readonly IRoutableService _routableService;
|
||||
|
||||
public BlogDriver(IOrchardServices services, IContentManager contentManager, IBlogService blogService, IBlogPostService blogPostService, IRoutableService routableService) {
|
||||
public BlogDriver(IOrchardServices services, IContentManager contentManager, IBlogService blogService, IBlogPostService blogPostService) {
|
||||
Services = services;
|
||||
_contentManager = contentManager;
|
||||
_blogService = blogService;
|
||||
_blogPostService = blogPostService;
|
||||
_routableService = routableService;
|
||||
T = NullLocalizer.Instance;
|
||||
}
|
||||
|
||||
@ -97,47 +95,9 @@ namespace Orchard.Blogs.Drivers {
|
||||
protected override DriverResult Editor(Blog blog, IUpdateModel updater) {
|
||||
updater.TryUpdateModel(blog, Prefix, null, null);
|
||||
|
||||
//todo: (heskew) something better needs to be done with this...still feels shoehorned in here
|
||||
ProcessSlug(blog, updater);
|
||||
|
||||
return Combined(
|
||||
ContentItemTemplate("Items/Blogs.Blog"),
|
||||
ContentPartTemplate(blog, "Parts/Blogs.Blog.Fields").Location("primary", "1"));
|
||||
}
|
||||
|
||||
private void ProcessSlug(Blog blog, IUpdateModel updater) {
|
||||
_routableService.FillSlug(blog.As<RoutableAspect>());
|
||||
|
||||
|
||||
if (string.IsNullOrEmpty(blog.Slug)) {
|
||||
return;
|
||||
|
||||
// OR
|
||||
|
||||
// updater.AddModelError("Routable.Slug", T("The slug is required.").ToString());
|
||||
// return;
|
||||
}
|
||||
|
||||
|
||||
if (!Regex.IsMatch(blog.Slug, @"^[^/:?#\[\]@!$&'()*+,;=\s]+$")) {
|
||||
//todo: (heskew) get rid of the hard-coded prefix
|
||||
updater.AddModelError("Routable.Slug", T("Please do not use any of the following characters in your slugs: \"/\", \":\", \"?\", \"#\", \"[\", \"]\", \"@\", \"!\", \"$\", \"&\", \"'\", \"(\", \")\", \"*\", \"+\", \",\", \";\", \"=\". No spaces are allowed (please use dashes or underscores instead).").ToString());
|
||||
}
|
||||
|
||||
var slugsLikeThis = _blogService.Get().Where(
|
||||
b => b.Slug.StartsWith(blog.Slug, StringComparison.OrdinalIgnoreCase) &&
|
||||
b.Id != blog.Id).Select(b => b.Slug);
|
||||
|
||||
//todo: (heskew) need better messages
|
||||
if (slugsLikeThis.Count() > 0) {
|
||||
var originalSlug = blog.Slug;
|
||||
//todo: (heskew) make auto-uniqueness optional
|
||||
blog.Slug = _routableService.GenerateUniqueSlug(blog.Slug, slugsLikeThis);
|
||||
|
||||
if (originalSlug != blog.Slug)
|
||||
Services.Notifier.Warning(T("Slugs in conflict. \"{0}\" is already set for a previously created blog so this blog now has the slug \"{1}\"",
|
||||
originalSlug, blog.Slug));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,19 +1,15 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Web.Routing;
|
||||
using JetBrains.Annotations;
|
||||
using Orchard.Blogs.Models;
|
||||
using Orchard.Blogs.Services;
|
||||
using Orchard.ContentManagement;
|
||||
using Orchard.ContentManagement.Drivers;
|
||||
using Orchard.Core.Common.Models;
|
||||
using Orchard.Core.Common.Services;
|
||||
using Orchard.Localization;
|
||||
using Orchard.UI.Notify;
|
||||
|
||||
namespace Orchard.Blogs.Drivers {
|
||||
[UsedImplicitly]
|
||||
[UsedImplicitly]
|
||||
public class BlogPostDriver : ContentItemDriver<BlogPost> {
|
||||
public IOrchardServices Services { get; set; }
|
||||
private readonly IBlogPostService _blogPostService;
|
||||
@ -78,54 +74,11 @@ namespace Orchard.Blogs.Drivers {
|
||||
protected override DriverResult Editor(BlogPost post, IUpdateModel updater) {
|
||||
updater.TryUpdateModel(post, Prefix, null, null);
|
||||
|
||||
//todo: (heskew) something better needs to be done with this...still feels shoehorned in here
|
||||
ProcessSlug(post, updater);
|
||||
|
||||
DateTime scheduled;
|
||||
if (DateTime.TryParse(string.Format("{0} {1}", post.ScheduledPublishUtcDate, post.ScheduledPublishUtcTime), out scheduled))
|
||||
post.ScheduledPublishUtc = scheduled;
|
||||
|
||||
return Editor(post);
|
||||
}
|
||||
|
||||
private void ProcessSlug(BlogPost post, IUpdateModel updater) {
|
||||
_routableService.FillSlug(post.As<RoutableAspect>());
|
||||
|
||||
if (string.IsNullOrEmpty(post.Slug)) {
|
||||
return;
|
||||
|
||||
// OR
|
||||
|
||||
//updater.AddModelError("Routable.Slug", T("The slug is required.").ToString());
|
||||
//return;
|
||||
}
|
||||
|
||||
if (!Regex.IsMatch(post.Slug, @"^[^/:?#\[\]@!$&'()*+,;=\s]+$")) {
|
||||
//todo: (heskew) get rid of the hard-coded prefix
|
||||
updater.AddModelError("Routable.Slug", T("Please do not use any of the following characters in your slugs: \"/\", \":\", \"?\", \"#\", \"[\", \"]\", \"@\", \"!\", \"$\", \"&\", \"'\", \"(\", \")\", \"*\", \"+\", \",\", \";\", \"=\". No spaces are allowed (please use dashes or underscores instead).").ToString());
|
||||
return;
|
||||
}
|
||||
|
||||
var slugsLikeThis = _blogPostService.Get(post.Blog, VersionOptions.Published).Where(
|
||||
p => p.Slug.StartsWith(post.Slug, StringComparison.OrdinalIgnoreCase) &&
|
||||
p.Id != post.Id).Select(p => p.Slug);
|
||||
|
||||
//todo: (heskew) need better messages
|
||||
if (slugsLikeThis.Count() > 0) {
|
||||
//todo: (heskew) need better messages
|
||||
Services.Notifier.Warning(T("A different blog post is already published with this same slug."));
|
||||
|
||||
if (post.ContentItem.VersionRecord == null || post.ContentItem.VersionRecord.Published)
|
||||
{
|
||||
var originalSlug = post.Slug;
|
||||
//todo: (heskew) make auto-uniqueness optional
|
||||
post.Slug = _routableService.GenerateUniqueSlug(post.Slug, slugsLikeThis);
|
||||
|
||||
if (originalSlug != post.Slug)
|
||||
Services.Notifier.Warning(T("Slugs in conflict. \"{0}\" is already set for a previously created blog post so this post now has the slug \"{1}\"",
|
||||
originalSlug, post.Slug));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -16,12 +16,10 @@ namespace Orchard.Blogs.Handlers {
|
||||
[UsedImplicitly]
|
||||
public class BlogPostHandler : ContentHandler {
|
||||
private readonly IBlogPostService _blogPostService;
|
||||
private readonly IRoutableService _routableService;
|
||||
private readonly IOrchardServices _orchardServices;
|
||||
|
||||
public BlogPostHandler(IBlogService blogService, IBlogPostService blogPostService, IRoutableService routableService, IOrchardServices orchardServices, RequestContext requestContext) {
|
||||
public BlogPostHandler(IBlogService blogService, IBlogPostService blogPostService, IOrchardServices orchardServices, RequestContext requestContext) {
|
||||
_blogPostService = blogPostService;
|
||||
_routableService = routableService;
|
||||
_orchardServices = orchardServices;
|
||||
T = NullLocalizer.Instance;
|
||||
|
||||
@ -63,8 +61,6 @@ namespace Orchard.Blogs.Handlers {
|
||||
OnVersioned<BlogPost>((context, bp1, bp2) => updateBlogPostCount(bp2.Blog));
|
||||
OnRemoved<BlogPost>((context, bp) => updateBlogPostCount(bp.Blog));
|
||||
|
||||
OnPublished<BlogPost>((context, bp) => ProcessSlug(bp));
|
||||
|
||||
OnRemoved<Blog>(
|
||||
(context, b) =>
|
||||
blogPostService.Get(context.ContentItem.As<Blog>()).ToList().ForEach(
|
||||
@ -72,23 +68,5 @@ namespace Orchard.Blogs.Handlers {
|
||||
}
|
||||
|
||||
Localizer T { get; set; }
|
||||
|
||||
private void ProcessSlug(BlogPost post) {
|
||||
_routableService.FillSlug(post.As<RoutableAspect>());
|
||||
|
||||
var slugsLikeThis = _blogPostService.Get(post.Blog, VersionOptions.Published).Where(
|
||||
p => p.Slug.StartsWith(post.Slug, StringComparison.OrdinalIgnoreCase) &&
|
||||
p.Id != post.Id).Select(p => p.Slug);
|
||||
|
||||
//todo: (heskew) need better messages
|
||||
if (slugsLikeThis.Count() > 0) {
|
||||
//todo: (heskew) need better messages
|
||||
var originalSlug = post.Slug;
|
||||
post.Slug = _routableService.GenerateUniqueSlug(post.Slug, slugsLikeThis);
|
||||
|
||||
if (originalSlug != post.Slug)
|
||||
_orchardServices.Notifier.Warning(T("A different blog post is already published with this same slug ({0}) so a unique slug ({1}) was generated for this post.", originalSlug, post.Slug));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -9,6 +9,7 @@ using Orchard.Localization;
|
||||
using Orchard.Security;
|
||||
using Orchard.Settings;
|
||||
using Orchard.UI.Notify;
|
||||
using Orchard.Utility.Extensions;
|
||||
|
||||
namespace Orchard.Comments.Controllers {
|
||||
public class CommentController : Controller {
|
||||
@ -42,7 +43,15 @@ namespace Orchard.Comments.Controllers {
|
||||
|
||||
var viewModel = new CommentsCreateViewModel();
|
||||
try {
|
||||
UpdateModel(viewModel);
|
||||
|
||||
// UpdateModel(viewModel);
|
||||
|
||||
if(!TryUpdateModel(viewModel)) {
|
||||
if (Request.Form["Name"].IsNullOrEmptyTrimmed()) {
|
||||
_notifier.Error("You must provide a Name in order to comment");
|
||||
}
|
||||
return Redirect(returnUrl);
|
||||
}
|
||||
|
||||
var context = new CreateCommentContext {
|
||||
Author = viewModel.Name,
|
||||
@ -63,7 +72,8 @@ namespace Orchard.Comments.Controllers {
|
||||
}
|
||||
catch (Exception exception) {
|
||||
_notifier.Error(T("Creating Comment failed: " + exception.Message));
|
||||
return View(viewModel);
|
||||
// return View(viewModel);
|
||||
return Redirect(returnUrl);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -76,74 +76,11 @@ namespace Orchard.Pages.Drivers {
|
||||
protected override DriverResult Editor(Page page, IUpdateModel updater) {
|
||||
updater.TryUpdateModel(page, Prefix, null, null);
|
||||
|
||||
//todo: (heskew) something better needs to be done with this...still feels shoehorned in here
|
||||
ProcessSlug(page, updater);
|
||||
|
||||
DateTime scheduled;
|
||||
if (DateTime.TryParse(string.Format("{0} {1}", page.ScheduledPublishUtcDate, page.ScheduledPublishUtcTime), out scheduled))
|
||||
page.ScheduledPublishUtc = scheduled;
|
||||
|
||||
return Editor(page);
|
||||
}
|
||||
|
||||
private void ProcessSlug(Page page, IUpdateModel updater) {
|
||||
_routableService.FillSlug(page.As<RoutableAspect>(), Slugify);
|
||||
|
||||
if (string.IsNullOrEmpty(page.Slug)) {
|
||||
return;
|
||||
|
||||
// OR
|
||||
|
||||
//updater.AddModelError("Routable.Slug", T("The slug is required.").ToString());
|
||||
//return;
|
||||
}
|
||||
|
||||
if (!Regex.IsMatch(page.Slug, @"^[^/:?#\[\]@!$&'()*+,;=\s](?(?=/)/[^/:?#\[\]@!$&'()*+,;=\s]|[^:?#\[\]@!$&'()*+,;=\s])*$")) {
|
||||
updater.AddModelError("Routable.Slug", T("Please do not use any of the following characters in your slugs: \":\", \"?\", \"#\", \"[\", \"]\", \"@\", \"!\", \"$\", \"&\", \"'\", \"(\", \")\", \"*\", \"+\", \",\", \";\", \"=\". No spaces are allowed (please use dashes or underscores instead).").ToString());
|
||||
return;
|
||||
}
|
||||
|
||||
var slugsLikeThis = _pageService.Get(PageStatus.Published).Where(
|
||||
p => p.Slug.StartsWith(page.Slug, StringComparison.OrdinalIgnoreCase) &&
|
||||
p.Id != page.Id).Select(p => p.Slug);
|
||||
|
||||
if (slugsLikeThis.Count() > 0) {
|
||||
//todo: (heskew) need better messages
|
||||
Services.Notifier.Warning(T("A different page is already published with this same slug."));
|
||||
|
||||
if (page.ContentItem.VersionRecord == null || page.ContentItem.VersionRecord.Published) {
|
||||
var originalSlug = page.Slug;
|
||||
//todo: (heskew) make auto-uniqueness optional
|
||||
page.Slug = _routableService.GenerateUniqueSlug(page.Slug, slugsLikeThis);
|
||||
|
||||
//todo: (heskew) need better messages
|
||||
if (originalSlug != page.Slug)
|
||||
Services.Notifier.Warning(T("Slugs in conflict. \"{0}\" is already set for a previously published page so this page now has the slug \"{1}\"",
|
||||
originalSlug, page.Slug));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static string Slugify(string value)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(value))
|
||||
{
|
||||
//todo: (heskew) improve - just doing multi-pass regex replaces for now with the simple rules of
|
||||
// (1) can't begin with a '/', (2) can't have adjacent '/'s and (3) can't have these characters
|
||||
var startsoffbad = new Regex(@"^[\s/]+");
|
||||
var slashhappy = new Regex("/{2,}");
|
||||
var dissallowed = new Regex(@"[:?#\[\]@!$&'()*+,;=\s]+");
|
||||
|
||||
value = startsoffbad.Replace(value, "-");
|
||||
value = slashhappy.Replace(value, "/");
|
||||
value = dissallowed.Replace(value, "-");
|
||||
value = value.Trim('-');
|
||||
|
||||
if (value.Length > 1000)
|
||||
value = value.Substring(0, 1000);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
@ -15,12 +15,10 @@ namespace Orchard.Pages.Handlers {
|
||||
[UsedImplicitly]
|
||||
public class PageHandler : ContentHandler {
|
||||
private readonly IPageService _pageService;
|
||||
private readonly IRoutableService _routableService;
|
||||
private readonly IOrchardServices _orchardServices;
|
||||
|
||||
public PageHandler(IPageService pageService, IRoutableService routableService, IOrchardServices orchardServices) {
|
||||
public PageHandler(IPageService pageService, IOrchardServices orchardServices) {
|
||||
_pageService = pageService;
|
||||
_routableService = routableService;
|
||||
_orchardServices = orchardServices;
|
||||
T = NullLocalizer.Instance;
|
||||
|
||||
@ -31,27 +29,8 @@ namespace Orchard.Pages.Handlers {
|
||||
Filters.Add(new ActivatingFilter<BodyAspect>(PageDriver.ContentType.Name));
|
||||
|
||||
OnLoaded<Page>((context, p) => p.ScheduledPublishUtc = _pageService.GetScheduledPublishUtc(p));
|
||||
OnPublished<Page>((context, p) => ProcessSlug(p));
|
||||
}
|
||||
|
||||
Localizer T { get; set; }
|
||||
|
||||
private void ProcessSlug(Page page) {
|
||||
_routableService.FillSlug(page.As<RoutableAspect>());
|
||||
|
||||
var slugsLikeThis = _pageService.Get(PageStatus.Published).Where(
|
||||
p => p.Slug.StartsWith(page.Slug, StringComparison.OrdinalIgnoreCase) &&
|
||||
p.Id != page.Id).Select(p => p.Slug);
|
||||
|
||||
//todo: (heskew) need better messages
|
||||
if (slugsLikeThis.Count() > 0) {
|
||||
//todo: (heskew) need better messages
|
||||
var originalSlug = page.Slug;
|
||||
page.Slug = _routableService.GenerateUniqueSlug(page.Slug, slugsLikeThis);
|
||||
|
||||
if (originalSlug != page.Slug)
|
||||
_orchardServices.Notifier.Warning(T("A different page is already published with this same slug ({0}) so a unique slug ({1}) was generated for this page.", originalSlug, page.Slug));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Globalization;
|
||||
using Orchard.Localization;
|
||||
using System.Security.Principal;
|
||||
using System.Web.Mvc;
|
||||
using System.Web.Security;
|
||||
@ -26,9 +26,11 @@ namespace Orchard.Users.Controllers {
|
||||
_membershipService = membershipService;
|
||||
_userService = userService;
|
||||
Logger = NullLogger.Instance;
|
||||
T = NullLocalizer.Instance;
|
||||
}
|
||||
|
||||
public ILogger Logger { get; set; }
|
||||
public Localizer T { get; set; }
|
||||
|
||||
public ActionResult AccessDenied() {
|
||||
var returnUrl = Request.QueryString["ReturnUrl"];
|
||||
@ -55,8 +57,8 @@ namespace Orchard.Users.Controllers {
|
||||
[HttpPost]
|
||||
[SuppressMessage("Microsoft.Design", "CA1054:UriParametersShouldNotBeStrings",
|
||||
Justification = "Needs to take same parameter type as Controller.Redirect()")]
|
||||
public ActionResult LogOn(string userName, string password, bool rememberMe) {
|
||||
var user = ValidateLogOn(userName, password);
|
||||
public ActionResult LogOn(string userNameOrEmail, string password, bool rememberMe) {
|
||||
var user = ValidateLogOn(userNameOrEmail, password);
|
||||
if (!ModelState.IsValid) {
|
||||
return View("LogOn", new LogOnViewModel {Title = "Log On"});
|
||||
}
|
||||
@ -98,7 +100,7 @@ namespace Orchard.Users.Controllers {
|
||||
return Redirect("~/");
|
||||
}
|
||||
else {
|
||||
ModelState.AddModelError("_FORM", ErrorCodeToString(/*createStatus*/MembershipCreateStatus.ProviderError));
|
||||
ModelState.AddModelError("_FORM", T(ErrorCodeToString(/*createStatus*/MembershipCreateStatus.ProviderError)));
|
||||
}
|
||||
}
|
||||
|
||||
@ -133,12 +135,12 @@ namespace Orchard.Users.Controllers {
|
||||
}
|
||||
else {
|
||||
ModelState.AddModelError("_FORM",
|
||||
"The current password is incorrect or the new password is invalid.");
|
||||
T("The current password is incorrect or the new password is invalid."));
|
||||
return ChangePassword();
|
||||
}
|
||||
}
|
||||
catch {
|
||||
ModelState.AddModelError("_FORM", "The current password is incorrect or the new password is invalid.");
|
||||
ModelState.AddModelError("_FORM", T("The current password is incorrect or the new password is invalid."));
|
||||
return ChangePassword();
|
||||
}
|
||||
}
|
||||
@ -157,32 +159,29 @@ namespace Orchard.Users.Controllers {
|
||||
|
||||
private bool ValidateChangePassword(string currentPassword, string newPassword, string confirmPassword) {
|
||||
if (String.IsNullOrEmpty(currentPassword)) {
|
||||
ModelState.AddModelError("currentPassword", "You must specify a current password.");
|
||||
ModelState.AddModelError("currentPassword", T("You must specify a current password."));
|
||||
}
|
||||
if (newPassword == null || newPassword.Length < MinPasswordLength) {
|
||||
ModelState.AddModelError("newPassword",
|
||||
String.Format(CultureInfo.CurrentCulture,
|
||||
"You must specify a new password of {0} or more characters.",
|
||||
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", "The new password and confirmation password do not match.");
|
||||
ModelState.AddModelError("_FORM", T("The new password and confirmation password do not match."));
|
||||
}
|
||||
|
||||
return ModelState.IsValid;
|
||||
}
|
||||
|
||||
private IUser ValidateLogOn(string userName, string password) {
|
||||
if (String.IsNullOrEmpty(userName)) {
|
||||
ModelState.AddModelError("username", "You must specify a username.");
|
||||
private IUser ValidateLogOn(string userNameOrEmail, string password) {
|
||||
if (String.IsNullOrEmpty(userNameOrEmail)) {
|
||||
ModelState.AddModelError("userNameOrEmail", T("You must specify a username or e-mail."));
|
||||
}
|
||||
if (String.IsNullOrEmpty(password)) {
|
||||
ModelState.AddModelError("password", "You must specify a password.");
|
||||
ModelState.AddModelError("password", T("You must specify a password."));
|
||||
}
|
||||
var user = _membershipService.ValidateUser(userName, password);
|
||||
var user = _membershipService.ValidateUser(userNameOrEmail, password);
|
||||
if (user == null) {
|
||||
ModelState.AddModelError("_FORM", "The username or password provided is incorrect.");
|
||||
ModelState.AddModelError("_FORM", T("The username or e-mail or password provided is incorrect."));
|
||||
}
|
||||
|
||||
return user;
|
||||
@ -190,23 +189,20 @@ namespace Orchard.Users.Controllers {
|
||||
|
||||
private bool ValidateRegistration(string userName, string email, string password, string confirmPassword) {
|
||||
if (String.IsNullOrEmpty(userName)) {
|
||||
ModelState.AddModelError("username", "You must specify a username.");
|
||||
ModelState.AddModelError("username", T("You must specify a username."));
|
||||
}
|
||||
if (String.IsNullOrEmpty(email)) {
|
||||
ModelState.AddModelError("email", "You must specify an email address.");
|
||||
ModelState.AddModelError("email", T("You must specify an email address."));
|
||||
}
|
||||
string userUnicityMessage = _userService.VerifyUserUnicity(userName, email);
|
||||
if (userUnicityMessage != null) {
|
||||
ModelState.AddModelError("userExists", userUnicityMessage);
|
||||
ModelState.AddModelError("userExists", T(userUnicityMessage));
|
||||
}
|
||||
if (password == null || password.Length < MinPasswordLength) {
|
||||
ModelState.AddModelError("password",
|
||||
String.Format(CultureInfo.CurrentCulture,
|
||||
"You must specify a password of {0} or more characters.",
|
||||
MinPasswordLength));
|
||||
ModelState.AddModelError("password", T("You must specify a password of {0} or more characters.", MinPasswordLength));
|
||||
}
|
||||
if (!String.Equals(password, confirmPassword, StringComparison.Ordinal)) {
|
||||
ModelState.AddModelError("_FORM", "The new password and confirmation password do not match.");
|
||||
ModelState.AddModelError("_FORM", T("The new password and confirmation password do not match."));
|
||||
}
|
||||
return ModelState.IsValid;
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
using System.Linq;
|
||||
using System.Web.Mvc;
|
||||
using Orchard.Localization;
|
||||
using Orchard.ContentManagement;
|
||||
using Orchard.Localization;
|
||||
using Orchard.Security;
|
||||
using Orchard.UI.Notify;
|
||||
using Orchard.Users.Drivers;
|
||||
@ -147,6 +147,7 @@ namespace Orchard.Users.Controllers {
|
||||
bool IUpdateModel.TryUpdateModel<TModel>(TModel model, string prefix, string[] includeProperties, string[] excludeProperties) {
|
||||
return TryUpdateModel(model, prefix, includeProperties, excludeProperties);
|
||||
}
|
||||
|
||||
public void AddModelError(string key, LocalizedString errorMessage) {
|
||||
ModelState.AddModelError(key, errorMessage.ToString());
|
||||
}
|
||||
|
@ -44,6 +44,9 @@ namespace Orchard.Users.Services {
|
||||
}
|
||||
|
||||
public IUser GetUser(string username) {
|
||||
if(username == null) {
|
||||
throw new ArgumentNullException("username");
|
||||
}
|
||||
var userRecord = _userRepository.Get(x => x.NormalizedUserName == username.ToLower());
|
||||
if (userRecord == null) {
|
||||
return null;
|
||||
@ -51,8 +54,10 @@ namespace Orchard.Users.Services {
|
||||
return _contentManager.Get<IUser>(userRecord.Id);
|
||||
}
|
||||
|
||||
public IUser ValidateUser(string username, string password) {
|
||||
var userRecord = _userRepository.Get(x => x.NormalizedUserName == username.ToLower());
|
||||
public IUser ValidateUser(string userNameOrEmail, string password) {
|
||||
var userRecord = _userRepository.Get(x => x.NormalizedUserName == userNameOrEmail.ToLower());
|
||||
if(userRecord == null)
|
||||
userRecord = _userRepository.Get(x => x.Email == userNameOrEmail.ToLower());
|
||||
if (userRecord == null || ValidatePassword(userRecord, password) == false)
|
||||
return null;
|
||||
|
||||
|
@ -8,9 +8,9 @@ using (Html.BeginFormAntiForgeryPost(Url.Action("LogOn", new {ReturnUrl = Reques
|
||||
<fieldset>
|
||||
<legend><%=_Encoded("Account Information")%></legend>
|
||||
<div>
|
||||
<label for="username"><%=_Encoded("Username:")%></label>
|
||||
<%= Html.TextBox("username")%>
|
||||
<%= Html.ValidationMessage("username")%>
|
||||
<label for="username"><%=_Encoded("Username or Email:")%></label>
|
||||
<%= Html.TextBox("userNameOrEmail")%>
|
||||
<%= Html.ValidationMessage("userNameOrEmail")%>
|
||||
</div>
|
||||
<div>
|
||||
<label for="password"><%=_Encoded("Password:")%></label>
|
||||
|
11
src/Orchard/Mvc/Extensions/ModelStateDictionaryExtensions.cs
Normal file
11
src/Orchard/Mvc/Extensions/ModelStateDictionaryExtensions.cs
Normal file
@ -0,0 +1,11 @@
|
||||
using System;
|
||||
using System.Web.Mvc;
|
||||
using Orchard.Localization;
|
||||
|
||||
namespace Orchard.Mvc.Extensions {
|
||||
public static class ModelStateDictionaryExtensions {
|
||||
public static void AddModelError(this ModelStateDictionary modelStateDictionary, string key, LocalizedString errorMessage) {
|
||||
modelStateDictionary.AddModelError(key, errorMessage.ToString());
|
||||
}
|
||||
}
|
||||
}
|
@ -195,6 +195,7 @@
|
||||
<Compile Include="Modules\IModuleService.cs" />
|
||||
<Compile Include="Mvc\AntiForgery\ValidateAntiForgeryTokenOrchardAttribute.cs" />
|
||||
<Compile Include="Mvc\Extensions\ControllerExtensions.cs" />
|
||||
<Compile Include="Mvc\Extensions\ModelStateDictionaryExtensions.cs" />
|
||||
<Compile Include="Mvc\Html\FileRegistrationContextExtensions.cs" />
|
||||
<Compile Include="Mvc\Extensions\UrlHelperExtensions.cs" />
|
||||
<Compile Include="Mvc\IHasRequestContext.cs" />
|
||||
|
@ -5,7 +5,7 @@
|
||||
IUser CreateUser(CreateUserParams createUserParams);
|
||||
IUser GetUser(string username);
|
||||
|
||||
IUser ValidateUser(string username, string password);
|
||||
IUser ValidateUser(string userNameOrEmail, string password);
|
||||
void SetPassword(IUser user, string password);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user