diff --git a/src/MusicStore.Spa/Apis/AlbumsApiController.cs b/src/MusicStore.Spa/Apis/AlbumsApiController.cs index d8051cecaf..124238c739 100644 --- a/src/MusicStore.Spa/Apis/AlbumsApiController.cs +++ b/src/MusicStore.Spa/Apis/AlbumsApiController.cs @@ -1,5 +1,4 @@ using System.Linq; -using System.Security.Claims; using System.Threading.Tasks; using Microsoft.AspNet.Mvc; using MusicStore.Infrastructure; @@ -23,8 +22,7 @@ namespace MusicStore.Apis var albums = await _storeContext.Albums //.Include(a => a.Genre) //.Include(a => a.Artist) - .SortBy(sortBy, a => a.Title) - .ToPagedListAsync(page, pageSize); + .ToPagedListAsync(page, pageSize, sortBy, a => a.Title); return Json(albums); } @@ -72,8 +70,7 @@ namespace MusicStore.Apis } [HttpPost] - //[Authorize(Roles = "Administrator")] - [Authorize(ClaimTypes.Role, "Administrator")] + [Authorize("ManageStore", "Allowed")] public async Task CreateAlbum() { var album = new Album(); @@ -99,8 +96,7 @@ namespace MusicStore.Apis } [HttpPut("{albumId:int}/update")] - //[Authorize(Roles = "Administrator")] - [Authorize(ClaimTypes.Role, "Administrator")] + [Authorize("ManageStore", "Allowed")] public async Task UpdateAlbum(int albumId) { var album = _storeContext.Albums.SingleOrDefault(a => a.AlbumId == albumId); @@ -133,11 +129,11 @@ namespace MusicStore.Apis } [HttpDelete("{albumId:int}")] - //[Authorize(Roles = "Administrator")] - [Authorize(ClaimTypes.Role, "Administrator")] + [Authorize("ManageStore", "Allowed")] public async Task DeleteAlbum(int albumId) { - var album = await _storeContext.Albums.SingleOrDefaultAsync(a => a.AlbumId == albumId); + //var album = await _storeContext.Albums.SingleOrDefaultAsync(a => a.AlbumId == albumId); + var album = _storeContext.Albums.SingleOrDefault(a => a.AlbumId == albumId); if (album != null) { diff --git a/src/MusicStore.Spa/Controllers/AccountController.cs b/src/MusicStore.Spa/Controllers/AccountController.cs index 2b1fc5c249..51b565da18 100644 --- a/src/MusicStore.Spa/Controllers/AccountController.cs +++ b/src/MusicStore.Spa/Controllers/AccountController.cs @@ -7,6 +7,7 @@ using MusicStore.Models; namespace MusicStore.Controllers { + [Route("account")] [Authorize] public class AccountController : Controller { @@ -20,20 +21,16 @@ namespace MusicStore.Controllers public SignInManager SignInManager { get; private set; } - // - // GET: /Account/Login [AllowAnonymous] //Bug: https://github.com/aspnet/WebFx/issues/339 - [HttpGet] + [HttpGet("login")] public IActionResult Login(string returnUrl) { ViewBag.ReturnUrl = returnUrl; return View(); } - // - // POST: /Account/Login - [HttpPost] + [HttpPost("login")] [AllowAnonymous] [ValidateAntiForgeryToken] public async Task Login(LoginViewModel model, string returnUrl) @@ -59,19 +56,15 @@ namespace MusicStore.Controllers return View(model); } - // - // GET: /Account/Register [AllowAnonymous] //Bug: https://github.com/aspnet/WebFx/issues/339 - [HttpGet] + [HttpGet("register")] public IActionResult Register() { return View(); } - // - // POST: /Account/Register - [HttpPost] + [HttpPost("register")] [AllowAnonymous] [ValidateAntiForgeryToken] public async Task Register(RegisterViewModel model) @@ -84,7 +77,7 @@ namespace MusicStore.Controllers if (result.Succeeded) { await SignInManager.SignInAsync(user, isPersistent: false); - return RedirectToAction("Index", "Home"); + return RedirectToAction("Home", "Page"); } else { @@ -96,9 +89,7 @@ namespace MusicStore.Controllers return View(model); } - // - // GET: /Account/Manage - [HttpGet] + [HttpGet("manage")] public IActionResult Manage(ManageMessageId? message = null) { ViewBag.StatusMessage = @@ -109,9 +100,7 @@ namespace MusicStore.Controllers return View(); } - // - // POST: /Account/Manage - [HttpPost] + [HttpPost("manage")] [ValidateAntiForgeryToken] public async Task Manage(ManageUserViewModel model) { @@ -135,14 +124,12 @@ namespace MusicStore.Controllers return View(model); } - // - // POST: /Account/LogOff - [HttpPost] + [HttpPost("logoff")] [ValidateAntiForgeryToken] public IActionResult LogOff() { SignInManager.SignOut(); - return RedirectToAction("Index", "Home"); + return RedirectToAction("Home", "Page"); } #region Helpers diff --git a/src/MusicStore.Spa/Controllers/HomeController.cs b/src/MusicStore.Spa/Controllers/HomeController.cs deleted file mode 100644 index 47c25ab519..0000000000 --- a/src/MusicStore.Spa/Controllers/HomeController.cs +++ /dev/null @@ -1,12 +0,0 @@ -using Microsoft.AspNet.Mvc; - -namespace MusicStore.Controllers -{ - public class HomeController : Controller - { - public IActionResult Index() - { - return View(); - } - } -} \ No newline at end of file diff --git a/src/MusicStore.Spa/Controllers/PageController.cs b/src/MusicStore.Spa/Controllers/PageController.cs new file mode 100644 index 0000000000..e25377f6eb --- /dev/null +++ b/src/MusicStore.Spa/Controllers/PageController.cs @@ -0,0 +1,22 @@ +using System.Security.Claims; +using Microsoft.AspNet.Mvc; + +namespace MusicStore.Spa.Controllers +{ + [Route("/")] + public class PageController : Controller + { + [HttpGet] + public IActionResult Home() + { + return View("/Pages/Home.cshtml"); + } + + [HttpGet("admin")] + [Authorize("ManageStore", "Allowed")] + public IActionResult Admin() + { + return View("/Pages/Admin.cshtml"); + } + } +} diff --git a/src/MusicStore.Spa/Infrastructure/ApiResult.cs b/src/MusicStore.Spa/Infrastructure/ApiResult.cs index f43848d021..4460e360f7 100644 --- a/src/MusicStore.Spa/Infrastructure/ApiResult.cs +++ b/src/MusicStore.Spa/Infrastructure/ApiResult.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Threading.Tasks; using Microsoft.AspNet.Mvc.ModelBinding; using Newtonsoft.Json; @@ -40,7 +41,7 @@ namespace Microsoft.AspNet.Mvc [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] public IEnumerable ModelErrors { get; set; } - public override void ExecuteResult(ActionContext context) + public override Task ExecuteResultAsync(ActionContext context) { if (StatusCode.HasValue) { @@ -48,7 +49,7 @@ namespace Microsoft.AspNet.Mvc } var json = new JsonResult(this); - json.ExecuteResult(context); + return json.ExecuteResultAsync(context); } public class ModelError diff --git a/src/MusicStore.Spa/Infrastructure/PagedList.cs b/src/MusicStore.Spa/Infrastructure/PagedList.cs index 59bc66ab40..78bd7d45fd 100644 --- a/src/MusicStore.Spa/Infrastructure/PagedList.cs +++ b/src/MusicStore.Spa/Infrastructure/PagedList.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Linq.Expressions; using System.Threading.Tasks; namespace MusicStore.Infrastructure @@ -64,7 +65,8 @@ namespace MusicStore.Infrastructure return new PagedList(data, pagingConfig.Page, pagingConfig.PageSize, query.Count()); } - public static async Task> ToPagedListAsync(this IQueryable query, int page, int pageSize) + public static async Task> ToPagedListAsync(this IQueryable query, int page, int pageSize, string sortExpression, Expression> defaultSortExpression, SortDirection defaultSortDirection = SortDirection.Ascending) + where TModel : class { if (query == null) { @@ -73,8 +75,15 @@ namespace MusicStore.Infrastructure var pagingConfig = new PagingConfig(page, pageSize); var skipCount = ValidatePagePropertiesAndGetSkipCount(pagingConfig); + var dataQuery = query; - var data = await query + if (defaultSortExpression != null) + { + dataQuery = dataQuery + .SortBy(sortExpression, defaultSortExpression); + } + + var data = await dataQuery .Skip(skipCount) .Take(pagingConfig.PageSize) .ToListAsync(); @@ -83,12 +92,14 @@ namespace MusicStore.Infrastructure { // Requested page has no records, just return the first page pagingConfig.Page = 1; - data = await query + data = await dataQuery .Take(pagingConfig.PageSize) .ToListAsync(); } - return new PagedList(data, pagingConfig.Page, pagingConfig.PageSize, await query.CountAsync()); + var count = await query.CountAsync(); + + return new PagedList(data, pagingConfig.Page, pagingConfig.PageSize, count); } private static int ValidatePagePropertiesAndGetSkipCount(PagingConfig pagingConfig) diff --git a/src/MusicStore.Spa/Models/SampleData.cs b/src/MusicStore.Spa/Models/SampleData.cs index 355f698c21..6c845ba701 100644 --- a/src/MusicStore.Spa/Models/SampleData.cs +++ b/src/MusicStore.Spa/Models/SampleData.cs @@ -56,22 +56,22 @@ namespace MusicStore.Models private static async Task CreateAdminUser(IServiceProvider serviceProvider) { var options = serviceProvider.GetService>().Options; - //const string adminRole = "Administrator"; + const string adminRole = "Administrator"; var userManager = serviceProvider.GetService>(); - // TODO: Identity SQL does not support roles yet - //var roleManager = serviceProvider.GetService(); - //if (!await roleManager.RoleExistsAsync(adminRole)) - //{ - // await roleManager.CreateAsync(new IdentityRole(adminRole)); - //} + var roleManager = serviceProvider.GetService>(); + + if (!await roleManager.RoleExistsAsync(adminRole)) + { + await roleManager.CreateAsync(new IdentityRole(adminRole)); + } var user = await userManager.FindByNameAsync(options.DefaultAdminUserName); if (user == null) { user = new ApplicationUser { UserName = options.DefaultAdminUserName }; await userManager.CreateAsync(user, options.DefaultAdminPassword); - //await userManager.AddToRoleAsync(user, adminRole); + await userManager.AddToRoleAsync(user, adminRole); await userManager.AddClaimAsync(user, new Claim("ManageStore", "Allowed")); } } diff --git a/src/MusicStore.Spa/MusicStore.Spa.kproj b/src/MusicStore.Spa/MusicStore.Spa.kproj index 971ab71704..f0d4b6c56d 100644 --- a/src/MusicStore.Spa/MusicStore.Spa.kproj +++ b/src/MusicStore.Spa/MusicStore.Spa.kproj @@ -15,7 +15,7 @@ 2.0 - 5001 + 5101 diff --git a/src/MusicStore.Spa/Pages/Admin.cshtml b/src/MusicStore.Spa/Pages/Admin.cshtml new file mode 100644 index 0000000000..59881197d5 --- /dev/null +++ b/src/MusicStore.Spa/Pages/Admin.cshtml @@ -0,0 +1,26 @@ +@model IEnumerable + +@{ + ViewBag.Title = "Store Manager"; + ViewBag.ngApp = "MusicStore.Admin"; + Layout = "/Views/Shared/_Layout.cshtml"; +} + +

Store Manager

+ +
+ +@*@Html.InlineData("Lookup", "ArtistsApi")*@ +@*@Html.InlineData("Lookup", "GenresApi")*@ + +@section Scripts { + + + + + +@* TODO: This is currently all the compiled TypeScript, non-minified. Need to explore options + for alternate loading schemes, e.g. AMD loader of individual modules, min vs. non-min, etc. *@ + + +} \ No newline at end of file diff --git a/src/MusicStore.Spa/Views/Home/Index.cshtml b/src/MusicStore.Spa/Pages/Home.cshtml similarity index 100% rename from src/MusicStore.Spa/Views/Home/Index.cshtml rename to src/MusicStore.Spa/Pages/Home.cshtml diff --git a/src/MusicStore.Spa/Views/Shared/_Layout.cshtml b/src/MusicStore.Spa/Views/Shared/_Layout.cshtml index 0e460fc4fe..6d64c3ed0d 100644 --- a/src/MusicStore.Spa/Views/Shared/_Layout.cshtml +++ b/src/MusicStore.Spa/Views/Shared/_Layout.cshtml @@ -17,11 +17,11 @@ - @Html.ActionLink("ASP.NET MVC Music Store", "Index", "Home", null, new { @class = "navbar-brand" }) + @Html.ActionLink("ASP.NET MVC Music Store", "Home", "Page", null, new { @class = "navbar-brand" }) diff --git a/src/MusicStore.Spa/project.json b/src/MusicStore.Spa/project.json index cf65b1b782..b39282b65e 100644 --- a/src/MusicStore.Spa/project.json +++ b/src/MusicStore.Spa/project.json @@ -21,9 +21,9 @@ "Microsoft.Framework.ConfigurationModel.Json": "1.0.0-*" }, "commands": { - "WebListener": "Microsoft.AspNet.Hosting --server Microsoft.AspNet.Server.WebListener --server.urls http://localhost:5002", - "Kestrel": "Microsoft.AspNet.Hosting --server Kestrel --server.urls http://localhost:5004", - "run": "run server.urls=http://localhost:5003" + "WebListener": "Microsoft.AspNet.Hosting --server Microsoft.AspNet.Server.WebListener --server.urls http://localhost:5102", + "Kestrel": "Microsoft.AspNet.Hosting --server Kestrel --server.urls http://localhost:5104", + "run": "run server.urls=http://localhost:5103" }, "frameworks": { "aspnet50": { },