diff --git a/src/Orchard.Tests.Modules/Orchard.Tests.Modules.csproj b/src/Orchard.Tests.Modules/Orchard.Tests.Modules.csproj index 0f42c0a5d..b7db352a3 100644 --- a/src/Orchard.Tests.Modules/Orchard.Tests.Modules.csproj +++ b/src/Orchard.Tests.Modules/Orchard.Tests.Modules.csproj @@ -166,7 +166,6 @@ - diff --git a/src/Orchard.Tests.Modules/Users/Controllers/AdminControllerTests.cs b/src/Orchard.Tests.Modules/Users/Controllers/AdminControllerTests.cs deleted file mode 100644 index 16daa1b90..000000000 --- a/src/Orchard.Tests.Modules/Users/Controllers/AdminControllerTests.cs +++ /dev/null @@ -1,170 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Web; -using System.Web.Mvc; -using System.Web.Routing; -using System.Xml.Linq; -using Autofac; -using Moq; -using NUnit.Framework; -using Orchard.Caching; -using Orchard.ContentManagement.MetaData; -using Orchard.ContentManagement.MetaData.Models; -using Orchard.ContentManagement.MetaData.Services; -using Orchard.Core.Settings.Metadata; -using Orchard.Data; -using Orchard.DisplayManagement; -using Orchard.DisplayManagement.Descriptors; -using Orchard.DisplayManagement.Implementation; -using Orchard.Environment; -using Orchard.ContentManagement; -using Orchard.ContentManagement.Handlers; -using Orchard.ContentManagement.Records; -using Orchard.Environment.Extensions; -using Orchard.Localization; -using Orchard.Messaging.Events; -using Orchard.Messaging.Services; -using Orchard.Security; -using Orchard.Security.Permissions; -using Orchard.Security.Providers; -using Orchard.Tests.Stubs; -using Orchard.UI.Notify; -using Orchard.Users.Controllers; -using Orchard.Users.Handlers; -using Orchard.Users.Models; -using Orchard.Users.Services; -using Orchard.Users.ViewModels; -using Orchard.Settings; -using Orchard.Core.Settings.Services; - -namespace Orchard.Tests.Modules.Users.Controllers { - [TestFixture] - public class AdminControllerTests : DatabaseEnabledTestsBase { - private AdminController _controller; - private Mock _authorizer; - - public override void Register(ContainerBuilder builder) { - builder.RegisterType().SingleInstance(); - builder.RegisterType().As(); - builder.RegisterType().As(); - builder.RegisterType().As(); - builder.RegisterType(typeof(SettingsFormatter)) - .As(typeof(IMapper)) - .As(typeof(IMapper)); - builder.RegisterType().As(); - builder.RegisterType().As(); - builder.RegisterType().As().InstancePerDependency(); - builder.RegisterType().As(); - builder.RegisterInstance(new Mock().Object); - builder.RegisterType().As(); - builder.RegisterType().As(); - builder.RegisterType().As(); - builder.RegisterType().As(); - builder.RegisterType().As(); - builder.RegisterType().As(); - builder.RegisterType().As(); - builder.RegisterType().As(); - builder.RegisterType().As(); - builder.RegisterInstance(new Mock().Object); - builder.RegisterInstance(new Mock().Object); - builder.RegisterType().As(); - builder.RegisterType().As(); - builder.RegisterType().As(); - builder.RegisterInstance(ShellSettingsUtility.CreateEncryptionEnabled()); - - _authorizer = new Mock(); - builder.RegisterInstance(_authorizer.Object); - } - - protected override IEnumerable DatabaseTypes { - get { - return new[] { typeof(UserPartRecord), - typeof(ContentTypeRecord), - typeof(ContentItemRecord), - typeof(ContentItemVersionRecord), - }; - } - } - - public override void Init() { - base.Init(); - - var manager = _container.Resolve(); - - var userOne = manager.New("User"); - userOne.Record = new UserPartRecord { UserName = "one" }; - manager.Create(userOne.ContentItem); - - var userTwo = manager.New("User"); - userTwo.Record = new UserPartRecord { UserName = "two" }; - manager.Create(userTwo.ContentItem); - - var userThree = manager.New("User"); - userThree.Record = new UserPartRecord { UserName = "three" }; - manager.Create(userThree.ContentItem); - - _controller = _container.Resolve(); - - var mockHttpContext = new Mock(); - _controller.ControllerContext = new ControllerContext( - mockHttpContext.Object, - new RouteData( - new Route("foo", new MvcRouteHandler()), - new MvcRouteHandler()), - _controller); - } - - [Test] - public void IndexShouldReturnRowsForUsers() { - _authorizer.Setup(x => x.Authorize(It.IsAny(), It.IsAny())).Returns(true); - - var controller = _container.Resolve(); - var result = (ViewResult)controller.Index(); - var model = (UsersIndexViewModel)result.ViewData.Model; - - Assert.That(model.Rows, Is.Not.Null); - } - - - [Test] - [Ignore("Needs to instead be a specflow test.")] - public void CreateShouldAddUserAndRedirect() { - _authorizer.Setup(x => x.Authorize(It.IsAny(), It.IsAny())).Returns(true); - - var controller = _container.Resolve(); - ActionResult result = null; // controller.CreatePOST(new UserCreateViewModel { - // UserName = "four", - // Email = "six@example.org", - // Password = "five", - // ConfirmPassword = "five" - //}); - Assert.That(result, Is.TypeOf()); - - var redirect = (RedirectToRouteResult)result; - var id = Convert.ToInt32(redirect.RouteValues["id"]); - var manager = _container.Resolve(); - var user = manager.Get(id).As(); - Assert.That(user.UserName, Is.EqualTo("four")); - } - - [Test] - [Ignore("Needs fixing. Needs to instead be a specflow test.")] - public void EditShouldDisplayUserAndStoreChanges() { - _authorizer.Setup(x => x.Authorize(It.IsAny(), It.IsAny())).Returns(true); - - var repository = _container.Resolve>(); - var id = repository.Get(x => x.UserName == "two").Id; - var result = (ViewResult)_container.Resolve().Edit(id); - var model = (UserEditViewModel)result.ViewData.Model; - //Assert.That(model.UserName, Is.EqualTo("two")); - - var controller = _container.Resolve(); - controller.ValueProvider = Values.From(new { - UserName = "bubba", - Email = "hotep", - }); - var result2 = controller.EditPOST(id); - Assert.That(result2, Is.TypeOf()); - } - } -} diff --git a/src/Orchard.Web/Modules/Orchard.Users/Controllers/AdminController.cs b/src/Orchard.Web/Modules/Orchard.Users/Controllers/AdminController.cs index 9da562383..a163d8ab3 100644 --- a/src/Orchard.Web/Modules/Orchard.Users/Controllers/AdminController.cs +++ b/src/Orchard.Web/Modules/Orchard.Users/Controllers/AdminController.cs @@ -1,6 +1,9 @@ +using System.Collections.Generic; using System.Linq; using System.Web.Mvc; using Orchard.ContentManagement; +using Orchard.Core.Common.Models; +using Orchard.Core.Contents.Controllers; using Orchard.Core.Settings.Models; using Orchard.DisplayManagement; using Orchard.Localization; @@ -12,6 +15,7 @@ using Orchard.Users.ViewModels; using Orchard.Mvc.Extensions; using System; using Orchard.Settings; +using Orchard.UI.Navigation; namespace Orchard.Users.Controllers { [ValidateInput(false)] @@ -39,24 +43,99 @@ namespace Orchard.Users.Controllers { public IOrchardServices Services { get; set; } public Localizer T { get; set; } - public ActionResult Index() { + public ActionResult Index(UserIndexOptions options, PagerParameters pagerParameters) { if (!Services.Authorizer.Authorize(StandardPermissions.SiteOwner, T("Not authorized to list users"))) return new HttpUnauthorizedResult(); + var pager = new Pager(_siteService.GetSiteSettings(), pagerParameters); + + // default options + if (options == null) + options = new UserIndexOptions(); + var users = Services.ContentManager - .Query() - .Where(x => x.UserName != null) - .List(); + .Query(); + + switch (options.Filter) { + case UsersFilter.Approved: + users = users.Where(u => u.RegistrationStatus == UserStatus.Approved); + break; + case UsersFilter.Pending: + users = users.Where(u => u.RegistrationStatus == UserStatus.Pending); + break; + case UsersFilter.EmailPending: + users = users.Where(u => u.EmailStatus == UserStatus.Approved); + break; + } + + if(!String.IsNullOrWhiteSpace(options.Search)) { + users = users.Where(u => u.UserName.Contains(options.Search) || u.Email.Contains(options.Search)); + } + + var pagerShape = Shape.Pager(pager).TotalItemCount(users.Count()); + + switch (options.Order) { + case UsersOrder.Name: + users = users.OrderBy(u => u.UserName); + break; + case UsersOrder.Email: + users = users.OrderBy(u => u.Email); + break; + } + + var results = users + .Slice(pager.GetStartIndex(), pager.PageSize) + .ToList(); var model = new UsersIndexViewModel { - Rows = users - .Select(x => new UsersIndexViewModel.Row { UserPart = x }) - .ToList() + Users = results + .Select(x => new UserEntry { User = x.Record }) + .ToList(), + Options = options, + Pager = pagerShape }; return View(model); } + [HttpPost] + [FormValueRequired("submit.BulkEdit")] + public ActionResult Index(FormCollection input) { + if (!Services.Authorizer.Authorize(StandardPermissions.SiteOwner, T("Not authorized to manage users"))) + return new HttpUnauthorizedResult(); + + var viewModel = new UsersIndexViewModel {Users = new List(), Options = new UserIndexOptions()}; + UpdateModel(viewModel); + + var checkedEntries = viewModel.Users.Where(c => c.IsChecked); + switch (viewModel.Options.BulkAction) { + case UsersBulkAction.None: + break; + case UsersBulkAction.Approve: + foreach (var entry in checkedEntries) { + Approve(entry.User.Id); + } + break; + case UsersBulkAction.Disable: + foreach (var entry in checkedEntries) { + Moderate(entry.User.Id); + } + break; + case UsersBulkAction.ChallengeEmail: + foreach (var entry in checkedEntries) { + SendChallengeEmail(entry.User.Id); + } + break; + case UsersBulkAction.Delete: + foreach (var entry in checkedEntries) { + Delete(entry.User.Id); + } + break; + } + + return RedirectToAction("Index"); + } + public ActionResult Create() { if (!Services.Authorizer.Authorize(StandardPermissions.SiteOwner, T("Not authorized to manage users"))) return new HttpUnauthorizedResult(); @@ -109,7 +188,7 @@ namespace Orchard.Users.Controllers { } Services.Notifier.Information(T("User created")); - return RedirectToAction("edit", new { user.Id }); + return RedirectToAction("Index"); } public ActionResult Edit(int id) { @@ -163,7 +242,7 @@ namespace Orchard.Users.Controllers { } Services.Notifier.Information(T("User information updated")); - return RedirectToAction("Edit", new { id }); + return RedirectToAction("Index"); } public ActionResult Delete(int id) { @@ -181,7 +260,7 @@ namespace Orchard.Users.Controllers { } else{ Services.ContentManager.Remove(user.ContentItem); - Services.Notifier.Information(T("User deleted")); + Services.Notifier.Information(T("User {0} deleted", user.UserName)); } } @@ -192,13 +271,13 @@ namespace Orchard.Users.Controllers { if (!Services.Authorizer.Authorize(StandardPermissions.SiteOwner, T("Not authorized to manage users"))) return new HttpUnauthorizedResult(); - var user = Services.ContentManager.Get(id); + var user = Services.ContentManager.Get(id); if ( user != null ) { _userService.SendChallengeEmail(user.As(), nonce => Url.AbsoluteAction(() => Url.Action("ChallengeEmail", "Account", new {Area = "Orchard.Users", nonce = nonce}))); + Services.Notifier.Information(T("Challenge email sent to {0}", user.UserName)); } - Services.Notifier.Information(T("Challenge email sent")); return RedirectToAction("Index"); } @@ -207,11 +286,11 @@ namespace Orchard.Users.Controllers { if (!Services.Authorizer.Authorize(StandardPermissions.SiteOwner, T("Not authorized to manage users"))) return new HttpUnauthorizedResult(); - var user = Services.ContentManager.Get(id); + var user = Services.ContentManager.Get(id); if ( user != null ) { user.As().RegistrationStatus = UserStatus.Approved; - Services.Notifier.Information(T("User approved")); + Services.Notifier.Information(T("User {0} approved", user.UserName)); } return RedirectToAction("Index"); diff --git a/src/Orchard.Web/Modules/Orchard.Users/ViewModels/UsersIndexViewModel.cs b/src/Orchard.Web/Modules/Orchard.Users/ViewModels/UsersIndexViewModel.cs index a77c65bee..051ee9da3 100644 --- a/src/Orchard.Web/Modules/Orchard.Users/ViewModels/UsersIndexViewModel.cs +++ b/src/Orchard.Web/Modules/Orchard.Users/ViewModels/UsersIndexViewModel.cs @@ -4,10 +4,40 @@ using Orchard.Users.Models; namespace Orchard.Users.ViewModels { public class UsersIndexViewModel { - public class Row { - public UserPart UserPart { get; set; } - } + public IList Users { get; set; } + public UserIndexOptions Options { get; set; } + public dynamic Pager { get; set; } + } - public IList Rows { get; set; } + public class UserEntry { + public UserPartRecord User { get; set; } + public bool IsChecked { get; set; } + } + + public class UserIndexOptions { + public string Search { get; set; } + public UsersOrder Order { get; set; } + public UsersFilter Filter { get; set; } + public UsersBulkAction BulkAction { get; set; } + } + + public enum UsersOrder { + Name, + Email + } + + public enum UsersFilter { + All, + Approved, + Pending, + EmailPending + } + + public enum UsersBulkAction { + None, + Delete, + Disable, + Approve, + ChallengeEmail } } diff --git a/src/Orchard.Web/Modules/Orchard.Users/Views/Admin/Index.cshtml b/src/Orchard.Web/Modules/Orchard.Users/Views/Admin/Index.cshtml index 684d319a4..37f37cc1e 100644 --- a/src/Orchard.Web/Modules/Orchard.Users/Views/Admin/Index.cshtml +++ b/src/Orchard.Web/Modules/Orchard.Users/Views/Admin/Index.cshtml @@ -1,52 +1,88 @@ @model Orchard.Users.ViewModels.UsersIndexViewModel @using Orchard.Users.Models; +@using Orchard.Users.ViewModels; + +@{ + var userIndex = 0; +}

@Html.TitleForPage(T("Manage Users").ToString())

@using (Html.BeginFormAntiForgeryPost()) { @Html.ValidationSummary()
@Html.ActionLink(T("Add a new user").ToString(), "Create", new { }, new { @class = "button primaryAction" })
-
+ +
+ + + +
+
+ @Html.TextBoxFor(m => m.Options.Search, new { @class = "text"}) + + + + + +
+
- - - - - + - + - @foreach (var row in Model.Rows) { - + @foreach (var entry in Model.Users) { + + - } + userIndex++; + }
 ↓ @T("Name") @T("Email")@T("") @T("Actions")
- @if(row.UserPart.RegistrationStatus == UserStatus.Approved && row.UserPart.EmailStatus == UserStatus.Approved) { + + + + @if(entry.User.RegistrationStatus == UserStatus.Approved && entry.User.EmailStatus == UserStatus.Approved) { @T( } else { - @T( + @T( } - @Html.ActionLink(row.UserPart.UserName, "Edit", new { row.UserPart.Id }) + @Html.ActionLink(entry.User.UserName, "Edit", new { entry.User.Id }) - @row.UserPart.Email + @entry.User.Email - @Html.ActionLink(T("Edit").ToString(), "Edit", new { row.UserPart.Id }) | - @Html.ActionLink(T("Remove").ToString(), "Delete", new { row.UserPart.Id }) | - @if(row.UserPart.RegistrationStatus == UserStatus.Pending) { - @Html.ActionLink(T("Approve").ToString(), "Approve", new { row.UserPart.Id }) + @Html.ActionLink(T("Edit").ToString(), "Edit", new { entry.User.Id }) | + @Html.ActionLink(T("Remove").ToString(), "Delete", new { entry.User.Id }) | + @if(entry.User.RegistrationStatus == UserStatus.Pending) { + @Html.ActionLink(T("Approve").ToString(), "Approve", new { entry.User.Id }) } else { - @Html.ActionLink(T("Disable").ToString(), "Moderate", new { row.UserPart.Id }) + @Html.ActionLink(T("Disable").ToString(), "Moderate", new { entry.User.Id }) } - @if ( row.UserPart.EmailStatus == UserStatus.Pending ) { | - @Html.ActionLink(T("Send challenge E-mail").ToString(), "SendChallengeEmail", new { row.UserPart.Id }) + @if ( entry.User.EmailStatus == UserStatus.Pending ) { | + @Html.ActionLink(T("Send challenge E-mail").ToString(), "SendChallengeEmail", new { entry.User.Id }) }
+ @T.Plural("No user found", "{1} users found", (int)Model.Pager.TotalItemCount + 1, (int)Model.Pager.TotalItemCount) + @Display(Model.Pager)
} \ No newline at end of file