Admin page (#324)
* Updates based on documentation * Getting the build passing * Getting app functioning * A few cleanups to confirm it's working as expected * Fixing functional tests * Updating dockerfile for 3.0 * Functional Tests now run sequentially * Updating to latest version of moq * Adding migration for post 3.0 upgrades * Removing commented out lines * Moving address and catalogitemordered configuration in to classes that own them * Adding admin user * Adding admin catalog screen - will also only display menu option if user is logged in as an admin * WIP - squash this * Allow user to edit a catalog item * Adding entry for new service * Invalidating cache after catalog item update - also a little bit of cleanup * Fixing bad merge * Removing Picture Uri and making Id readonly * Adjusting style in menu dropdown so all options are shown * Creating Cache helpers with unit tests
This commit is contained in:
committed by
Steve Smith
parent
539d8c689d
commit
f3f74a342e
12
src/ApplicationCore/Constants/AuthorizationConstants.cs
Normal file
12
src/ApplicationCore/Constants/AuthorizationConstants.cs
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
namespace Microsoft.eShopWeb.ApplicationCore.Constants
|
||||||
|
{
|
||||||
|
public class AuthorizationConstants
|
||||||
|
{
|
||||||
|
public static class Roles
|
||||||
|
{
|
||||||
|
public const string ADMINISTRATORS = "Administrators";
|
||||||
|
}
|
||||||
|
|
||||||
|
public const string DEFAULT_PASSWORD = "Pass@word1";
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,14 +1,23 @@
|
|||||||
using Microsoft.AspNetCore.Identity;
|
using Microsoft.AspNetCore.Identity;
|
||||||
|
using Microsoft.eShopWeb.ApplicationCore.Constants;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace Microsoft.eShopWeb.Infrastructure.Identity
|
namespace Microsoft.eShopWeb.Infrastructure.Identity
|
||||||
{
|
{
|
||||||
public class AppIdentityDbContextSeed
|
public class AppIdentityDbContextSeed
|
||||||
{
|
{
|
||||||
public static async Task SeedAsync(UserManager<ApplicationUser> userManager)
|
public static async Task SeedAsync(UserManager<ApplicationUser> userManager, RoleManager<IdentityRole> roleManager)
|
||||||
{
|
{
|
||||||
|
await roleManager.CreateAsync(new IdentityRole(AuthorizationConstants.Roles.ADMINISTRATORS));
|
||||||
|
|
||||||
var defaultUser = new ApplicationUser { UserName = "demouser@microsoft.com", Email = "demouser@microsoft.com" };
|
var defaultUser = new ApplicationUser { UserName = "demouser@microsoft.com", Email = "demouser@microsoft.com" };
|
||||||
await userManager.CreateAsync(defaultUser, "Pass@word1");
|
await userManager.CreateAsync(defaultUser, AuthorizationConstants.DEFAULT_PASSWORD);
|
||||||
|
|
||||||
|
string adminUserName = "admin@microsoft.com";
|
||||||
|
var adminUser = new ApplicationUser { UserName = adminUserName, Email = adminUserName };
|
||||||
|
await userManager.CreateAsync(adminUser, AuthorizationConstants.DEFAULT_PASSWORD);
|
||||||
|
adminUser = await userManager.FindByNameAsync(adminUserName);
|
||||||
|
await userManager.AddToRoleAsync(adminUser, AuthorizationConstants.Roles.ADMINISTRATORS);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
25
src/Web/Extensions/CacheHelpers.cs
Normal file
25
src/Web/Extensions/CacheHelpers.cs
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Microsoft.eShopWeb.Web.Extensions
|
||||||
|
{
|
||||||
|
public static class CacheHelpers
|
||||||
|
{
|
||||||
|
public static readonly TimeSpan DefaultCacheDuration = TimeSpan.FromSeconds(30);
|
||||||
|
private static readonly string _itemsKeyTemplate = "items-{0}-{1}-{2}-{3}";
|
||||||
|
|
||||||
|
public static string GenerateCatalogItemCacheKey(int pageIndex, int itemsPage, int? brandId, int? typeId)
|
||||||
|
{
|
||||||
|
return string.Format(_itemsKeyTemplate, pageIndex, itemsPage, brandId, typeId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string GenerateBrandsCacheKey()
|
||||||
|
{
|
||||||
|
return "brands";
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string GenerateTypesCacheKey()
|
||||||
|
{
|
||||||
|
return "types";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
10
src/Web/Interfaces/ICatalogItemViewModelService.cs
Normal file
10
src/Web/Interfaces/ICatalogItemViewModelService.cs
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
using Microsoft.eShopWeb.Web.ViewModels;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Microsoft.eShopWeb.Web.Interfaces
|
||||||
|
{
|
||||||
|
public interface ICatalogItemViewModelService
|
||||||
|
{
|
||||||
|
Task UpdateCatalogItem(CatalogItemViewModel viewModel);
|
||||||
|
}
|
||||||
|
}
|
||||||
38
src/Web/Pages/Admin/EditCatalogItem.cshtml
Normal file
38
src/Web/Pages/Admin/EditCatalogItem.cshtml
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
@page
|
||||||
|
@{
|
||||||
|
ViewData["Title"] = "Admin - Edit Catalog";
|
||||||
|
@model EditCatalogItemModel
|
||||||
|
}
|
||||||
|
|
||||||
|
<div class="container">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-8">
|
||||||
|
<img class="esh-catalog-thumbnail" src="@Model.CatalogModel.PictureUri" />
|
||||||
|
<form method="post">
|
||||||
|
<div class="form-group">
|
||||||
|
<label asp-for="CatalogModel.Name"></label>
|
||||||
|
<input asp-for="CatalogModel.Name" class="form-control" />
|
||||||
|
<span asp-validation-for="CatalogModel.Name"></span>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label asp-for="CatalogModel.Price"></label>
|
||||||
|
<input asp-for="CatalogModel.Price" class="form-control" />
|
||||||
|
<span asp-validation-for="CatalogModel.Price"></span>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label asp-for="CatalogModel.Id"></label>
|
||||||
|
<input asp-for="CatalogModel.Id" readonly class="form-control" />
|
||||||
|
<span asp-validation-for="CatalogModel.Id"></span>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-2">
|
||||||
|
<input type="submit" value="Save" class="esh-catalog-button" />
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
@section Scripts {
|
||||||
|
<partial name="_ValidationScriptsPartial" />
|
||||||
|
}
|
||||||
39
src/Web/Pages/Admin/EditCatalogItem.cshtml.cs
Normal file
39
src/Web/Pages/Admin/EditCatalogItem.cshtml.cs
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.AspNetCore.Mvc.RazorPages;
|
||||||
|
using Microsoft.eShopWeb.ApplicationCore.Constants;
|
||||||
|
using Microsoft.eShopWeb.Web.Interfaces;
|
||||||
|
using Microsoft.eShopWeb.Web.ViewModels;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Microsoft.eShopWeb.Web.Pages.Admin
|
||||||
|
{
|
||||||
|
[Authorize(Roles = AuthorizationConstants.Roles.ADMINISTRATORS)]
|
||||||
|
public class EditCatalogItemModel : PageModel
|
||||||
|
{
|
||||||
|
private readonly ICatalogItemViewModelService _catalogItemViewModelService;
|
||||||
|
|
||||||
|
public EditCatalogItemModel(ICatalogItemViewModelService catalogItemViewModelService)
|
||||||
|
{
|
||||||
|
_catalogItemViewModelService = catalogItemViewModelService;
|
||||||
|
}
|
||||||
|
|
||||||
|
[BindProperty]
|
||||||
|
public CatalogItemViewModel CatalogModel { get; set; } = new CatalogItemViewModel();
|
||||||
|
|
||||||
|
public async Task OnGet(CatalogItemViewModel catalogModel)
|
||||||
|
{
|
||||||
|
CatalogModel = catalogModel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<IActionResult> OnPostAsync()
|
||||||
|
{
|
||||||
|
if (ModelState.IsValid)
|
||||||
|
{
|
||||||
|
await _catalogItemViewModelService.UpdateCatalogItem(CatalogModel);
|
||||||
|
}
|
||||||
|
|
||||||
|
return RedirectToPage("/Admin/Index");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
45
src/Web/Pages/Admin/Index.cshtml
Normal file
45
src/Web/Pages/Admin/Index.cshtml
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
@page
|
||||||
|
@{
|
||||||
|
ViewData["Title"] = "Admin - Catalog";
|
||||||
|
@model IndexModel
|
||||||
|
}
|
||||||
|
<section class="esh-catalog-hero">
|
||||||
|
<div class="container">
|
||||||
|
<img class="esh-catalog-title" src="~/images/main_banner_text.png" />
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<section class="esh-catalog-filters">
|
||||||
|
<div class="container">
|
||||||
|
<form method="get">
|
||||||
|
<label class="esh-catalog-label" data-title="brand">
|
||||||
|
<select asp-for="@Model.CatalogModel.BrandFilterApplied" asp-items="@Model.CatalogModel.Brands" class="esh-catalog-filter"></select>
|
||||||
|
</label>
|
||||||
|
<label class="esh-catalog-label" data-title="type">
|
||||||
|
<select asp-for="@Model.CatalogModel.TypesFilterApplied" asp-items="@Model.CatalogModel.Types" class="esh-catalog-filter"></select>
|
||||||
|
</label>
|
||||||
|
<input class="esh-catalog-send" type="image" src="images/arrow-right.svg" />
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<div class="container">
|
||||||
|
@if (Model.CatalogModel.CatalogItems.Any())
|
||||||
|
{
|
||||||
|
<partial name="_pagination" for="CatalogModel.PaginationInfo" />
|
||||||
|
|
||||||
|
<div class="esh-catalog-items row">
|
||||||
|
@foreach (var catalogItem in Model.CatalogModel.CatalogItems)
|
||||||
|
{
|
||||||
|
<div class="esh-catalog-item col-md-4">
|
||||||
|
<partial name="_editCatalog" for="@catalogItem" />
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
<partial name="_pagination" for="CatalogModel.PaginationInfo" />
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<div class="esh-catalog-items row">
|
||||||
|
THERE ARE NO RESULTS THAT MATCH YOUR SEARCH
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
35
src/Web/Pages/Admin/Index.cshtml.cs
Normal file
35
src/Web/Pages/Admin/Index.cshtml.cs
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Mvc.RazorPages;
|
||||||
|
using Microsoft.eShopWeb.ApplicationCore.Constants;
|
||||||
|
using Microsoft.eShopWeb.Web.Extensions;
|
||||||
|
using Microsoft.eShopWeb.Web.Services;
|
||||||
|
using Microsoft.eShopWeb.Web.ViewModels;
|
||||||
|
using Microsoft.Extensions.Caching.Memory;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Microsoft.eShopWeb.Web.Pages.Admin
|
||||||
|
{
|
||||||
|
[Authorize(Roles = AuthorizationConstants.Roles.ADMINISTRATORS)]
|
||||||
|
public class IndexModel : PageModel
|
||||||
|
{
|
||||||
|
private readonly ICatalogViewModelService _catalogViewModelService;
|
||||||
|
private readonly IMemoryCache _cache;
|
||||||
|
|
||||||
|
public IndexModel(ICatalogViewModelService catalogViewModelService, IMemoryCache cache)
|
||||||
|
{
|
||||||
|
_catalogViewModelService = catalogViewModelService;
|
||||||
|
_cache = cache;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CatalogIndexViewModel CatalogModel { get; set; } = new CatalogIndexViewModel();
|
||||||
|
|
||||||
|
public async Task OnGet(CatalogIndexViewModel catalogModel, int? pageId)
|
||||||
|
{
|
||||||
|
var cacheKey = CacheHelpers.GenerateCatalogItemCacheKey(pageId.GetValueOrDefault(), Constants.ITEMS_PER_PAGE, catalogModel.BrandFilterApplied, catalogModel.TypesFilterApplied);
|
||||||
|
|
||||||
|
_cache.Remove(cacheKey);
|
||||||
|
|
||||||
|
CatalogModel = await _catalogViewModelService.GetCatalogItems(pageId.GetValueOrDefault(), Constants.ITEMS_PER_PAGE, catalogModel.BrandFilterApplied, catalogModel.TypesFilterApplied);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,26 +1,24 @@
|
|||||||
using Microsoft.AspNetCore.Mvc.RazorPages;
|
using Microsoft.AspNetCore.Mvc.RazorPages;
|
||||||
using Microsoft.eShopWeb.Web.Services;
|
using Microsoft.eShopWeb.Web.Services;
|
||||||
using Microsoft.eShopWeb.Web.ViewModels;
|
using Microsoft.eShopWeb.Web.ViewModels;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace Microsoft.eShopWeb.Web.Pages
|
namespace Microsoft.eShopWeb.Web.Pages
|
||||||
{
|
{
|
||||||
public class IndexModel : PageModel
|
public class IndexModel : PageModel
|
||||||
{
|
{
|
||||||
private readonly ICatalogViewModelService _catalogViewModelService;
|
private readonly ICatalogViewModelService _catalogViewModelService;
|
||||||
|
|
||||||
public IndexModel(ICatalogViewModelService catalogViewModelService)
|
public IndexModel(ICatalogViewModelService catalogViewModelService)
|
||||||
{
|
{
|
||||||
_catalogViewModelService = catalogViewModelService;
|
_catalogViewModelService = catalogViewModelService;
|
||||||
}
|
}
|
||||||
|
|
||||||
public CatalogIndexViewModel CatalogModel { get; set; } = new CatalogIndexViewModel();
|
public CatalogIndexViewModel CatalogModel { get; set; } = new CatalogIndexViewModel();
|
||||||
|
|
||||||
public async Task OnGet(CatalogIndexViewModel catalogModel, int? pageId)
|
public async Task OnGet(CatalogIndexViewModel catalogModel, int? pageId)
|
||||||
{
|
{
|
||||||
CatalogModel = await _catalogViewModelService.GetCatalogItems(pageId ?? 0, Constants.ITEMS_PER_PAGE, catalogModel.BrandFilterApplied, catalogModel.TypesFilterApplied);
|
CatalogModel = await _catalogViewModelService.GetCatalogItems(pageId ?? 0, Constants.ITEMS_PER_PAGE, catalogModel.BrandFilterApplied, catalogModel.TypesFilterApplied);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
15
src/Web/Pages/Shared/_editCatalog.cshtml
Normal file
15
src/Web/Pages/Shared/_editCatalog.cshtml
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
@model CatalogItemViewModel
|
||||||
|
|
||||||
|
<form asp-page="/Admin/EditCatalogItem" method="get">
|
||||||
|
<div>
|
||||||
|
<img class="esh-catalog-thumbnail" src="@Model.PictureUri" />
|
||||||
|
<div class="esh-catalog-name">
|
||||||
|
<span>@Model.Name</span>
|
||||||
|
</div>
|
||||||
|
<input class="esh-catalog-button" type="submit" value="[ Edit ]" />
|
||||||
|
<input type="hidden" asp-for="@Model.Id" name="id" />
|
||||||
|
<input type="hidden" asp-for="@Model.Name" name="name" />
|
||||||
|
<input type="hidden" asp-for="@Model.PictureUri" name="pictureUri" />
|
||||||
|
<input type="hidden" asp-for="@Model.Price" name="price" />
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
@@ -27,7 +27,8 @@ namespace Microsoft.eShopWeb.Web
|
|||||||
await CatalogContextSeed.SeedAsync(catalogContext, loggerFactory);
|
await CatalogContextSeed.SeedAsync(catalogContext, loggerFactory);
|
||||||
|
|
||||||
var userManager = services.GetRequiredService<UserManager<ApplicationUser>>();
|
var userManager = services.GetRequiredService<UserManager<ApplicationUser>>();
|
||||||
await AppIdentityDbContextSeed.SeedAsync(userManager);
|
var roleManager = services.GetRequiredService<RoleManager<IdentityRole>>();
|
||||||
|
await AppIdentityDbContextSeed.SeedAsync(userManager, roleManager);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ using System.Threading.Tasks;
|
|||||||
using Microsoft.AspNetCore.Mvc.Rendering;
|
using Microsoft.AspNetCore.Mvc.Rendering;
|
||||||
using Microsoft.eShopWeb.Web.ViewModels;
|
using Microsoft.eShopWeb.Web.ViewModels;
|
||||||
using Microsoft.Extensions.Caching.Memory;
|
using Microsoft.Extensions.Caching.Memory;
|
||||||
using System;
|
using Microsoft.eShopWeb.Web.Extensions;
|
||||||
|
|
||||||
namespace Microsoft.eShopWeb.Web.Services
|
namespace Microsoft.eShopWeb.Web.Services
|
||||||
{
|
{
|
||||||
@@ -11,10 +11,6 @@ namespace Microsoft.eShopWeb.Web.Services
|
|||||||
{
|
{
|
||||||
private readonly IMemoryCache _cache;
|
private readonly IMemoryCache _cache;
|
||||||
private readonly CatalogViewModelService _catalogViewModelService;
|
private readonly CatalogViewModelService _catalogViewModelService;
|
||||||
private static readonly string _brandsKey = "brands";
|
|
||||||
private static readonly string _typesKey = "types";
|
|
||||||
private static readonly string _itemsKeyTemplate = "items-{0}-{1}-{2}-{3}";
|
|
||||||
private static readonly TimeSpan _defaultCacheDuration = TimeSpan.FromSeconds(30);
|
|
||||||
|
|
||||||
public CachedCatalogViewModelService(IMemoryCache cache,
|
public CachedCatalogViewModelService(IMemoryCache cache,
|
||||||
CatalogViewModelService catalogViewModelService)
|
CatalogViewModelService catalogViewModelService)
|
||||||
@@ -25,28 +21,29 @@ namespace Microsoft.eShopWeb.Web.Services
|
|||||||
|
|
||||||
public async Task<IEnumerable<SelectListItem>> GetBrands()
|
public async Task<IEnumerable<SelectListItem>> GetBrands()
|
||||||
{
|
{
|
||||||
return await _cache.GetOrCreateAsync(_brandsKey, async entry =>
|
return await _cache.GetOrCreateAsync(CacheHelpers.GenerateBrandsCacheKey(), async entry =>
|
||||||
{
|
{
|
||||||
entry.SlidingExpiration = _defaultCacheDuration;
|
entry.SlidingExpiration = CacheHelpers.DefaultCacheDuration;
|
||||||
return await _catalogViewModelService.GetBrands();
|
return await _catalogViewModelService.GetBrands();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<CatalogIndexViewModel> GetCatalogItems(int pageIndex, int itemsPage, int? brandId, int? typeId)
|
public async Task<CatalogIndexViewModel> GetCatalogItems(int pageIndex, int itemsPage, int? brandId, int? typeId)
|
||||||
{
|
{
|
||||||
string cacheKey = String.Format(_itemsKeyTemplate, pageIndex, itemsPage, brandId, typeId);
|
var cacheKey = CacheHelpers.GenerateCatalogItemCacheKey(pageIndex, Constants.ITEMS_PER_PAGE, brandId, typeId);
|
||||||
|
|
||||||
return await _cache.GetOrCreateAsync(cacheKey, async entry =>
|
return await _cache.GetOrCreateAsync(cacheKey, async entry =>
|
||||||
{
|
{
|
||||||
entry.SlidingExpiration = _defaultCacheDuration;
|
entry.SlidingExpiration = CacheHelpers.DefaultCacheDuration;
|
||||||
return await _catalogViewModelService.GetCatalogItems(pageIndex, itemsPage, brandId, typeId);
|
return await _catalogViewModelService.GetCatalogItems(pageIndex, itemsPage, brandId, typeId);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<IEnumerable<SelectListItem>> GetTypes()
|
public async Task<IEnumerable<SelectListItem>> GetTypes()
|
||||||
{
|
{
|
||||||
return await _cache.GetOrCreateAsync(_typesKey, async entry =>
|
return await _cache.GetOrCreateAsync(CacheHelpers.GenerateTypesCacheKey(), async entry =>
|
||||||
{
|
{
|
||||||
entry.SlidingExpiration = _defaultCacheDuration;
|
entry.SlidingExpiration = CacheHelpers.DefaultCacheDuration;
|
||||||
return await _catalogViewModelService.GetTypes();
|
return await _catalogViewModelService.GetTypes();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
31
src/Web/Services/CatalogItemViewModelService.cs
Normal file
31
src/Web/Services/CatalogItemViewModelService.cs
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
using Microsoft.eShopWeb.ApplicationCore.Entities;
|
||||||
|
using Microsoft.eShopWeb.ApplicationCore.Interfaces;
|
||||||
|
using Microsoft.eShopWeb.Web.Interfaces;
|
||||||
|
using Microsoft.eShopWeb.Web.ViewModels;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Microsoft.eShopWeb.Web.Services
|
||||||
|
{
|
||||||
|
public class CatalogItemViewModelService : ICatalogItemViewModelService
|
||||||
|
{
|
||||||
|
private readonly IAsyncRepository<CatalogItem> _catalogItemRepository;
|
||||||
|
|
||||||
|
public CatalogItemViewModelService(IAsyncRepository<CatalogItem> catalogItemRepository)
|
||||||
|
{
|
||||||
|
_catalogItemRepository = catalogItemRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task UpdateCatalogItem(CatalogItemViewModel viewModel)
|
||||||
|
{
|
||||||
|
//Get existing CatalogItem
|
||||||
|
var existingCatalogItem = await _catalogItemRepository.GetByIdAsync(viewModel.Id);
|
||||||
|
|
||||||
|
//Build updated CatalogItem
|
||||||
|
var updatedCatalogItem = existingCatalogItem;
|
||||||
|
updatedCatalogItem.Name = viewModel.Name;
|
||||||
|
updatedCatalogItem.Price = viewModel.Price;
|
||||||
|
|
||||||
|
await _catalogItemRepository.UpdateAsync(updatedCatalogItem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -92,6 +92,7 @@ namespace Microsoft.eShopWeb.Web
|
|||||||
services.AddScoped<IOrderService, OrderService>();
|
services.AddScoped<IOrderService, OrderService>();
|
||||||
services.AddScoped<IOrderRepository, OrderRepository>();
|
services.AddScoped<IOrderRepository, OrderRepository>();
|
||||||
services.AddScoped<CatalogViewModelService>();
|
services.AddScoped<CatalogViewModelService>();
|
||||||
|
services.AddScoped<ICatalogItemViewModelService, CatalogItemViewModelService>();
|
||||||
services.Configure<CatalogSettings>(Configuration);
|
services.Configure<CatalogSettings>(Configuration);
|
||||||
services.AddSingleton<IUriComposer>(new UriComposer(Configuration.Get<CatalogSettings>()));
|
services.AddSingleton<IUriComposer>(new UriComposer(Configuration.Get<CatalogSettings>()));
|
||||||
services.AddScoped(typeof(IAppLogger<>), typeof(LoggerAdapter<>));
|
services.AddScoped(typeof(IAppLogger<>), typeof(LoggerAdapter<>));
|
||||||
|
|||||||
@@ -8,6 +8,13 @@
|
|||||||
<img class="esh-identity-image" src="~/images/arrow-down.png">
|
<img class="esh-identity-image" src="~/images/arrow-down.png">
|
||||||
</section>
|
</section>
|
||||||
<section class="esh-identity-drop">
|
<section class="esh-identity-drop">
|
||||||
|
@if (User.IsInRole("Administrators"))
|
||||||
|
{
|
||||||
|
<a class="esh-identity-item"
|
||||||
|
asp-page="/Admin/Index">
|
||||||
|
<div class="esh-identity-name esh-identity-name--upper">Admin</div>
|
||||||
|
</a>
|
||||||
|
}
|
||||||
<a class="esh-identity-item"
|
<a class="esh-identity-item"
|
||||||
asp-controller="Order"
|
asp-controller="Order"
|
||||||
asp-action="MyOrders">
|
asp-action="MyOrders">
|
||||||
@@ -18,8 +25,7 @@
|
|||||||
asp-action="MyAccount">
|
asp-action="MyAccount">
|
||||||
<div class="esh-identity-name esh-identity-name--upper">My account</div>
|
<div class="esh-identity-name esh-identity-name--upper">My account</div>
|
||||||
</a>
|
</a>
|
||||||
<a class="esh-identity-item"
|
<a class="esh-identity-item" href="javascript:document.getElementById('logoutForm').submit()">
|
||||||
href="javascript:document.getElementById('logoutForm').submit()">
|
|
||||||
<div class="esh-identity-name esh-identity-name--upper">Log Out</div>
|
<div class="esh-identity-name esh-identity-name--upper">Log Out</div>
|
||||||
<img class="esh-identity-image" src="~/images/logout.png">
|
<img class="esh-identity-image" src="~/images/logout.png">
|
||||||
</a>
|
</a>
|
||||||
|
|||||||
@@ -41,7 +41,7 @@
|
|||||||
|
|
||||||
.esh-identity:hover .esh-identity-drop {
|
.esh-identity:hover .esh-identity-drop {
|
||||||
border: 1px solid #EEEEEE;
|
border: 1px solid #EEEEEE;
|
||||||
height: 10rem;
|
height: 14rem;
|
||||||
transition: height 0.35s;
|
transition: height 0.35s;
|
||||||
z-index: 10;
|
z-index: 10;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -64,8 +64,8 @@ namespace Microsoft.eShopWeb.FunctionalTests.Web.Controllers
|
|||||||
|
|
||||||
// seed sample user data
|
// seed sample user data
|
||||||
var userManager = scopedServices.GetRequiredService<UserManager<ApplicationUser>>();
|
var userManager = scopedServices.GetRequiredService<UserManager<ApplicationUser>>();
|
||||||
|
var roleManager = scopedServices.GetRequiredService<RoleManager<IdentityRole>>();
|
||||||
AppIdentityDbContextSeed.SeedAsync(userManager).Wait();
|
AppIdentityDbContextSeed.SeedAsync(userManager, roleManager).Wait();
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
using Microsoft.eShopWeb.Web.Extensions;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace Microsoft.eShopWeb.UnitTests.Web.Extensions.CacheHelpersTests
|
||||||
|
{
|
||||||
|
public class GenerateBrandsCacheKey_Should
|
||||||
|
{
|
||||||
|
[Fact]
|
||||||
|
public void ReturnBrandsCacheKey()
|
||||||
|
{
|
||||||
|
var result = CacheHelpers.GenerateBrandsCacheKey();
|
||||||
|
|
||||||
|
Assert.Equal("brands", result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
using Microsoft.eShopWeb.Web;
|
||||||
|
using Microsoft.eShopWeb.Web.Extensions;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace Microsoft.eShopWeb.UnitTests.Web.Extensions.CacheHelpersTests
|
||||||
|
{
|
||||||
|
public class GenerateCatalogItemCacheKey_Should
|
||||||
|
{
|
||||||
|
[Fact]
|
||||||
|
public void ReturnCatalogItemCacheKey()
|
||||||
|
{
|
||||||
|
var pageIndex = 0;
|
||||||
|
int? brandId = null;
|
||||||
|
int? typeId = null;
|
||||||
|
|
||||||
|
var result = CacheHelpers.GenerateCatalogItemCacheKey(pageIndex, Constants.ITEMS_PER_PAGE, brandId, typeId);
|
||||||
|
|
||||||
|
Assert.Equal("items-0-10--", result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
using Microsoft.eShopWeb.Web.Extensions;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace Microsoft.eShopWeb.UnitTests.Web.Extensions.CacheHelpersTests
|
||||||
|
{
|
||||||
|
public class GenerateTypesCacheKey_Should
|
||||||
|
{
|
||||||
|
[Fact]
|
||||||
|
public void ReturnTypesCacheKey()
|
||||||
|
{
|
||||||
|
var result = CacheHelpers.GenerateTypesCacheKey();
|
||||||
|
|
||||||
|
Assert.Equal("types", result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user