Merge branch 'Dev' of https://github.com/dotnet/eShopOnContainers into Dev
@ -39,12 +39,12 @@ Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "eShopOnContainers.WebMVC",
|
||||
EndProject
|
||||
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "eShopOnContainers.WebSPA", "src\Web\WebSPA\eShopOnContainers.WebSPA\eShopOnContainers.WebSPA.xproj", "{9842DB3A-1391-48C7-A49C-2FABD0A18AC2}"
|
||||
EndProject
|
||||
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Ordering.Application", "src\Services\Ordering\Ordering.Application\Ordering.Application.xproj", "{4193CAA3-A1C3-4818-A06F-A2D85FDE77E7}"
|
||||
EndProject
|
||||
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Ordering.Infrastructure", "src\Services\Ordering\Ordering.Infrastructure\Ordering.Infrastructure.xproj", "{95F1F07C-4D92-4742-BD07-E5B805AAB651}"
|
||||
EndProject
|
||||
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "FunctionalTests", "test\Services\FunctionalTests\FunctionalTests.xproj", "{621E7211-58D0-45FD-9600-1CB490BD930E}"
|
||||
EndProject
|
||||
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "UnitTest", "test\Services\UnitTest\UnitTest.xproj", "{7796F5D8-31FC-45A4-B673-19DE5BA194CF}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Ad-Hoc|Any CPU = Ad-Hoc|Any CPU
|
||||
@ -251,54 +251,6 @@ Global
|
||||
{9842DB3A-1391-48C7-A49C-2FABD0A18AC2}.Release|x64.Build.0 = Release|Any CPU
|
||||
{9842DB3A-1391-48C7-A49C-2FABD0A18AC2}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{9842DB3A-1391-48C7-A49C-2FABD0A18AC2}.Release|x86.Build.0 = Release|Any CPU
|
||||
{4193CAA3-A1C3-4818-A06F-A2D85FDE77E7}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{4193CAA3-A1C3-4818-A06F-A2D85FDE77E7}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU
|
||||
{4193CAA3-A1C3-4818-A06F-A2D85FDE77E7}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU
|
||||
{4193CAA3-A1C3-4818-A06F-A2D85FDE77E7}.Ad-Hoc|ARM.Build.0 = Debug|Any CPU
|
||||
{4193CAA3-A1C3-4818-A06F-A2D85FDE77E7}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU
|
||||
{4193CAA3-A1C3-4818-A06F-A2D85FDE77E7}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU
|
||||
{4193CAA3-A1C3-4818-A06F-A2D85FDE77E7}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||
{4193CAA3-A1C3-4818-A06F-A2D85FDE77E7}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||
{4193CAA3-A1C3-4818-A06F-A2D85FDE77E7}.Ad-Hoc|x64.ActiveCfg = Debug|Any CPU
|
||||
{4193CAA3-A1C3-4818-A06F-A2D85FDE77E7}.Ad-Hoc|x64.Build.0 = Debug|Any CPU
|
||||
{4193CAA3-A1C3-4818-A06F-A2D85FDE77E7}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU
|
||||
{4193CAA3-A1C3-4818-A06F-A2D85FDE77E7}.Ad-Hoc|x86.Build.0 = Debug|Any CPU
|
||||
{4193CAA3-A1C3-4818-A06F-A2D85FDE77E7}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{4193CAA3-A1C3-4818-A06F-A2D85FDE77E7}.AppStore|Any CPU.Build.0 = Debug|Any CPU
|
||||
{4193CAA3-A1C3-4818-A06F-A2D85FDE77E7}.AppStore|ARM.ActiveCfg = Debug|Any CPU
|
||||
{4193CAA3-A1C3-4818-A06F-A2D85FDE77E7}.AppStore|ARM.Build.0 = Debug|Any CPU
|
||||
{4193CAA3-A1C3-4818-A06F-A2D85FDE77E7}.AppStore|iPhone.ActiveCfg = Debug|Any CPU
|
||||
{4193CAA3-A1C3-4818-A06F-A2D85FDE77E7}.AppStore|iPhone.Build.0 = Debug|Any CPU
|
||||
{4193CAA3-A1C3-4818-A06F-A2D85FDE77E7}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||
{4193CAA3-A1C3-4818-A06F-A2D85FDE77E7}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||
{4193CAA3-A1C3-4818-A06F-A2D85FDE77E7}.AppStore|x64.ActiveCfg = Debug|Any CPU
|
||||
{4193CAA3-A1C3-4818-A06F-A2D85FDE77E7}.AppStore|x64.Build.0 = Debug|Any CPU
|
||||
{4193CAA3-A1C3-4818-A06F-A2D85FDE77E7}.AppStore|x86.ActiveCfg = Debug|Any CPU
|
||||
{4193CAA3-A1C3-4818-A06F-A2D85FDE77E7}.AppStore|x86.Build.0 = Debug|Any CPU
|
||||
{4193CAA3-A1C3-4818-A06F-A2D85FDE77E7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{4193CAA3-A1C3-4818-A06F-A2D85FDE77E7}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{4193CAA3-A1C3-4818-A06F-A2D85FDE77E7}.Debug|ARM.ActiveCfg = Debug|Any CPU
|
||||
{4193CAA3-A1C3-4818-A06F-A2D85FDE77E7}.Debug|ARM.Build.0 = Debug|Any CPU
|
||||
{4193CAA3-A1C3-4818-A06F-A2D85FDE77E7}.Debug|iPhone.ActiveCfg = Debug|Any CPU
|
||||
{4193CAA3-A1C3-4818-A06F-A2D85FDE77E7}.Debug|iPhone.Build.0 = Debug|Any CPU
|
||||
{4193CAA3-A1C3-4818-A06F-A2D85FDE77E7}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||
{4193CAA3-A1C3-4818-A06F-A2D85FDE77E7}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||
{4193CAA3-A1C3-4818-A06F-A2D85FDE77E7}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{4193CAA3-A1C3-4818-A06F-A2D85FDE77E7}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{4193CAA3-A1C3-4818-A06F-A2D85FDE77E7}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{4193CAA3-A1C3-4818-A06F-A2D85FDE77E7}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{4193CAA3-A1C3-4818-A06F-A2D85FDE77E7}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{4193CAA3-A1C3-4818-A06F-A2D85FDE77E7}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{4193CAA3-A1C3-4818-A06F-A2D85FDE77E7}.Release|ARM.ActiveCfg = Release|Any CPU
|
||||
{4193CAA3-A1C3-4818-A06F-A2D85FDE77E7}.Release|ARM.Build.0 = Release|Any CPU
|
||||
{4193CAA3-A1C3-4818-A06F-A2D85FDE77E7}.Release|iPhone.ActiveCfg = Release|Any CPU
|
||||
{4193CAA3-A1C3-4818-A06F-A2D85FDE77E7}.Release|iPhone.Build.0 = Release|Any CPU
|
||||
{4193CAA3-A1C3-4818-A06F-A2D85FDE77E7}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
||||
{4193CAA3-A1C3-4818-A06F-A2D85FDE77E7}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
|
||||
{4193CAA3-A1C3-4818-A06F-A2D85FDE77E7}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{4193CAA3-A1C3-4818-A06F-A2D85FDE77E7}.Release|x64.Build.0 = Release|Any CPU
|
||||
{4193CAA3-A1C3-4818-A06F-A2D85FDE77E7}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{4193CAA3-A1C3-4818-A06F-A2D85FDE77E7}.Release|x86.Build.0 = Release|Any CPU
|
||||
{95F1F07C-4D92-4742-BD07-E5B805AAB651}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{95F1F07C-4D92-4742-BD07-E5B805AAB651}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU
|
||||
{95F1F07C-4D92-4742-BD07-E5B805AAB651}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU
|
||||
@ -395,6 +347,54 @@ Global
|
||||
{621E7211-58D0-45FD-9600-1CB490BD930E}.Release|x64.Build.0 = Release|Any CPU
|
||||
{621E7211-58D0-45FD-9600-1CB490BD930E}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{621E7211-58D0-45FD-9600-1CB490BD930E}.Release|x86.Build.0 = Release|Any CPU
|
||||
{7796F5D8-31FC-45A4-B673-19DE5BA194CF}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{7796F5D8-31FC-45A4-B673-19DE5BA194CF}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU
|
||||
{7796F5D8-31FC-45A4-B673-19DE5BA194CF}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU
|
||||
{7796F5D8-31FC-45A4-B673-19DE5BA194CF}.Ad-Hoc|ARM.Build.0 = Debug|Any CPU
|
||||
{7796F5D8-31FC-45A4-B673-19DE5BA194CF}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU
|
||||
{7796F5D8-31FC-45A4-B673-19DE5BA194CF}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU
|
||||
{7796F5D8-31FC-45A4-B673-19DE5BA194CF}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||
{7796F5D8-31FC-45A4-B673-19DE5BA194CF}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||
{7796F5D8-31FC-45A4-B673-19DE5BA194CF}.Ad-Hoc|x64.ActiveCfg = Debug|Any CPU
|
||||
{7796F5D8-31FC-45A4-B673-19DE5BA194CF}.Ad-Hoc|x64.Build.0 = Debug|Any CPU
|
||||
{7796F5D8-31FC-45A4-B673-19DE5BA194CF}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU
|
||||
{7796F5D8-31FC-45A4-B673-19DE5BA194CF}.Ad-Hoc|x86.Build.0 = Debug|Any CPU
|
||||
{7796F5D8-31FC-45A4-B673-19DE5BA194CF}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{7796F5D8-31FC-45A4-B673-19DE5BA194CF}.AppStore|Any CPU.Build.0 = Debug|Any CPU
|
||||
{7796F5D8-31FC-45A4-B673-19DE5BA194CF}.AppStore|ARM.ActiveCfg = Debug|Any CPU
|
||||
{7796F5D8-31FC-45A4-B673-19DE5BA194CF}.AppStore|ARM.Build.0 = Debug|Any CPU
|
||||
{7796F5D8-31FC-45A4-B673-19DE5BA194CF}.AppStore|iPhone.ActiveCfg = Debug|Any CPU
|
||||
{7796F5D8-31FC-45A4-B673-19DE5BA194CF}.AppStore|iPhone.Build.0 = Debug|Any CPU
|
||||
{7796F5D8-31FC-45A4-B673-19DE5BA194CF}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||
{7796F5D8-31FC-45A4-B673-19DE5BA194CF}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||
{7796F5D8-31FC-45A4-B673-19DE5BA194CF}.AppStore|x64.ActiveCfg = Debug|Any CPU
|
||||
{7796F5D8-31FC-45A4-B673-19DE5BA194CF}.AppStore|x64.Build.0 = Debug|Any CPU
|
||||
{7796F5D8-31FC-45A4-B673-19DE5BA194CF}.AppStore|x86.ActiveCfg = Debug|Any CPU
|
||||
{7796F5D8-31FC-45A4-B673-19DE5BA194CF}.AppStore|x86.Build.0 = Debug|Any CPU
|
||||
{7796F5D8-31FC-45A4-B673-19DE5BA194CF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{7796F5D8-31FC-45A4-B673-19DE5BA194CF}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{7796F5D8-31FC-45A4-B673-19DE5BA194CF}.Debug|ARM.ActiveCfg = Debug|Any CPU
|
||||
{7796F5D8-31FC-45A4-B673-19DE5BA194CF}.Debug|ARM.Build.0 = Debug|Any CPU
|
||||
{7796F5D8-31FC-45A4-B673-19DE5BA194CF}.Debug|iPhone.ActiveCfg = Debug|Any CPU
|
||||
{7796F5D8-31FC-45A4-B673-19DE5BA194CF}.Debug|iPhone.Build.0 = Debug|Any CPU
|
||||
{7796F5D8-31FC-45A4-B673-19DE5BA194CF}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||
{7796F5D8-31FC-45A4-B673-19DE5BA194CF}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||
{7796F5D8-31FC-45A4-B673-19DE5BA194CF}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{7796F5D8-31FC-45A4-B673-19DE5BA194CF}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{7796F5D8-31FC-45A4-B673-19DE5BA194CF}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{7796F5D8-31FC-45A4-B673-19DE5BA194CF}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{7796F5D8-31FC-45A4-B673-19DE5BA194CF}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{7796F5D8-31FC-45A4-B673-19DE5BA194CF}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{7796F5D8-31FC-45A4-B673-19DE5BA194CF}.Release|ARM.ActiveCfg = Release|Any CPU
|
||||
{7796F5D8-31FC-45A4-B673-19DE5BA194CF}.Release|ARM.Build.0 = Release|Any CPU
|
||||
{7796F5D8-31FC-45A4-B673-19DE5BA194CF}.Release|iPhone.ActiveCfg = Release|Any CPU
|
||||
{7796F5D8-31FC-45A4-B673-19DE5BA194CF}.Release|iPhone.Build.0 = Release|Any CPU
|
||||
{7796F5D8-31FC-45A4-B673-19DE5BA194CF}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
||||
{7796F5D8-31FC-45A4-B673-19DE5BA194CF}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
|
||||
{7796F5D8-31FC-45A4-B673-19DE5BA194CF}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{7796F5D8-31FC-45A4-B673-19DE5BA194CF}.Release|x64.Build.0 = Release|Any CPU
|
||||
{7796F5D8-31FC-45A4-B673-19DE5BA194CF}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{7796F5D8-31FC-45A4-B673-19DE5BA194CF}.Release|x86.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
@ -412,8 +412,8 @@ Global
|
||||
{EF0337F2-ED00-4643-89FD-EE10863F1870} = {A857AD10-40FF-4303-BEC2-FF1C58D5735E}
|
||||
{F0333D8E-0B27-42B7-B2C6-78F3657624E2} = {E279BF0F-7F66-4F3A-A3AB-2CDA66C1CD04}
|
||||
{9842DB3A-1391-48C7-A49C-2FABD0A18AC2} = {E279BF0F-7F66-4F3A-A3AB-2CDA66C1CD04}
|
||||
{4193CAA3-A1C3-4818-A06F-A2D85FDE77E7} = {0BD0DB92-2D98-44D9-9AC0-C59186D59B0B}
|
||||
{95F1F07C-4D92-4742-BD07-E5B805AAB651} = {0BD0DB92-2D98-44D9-9AC0-C59186D59B0B}
|
||||
{621E7211-58D0-45FD-9600-1CB490BD930E} = {EF0337F2-ED00-4643-89FD-EE10863F1870}
|
||||
{7796F5D8-31FC-45A4-B673-19DE5BA194CF} = {EF0337F2-ED00-4643-89FD-EE10863F1870}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
@ -6,6 +6,7 @@ namespace Microsoft.eShopOnContainers.Services.Catalog.API.Controllers
|
||||
using Microsoft.eShopOnContainers.Services.Catalog.API.Infrastructure;
|
||||
using Model;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using ViewModel;
|
||||
@ -56,6 +57,8 @@ namespace Microsoft.eShopOnContainers.Services.Catalog.API.Controllers
|
||||
.Take(pageSize)
|
||||
.ToListAsync();
|
||||
|
||||
itemsOnPage = ComposePicUri(itemsOnPage);
|
||||
|
||||
var model = new PaginatedItemsViewModel<CatalogItem>(
|
||||
pageIndex, pageSize, totalItems, itemsOnPage);
|
||||
|
||||
@ -87,9 +90,11 @@ namespace Microsoft.eShopOnContainers.Services.Catalog.API.Controllers
|
||||
.Take(pageSize)
|
||||
.ToListAsync();
|
||||
|
||||
itemsOnPage = ComposePicUri(itemsOnPage);
|
||||
|
||||
var model = new PaginatedItemsViewModel<CatalogItem>(
|
||||
pageIndex, pageSize, totalItems, itemsOnPage);
|
||||
|
||||
|
||||
return Ok(model);
|
||||
}
|
||||
|
||||
@ -114,5 +119,14 @@ namespace Microsoft.eShopOnContainers.Services.Catalog.API.Controllers
|
||||
|
||||
return Ok(items);
|
||||
}
|
||||
|
||||
private List<CatalogItem> ComposePicUri(List<CatalogItem> items) {
|
||||
items.ForEach(x =>
|
||||
{
|
||||
x.PictureUri = x.PictureUri.Replace("localhost", Request.Host.Host);
|
||||
});
|
||||
|
||||
return items;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,32 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using System.IO;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
|
||||
// For more information on enabling MVC for empty projects, visit http://go.microsoft.com/fwlink/?LinkID=397860
|
||||
|
||||
namespace Microsoft.eShopOnContainers.Services.Catalog.API.Controllers
|
||||
{
|
||||
[Route("api/v1/[controller]")]
|
||||
public class PicController : Controller
|
||||
{
|
||||
private readonly IHostingEnvironment _env;
|
||||
public PicController(IHostingEnvironment env)
|
||||
{
|
||||
_env = env;
|
||||
}
|
||||
|
||||
[HttpGet("{id}")]
|
||||
// GET: /<controller>/
|
||||
public IActionResult GetImage(int id)
|
||||
{
|
||||
var webRoot = _env.WebRootPath;
|
||||
var path = Path.Combine(webRoot, id + ".png");
|
||||
Byte[] b = System.IO.File.ReadAllBytes(path);
|
||||
return File(b, "image/png");
|
||||
}
|
||||
}
|
||||
}
|
@ -74,7 +74,7 @@
|
||||
{
|
||||
new CatalogType() { Type = "Mug"},
|
||||
new CatalogType() { Type = "T-Shirt" },
|
||||
new CatalogType() { Type = "Backpack" },
|
||||
new CatalogType() { Type = "Sheet" },
|
||||
new CatalogType() { Type = "USB Memory Stick" }
|
||||
};
|
||||
}
|
||||
@ -83,10 +83,18 @@
|
||||
{
|
||||
return new List<CatalogItem>()
|
||||
{
|
||||
new CatalogItem() { CatalogTypeId=2,CatalogBrandId=2, Description = "Roslyn Red T-Shirt", Name = "Roslyn Red T-Shirt", Price = 12, PictureUri = "https://fakeimg.pl/370x240/EEEEEE/000/?text=RoslynRedT-Shirt" },
|
||||
new CatalogItem() { CatalogTypeId=1,CatalogBrandId=2, Description = "Cupt Black & White Mug", Name = "Cupt Black & White Mug", Price= 17, PictureUri = "https://fakeimg.pl/370x240/EEEEEE/000/?text=CuptBlack&WhiteMug" },
|
||||
new CatalogItem() { CatalogTypeId=2,CatalogBrandId=2, Description = "Prism White T-Shirt", Name = "Prism White T-Shirt", Price = 12, PictureUri = "http://fakeimg.pl/370x240/EEEEEE/000/?text=.PrismWhiteT-Shirt" },
|
||||
new CatalogItem() { CatalogTypeId=2,CatalogBrandId=1, Description = ".NET Bot Black Sweatshirt", Name = ".NET Bot Black Sweatshirt", Price = 19.5M, PictureUri = "http://fakeimg.pl/370x240/EEEEEE/000/?text=.NETBotBlack" },
|
||||
new CatalogItem() { CatalogTypeId=2,CatalogBrandId=1, Description = ".NET Bot Black Sweatshirt", Name = ".NET Bot Black Sweatshirt", Price = 19.5M, PictureUri = "http://localhost:5101/api/v1/pic/1" },
|
||||
new CatalogItem() { CatalogTypeId=1,CatalogBrandId=2, Description = ".NET Black & White Mug", Name = ".NET Black & White Mug", Price= 8.50M, PictureUri = "http://localhost:5101/api/v1/pic/2" },
|
||||
new CatalogItem() { CatalogTypeId=2,CatalogBrandId=2, Description = "Prism White T-Shirt", Name = "Prism White T-Shirt", Price = 12, PictureUri = "http://localhost:5101/api/v1/pic/3" },
|
||||
new CatalogItem() { CatalogTypeId=2,CatalogBrandId=1, Description = ".NET Foundation Sweatshirt", Name = ".NET Foundation Sweatshirt", Price = 12, PictureUri = "http://localhost:5101/api/v1/pic/4" },
|
||||
new CatalogItem() { CatalogTypeId=2,CatalogBrandId=1, Description = "Roslyn Red Sheet", Name = "Roslyn Red Sheet", Price = 8.5M, PictureUri = "http://localhost:5101/api/v1/pic/5" },
|
||||
new CatalogItem() { CatalogTypeId=2,CatalogBrandId=1, Description = ".NET Blue Sweatshirt", Name = ".NET Blue Sweatshirt", Price = 12, PictureUri = "http://localhost:5101/api/v1/pic/6" },
|
||||
new CatalogItem() { CatalogTypeId=2,CatalogBrandId=2, Description = "Roslyn Red T-Shirt", Name = "Roslyn Red T-Shirt", Price = 12, PictureUri = "http://localhost:5101/api/v1/pic/7" },
|
||||
new CatalogItem() { CatalogTypeId=2,CatalogBrandId=1, Description = ".NET Purple Sweatshirt", Name = ".NET Purple Sweatshirt", Price = 8.5M, PictureUri = "http://localhost:5101/api/v1/pic/8" },
|
||||
new CatalogItem() { CatalogTypeId=1,CatalogBrandId=1, Description = ".NET T White Mug", Name = ".NET T White Mug", Price = 12, PictureUri = "http://localhost:5101/api/v1/pic/9" },
|
||||
new CatalogItem() { CatalogTypeId=2,CatalogBrandId=1, Description = ".NET Foundation Sheet", Name = ".NET Foundation Sheet", Price = 12, PictureUri = "http://localhost:5101/api/v1/pic/10" },
|
||||
new CatalogItem() { CatalogTypeId=2,CatalogBrandId=1, Description = ".NET T Sheet", Name = ".NET T Sheet", Price = 8.5M, PictureUri = "http://localhost:5101/api/v1/pic/11" },
|
||||
new CatalogItem() { CatalogTypeId=2,CatalogBrandId=1, Description = "Prism White TShirt", Name = "Prism White TShirt", Price = 12, PictureUri = "http://localhost:5101/api/v1/pic/12" }
|
||||
};
|
||||
}
|
||||
}
|
||||
|
BIN
src/Services/Catalog/Catalog.API/Pics/1.png
Normal file
After Width: | Height: | Size: 148 KiB |
BIN
src/Services/Catalog/Catalog.API/Pics/10.png
Normal file
After Width: | Height: | Size: 223 KiB |
BIN
src/Services/Catalog/Catalog.API/Pics/11.png
Normal file
After Width: | Height: | Size: 212 KiB |
BIN
src/Services/Catalog/Catalog.API/Pics/12.png
Normal file
After Width: | Height: | Size: 165 KiB |
BIN
src/Services/Catalog/Catalog.API/Pics/2.png
Normal file
After Width: | Height: | Size: 41 KiB |
BIN
src/Services/Catalog/Catalog.API/Pics/3.png
Normal file
After Width: | Height: | Size: 170 KiB |
BIN
src/Services/Catalog/Catalog.API/Pics/4.png
Normal file
After Width: | Height: | Size: 152 KiB |
BIN
src/Services/Catalog/Catalog.API/Pics/5.png
Normal file
After Width: | Height: | Size: 226 KiB |
BIN
src/Services/Catalog/Catalog.API/Pics/6.png
Normal file
After Width: | Height: | Size: 179 KiB |
BIN
src/Services/Catalog/Catalog.API/Pics/7.png
Normal file
After Width: | Height: | Size: 182 KiB |
BIN
src/Services/Catalog/Catalog.API/Pics/8.png
Normal file
After Width: | Height: | Size: 167 KiB |
BIN
src/Services/Catalog/Catalog.API/Pics/9.png
Normal file
After Width: | Height: | Size: 40 KiB |
@ -14,8 +14,10 @@ namespace Microsoft.eShopOnContainers.Services.Catalog.API
|
||||
{
|
||||
var host = new WebHostBuilder()
|
||||
.UseKestrel()
|
||||
.UseUrls(Environment.GetEnvironmentVariable("ASPNETCORE_URLS") ?? String.Empty)
|
||||
.UseUrls("http://0.0.0.0:5101")
|
||||
.UseIISIntegration()
|
||||
.UseContentRoot(Directory.GetCurrentDirectory())
|
||||
.UseWebRoot("Pics")
|
||||
.UseStartup<Startup>()
|
||||
.Build();
|
||||
|
||||
|
@ -3,7 +3,7 @@
|
||||
"windowsAuthentication": false,
|
||||
"anonymousAuthentication": true,
|
||||
"iisExpress": {
|
||||
"applicationUrl": "http://localhost:2418/",
|
||||
"applicationUrl": "http://localhost:5101",
|
||||
"sslPort": 0
|
||||
}
|
||||
},
|
||||
|
@ -1,5 +1,7 @@
|
||||
namespace Microsoft.eShopOnContainers.Services.Catalog.API
|
||||
{
|
||||
using AspNetCore.Http;
|
||||
using Extensions.FileProviders;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
@ -9,6 +11,7 @@
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
@ -85,7 +88,6 @@
|
||||
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
|
||||
loggerFactory.AddDebug();
|
||||
|
||||
// Use frameworks
|
||||
app.UseCors("CorsPolicy");
|
||||
|
||||
app.UseMvcWithDefaultRoute();
|
||||
|
@ -7,6 +7,7 @@
|
||||
"Microsoft.AspNetCore.Mvc": "1.0.1",
|
||||
"Microsoft.AspNetCore.Diagnostics": "1.0.0",
|
||||
"Microsoft.AspNetCore.Diagnostics.Abstractions": "1.0.0",
|
||||
"Microsoft.AspNetCore.Server.IISIntegration": "1.0.0",
|
||||
"Microsoft.AspNetCore.Server.Kestrel": "1.0.1",
|
||||
"Microsoft.Extensions.Configuration.EnvironmentVariables": "1.0.0",
|
||||
"Microsoft.Extensions.Configuration.FileExtensions": "1.0.0",
|
||||
|
@ -11,6 +11,7 @@ using IdentityServer4.Models;
|
||||
using IdentityServer4.Stores;
|
||||
using IdentityServer4.Quickstart.UI.Models;
|
||||
using eShopOnContainers.Identity.Models.AccountViewModels;
|
||||
using eShopOnContainers.Identity.Services;
|
||||
|
||||
namespace IdentityServer4.Quickstart.UI.Controllers
|
||||
{
|
||||
@ -23,6 +24,7 @@ namespace IdentityServer4.Quickstart.UI.Controllers
|
||||
private readonly IClientStore _clientStore;
|
||||
private readonly IScopeStore _scopeStore;
|
||||
private readonly IIdentityServerInteractionService _interaction;
|
||||
|
||||
|
||||
public ConsentController(
|
||||
ILogger<ConsentController> logger,
|
||||
@ -45,6 +47,7 @@ namespace IdentityServer4.Quickstart.UI.Controllers
|
||||
public async Task<IActionResult> Index(string returnUrl)
|
||||
{
|
||||
var vm = await BuildViewModelAsync(returnUrl);
|
||||
ViewData["ReturnUrl"] = returnUrl;
|
||||
if (vm != null)
|
||||
{
|
||||
return View("Index", vm);
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
|
||||
using eShopOnContainers.Identity;
|
||||
using eShopOnContainers.Identity.Services;
|
||||
using IdentityServer4.Quickstart.UI.Models;
|
||||
using IdentityServer4.Services;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
@ -15,11 +16,13 @@ namespace IdentityServer4.Quickstart.UI.Controllers
|
||||
{
|
||||
private readonly IIdentityServerInteractionService _interaction;
|
||||
private readonly IOptions<AppSettings> _settings;
|
||||
private readonly IRedirectService _redirectSvc;
|
||||
|
||||
public HomeController(IIdentityServerInteractionService interaction, IOptions<AppSettings> settings)
|
||||
public HomeController(IIdentityServerInteractionService interaction, IOptions<AppSettings> settings,IRedirectService redirectSvc)
|
||||
{
|
||||
_interaction = interaction;
|
||||
_settings = settings;
|
||||
_redirectSvc = redirectSvc;
|
||||
}
|
||||
|
||||
public IActionResult Index(string returnUrl)
|
||||
@ -27,6 +30,14 @@ namespace IdentityServer4.Quickstart.UI.Controllers
|
||||
return View();
|
||||
}
|
||||
|
||||
public IActionResult ReturnToOriginalApplication(string returnUrl)
|
||||
{
|
||||
if (returnUrl != null)
|
||||
return Redirect(_redirectSvc.ExtractRedirectUriFromReturnUrl(returnUrl));
|
||||
else
|
||||
return RedirectToAction("Index", "Home");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Shows the error page
|
||||
/// </summary>
|
||||
|
@ -1,360 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using eShopOnContainers.Identity.Models;
|
||||
using eShopOnContainers.Identity.Models.ManageViewModels;
|
||||
using eShopOnContainers.Identity.Services;
|
||||
|
||||
namespace eShopOnContainers.Identity.Controllers
|
||||
{
|
||||
[Authorize]
|
||||
public class ManageController : Controller
|
||||
{
|
||||
private readonly UserManager<ApplicationUser> _userManager;
|
||||
private readonly SignInManager<ApplicationUser> _signInManager;
|
||||
private readonly IEmailSender _emailSender;
|
||||
private readonly ISmsSender _smsSender;
|
||||
private readonly ILogger _logger;
|
||||
|
||||
public ManageController(
|
||||
UserManager<ApplicationUser> userManager,
|
||||
SignInManager<ApplicationUser> signInManager,
|
||||
IEmailSender emailSender,
|
||||
ISmsSender smsSender,
|
||||
ILoggerFactory loggerFactory)
|
||||
{
|
||||
_userManager = userManager;
|
||||
_signInManager = signInManager;
|
||||
_emailSender = emailSender;
|
||||
_smsSender = smsSender;
|
||||
_logger = loggerFactory.CreateLogger<ManageController>();
|
||||
}
|
||||
|
||||
//
|
||||
// GET: /Manage/Index
|
||||
[HttpGet]
|
||||
public async Task<IActionResult> Index(ManageMessageId? message = null)
|
||||
{
|
||||
ViewData["StatusMessage"] =
|
||||
message == ManageMessageId.ChangePasswordSuccess ? "Your password has been changed."
|
||||
: message == ManageMessageId.SetPasswordSuccess ? "Your password has been set."
|
||||
: message == ManageMessageId.SetTwoFactorSuccess ? "Your two-factor authentication provider has been set."
|
||||
: message == ManageMessageId.Error ? "An error has occurred."
|
||||
: message == ManageMessageId.AddPhoneSuccess ? "Your phone number was added."
|
||||
: message == ManageMessageId.RemovePhoneSuccess ? "Your phone number was removed."
|
||||
: "";
|
||||
|
||||
var user = await GetCurrentUserAsync();
|
||||
if (user == null)
|
||||
{
|
||||
return View("Error");
|
||||
}
|
||||
var model = new IndexViewModel
|
||||
{
|
||||
HasPassword = await _userManager.HasPasswordAsync(user),
|
||||
PhoneNumber = await _userManager.GetPhoneNumberAsync(user),
|
||||
TwoFactor = await _userManager.GetTwoFactorEnabledAsync(user),
|
||||
Logins = await _userManager.GetLoginsAsync(user),
|
||||
BrowserRemembered = await _signInManager.IsTwoFactorClientRememberedAsync(user)
|
||||
};
|
||||
return View(model);
|
||||
}
|
||||
|
||||
//
|
||||
// POST: /Manage/RemoveLogin
|
||||
[HttpPost]
|
||||
[ValidateAntiForgeryToken]
|
||||
public async Task<IActionResult> RemoveLogin(RemoveLoginViewModel account)
|
||||
{
|
||||
ManageMessageId? message = ManageMessageId.Error;
|
||||
var user = await GetCurrentUserAsync();
|
||||
if (user != null)
|
||||
{
|
||||
var result = await _userManager.RemoveLoginAsync(user, account.LoginProvider, account.ProviderKey);
|
||||
if (result.Succeeded)
|
||||
{
|
||||
await _signInManager.SignInAsync(user, isPersistent: false);
|
||||
message = ManageMessageId.RemoveLoginSuccess;
|
||||
}
|
||||
}
|
||||
return RedirectToAction(nameof(ManageLogins), new { Message = message });
|
||||
}
|
||||
|
||||
//
|
||||
// GET: /Manage/AddPhoneNumber
|
||||
public IActionResult AddPhoneNumber()
|
||||
{
|
||||
return View();
|
||||
}
|
||||
|
||||
//
|
||||
// POST: /Manage/AddPhoneNumber
|
||||
[HttpPost]
|
||||
[ValidateAntiForgeryToken]
|
||||
public async Task<IActionResult> AddPhoneNumber(AddPhoneNumberViewModel model)
|
||||
{
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
return View(model);
|
||||
}
|
||||
// Generate the token and send it
|
||||
var user = await GetCurrentUserAsync();
|
||||
if (user == null)
|
||||
{
|
||||
return View("Error");
|
||||
}
|
||||
var code = await _userManager.GenerateChangePhoneNumberTokenAsync(user, model.PhoneNumber);
|
||||
await _smsSender.SendSmsAsync(model.PhoneNumber, "Your security code is: " + code);
|
||||
return RedirectToAction(nameof(VerifyPhoneNumber), new { PhoneNumber = model.PhoneNumber });
|
||||
}
|
||||
|
||||
//
|
||||
// POST: /Manage/EnableTwoFactorAuthentication
|
||||
[HttpPost]
|
||||
[ValidateAntiForgeryToken]
|
||||
public async Task<IActionResult> EnableTwoFactorAuthentication()
|
||||
{
|
||||
var user = await GetCurrentUserAsync();
|
||||
if (user != null)
|
||||
{
|
||||
await _userManager.SetTwoFactorEnabledAsync(user, true);
|
||||
await _signInManager.SignInAsync(user, isPersistent: false);
|
||||
_logger.LogInformation(1, "User enabled two-factor authentication.");
|
||||
}
|
||||
return RedirectToAction(nameof(Index), "Manage");
|
||||
}
|
||||
|
||||
//
|
||||
// POST: /Manage/DisableTwoFactorAuthentication
|
||||
[HttpPost]
|
||||
[ValidateAntiForgeryToken]
|
||||
public async Task<IActionResult> DisableTwoFactorAuthentication()
|
||||
{
|
||||
var user = await GetCurrentUserAsync();
|
||||
if (user != null)
|
||||
{
|
||||
await _userManager.SetTwoFactorEnabledAsync(user, false);
|
||||
await _signInManager.SignInAsync(user, isPersistent: false);
|
||||
_logger.LogInformation(2, "User disabled two-factor authentication.");
|
||||
}
|
||||
return RedirectToAction(nameof(Index), "Manage");
|
||||
}
|
||||
|
||||
//
|
||||
// GET: /Manage/VerifyPhoneNumber
|
||||
[HttpGet]
|
||||
public async Task<IActionResult> VerifyPhoneNumber(string phoneNumber)
|
||||
{
|
||||
var user = await GetCurrentUserAsync();
|
||||
if (user == null)
|
||||
{
|
||||
return View("Error");
|
||||
}
|
||||
var code = await _userManager.GenerateChangePhoneNumberTokenAsync(user, phoneNumber);
|
||||
// Send an SMS to verify the phone number
|
||||
return phoneNumber == null ? View("Error") : View(new VerifyPhoneNumberViewModel { PhoneNumber = phoneNumber });
|
||||
}
|
||||
|
||||
//
|
||||
// POST: /Manage/VerifyPhoneNumber
|
||||
[HttpPost]
|
||||
[ValidateAntiForgeryToken]
|
||||
public async Task<IActionResult> VerifyPhoneNumber(VerifyPhoneNumberViewModel model)
|
||||
{
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
return View(model);
|
||||
}
|
||||
var user = await GetCurrentUserAsync();
|
||||
if (user != null)
|
||||
{
|
||||
var result = await _userManager.ChangePhoneNumberAsync(user, model.PhoneNumber, model.Code);
|
||||
if (result.Succeeded)
|
||||
{
|
||||
await _signInManager.SignInAsync(user, isPersistent: false);
|
||||
return RedirectToAction(nameof(Index), new { Message = ManageMessageId.AddPhoneSuccess });
|
||||
}
|
||||
}
|
||||
// If we got this far, something failed, redisplay the form
|
||||
ModelState.AddModelError(string.Empty, "Failed to verify phone number");
|
||||
return View(model);
|
||||
}
|
||||
|
||||
//
|
||||
// POST: /Manage/RemovePhoneNumber
|
||||
[HttpPost]
|
||||
[ValidateAntiForgeryToken]
|
||||
public async Task<IActionResult> RemovePhoneNumber()
|
||||
{
|
||||
var user = await GetCurrentUserAsync();
|
||||
if (user != null)
|
||||
{
|
||||
var result = await _userManager.SetPhoneNumberAsync(user, null);
|
||||
if (result.Succeeded)
|
||||
{
|
||||
await _signInManager.SignInAsync(user, isPersistent: false);
|
||||
return RedirectToAction(nameof(Index), new { Message = ManageMessageId.RemovePhoneSuccess });
|
||||
}
|
||||
}
|
||||
return RedirectToAction(nameof(Index), new { Message = ManageMessageId.Error });
|
||||
}
|
||||
|
||||
//
|
||||
// GET: /Manage/ChangePassword
|
||||
[HttpGet]
|
||||
public IActionResult ChangePassword()
|
||||
{
|
||||
return View();
|
||||
}
|
||||
|
||||
//
|
||||
// POST: /Manage/ChangePassword
|
||||
[HttpPost]
|
||||
[ValidateAntiForgeryToken]
|
||||
public async Task<IActionResult> ChangePassword(ChangePasswordViewModel model)
|
||||
{
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
return View(model);
|
||||
}
|
||||
var user = await GetCurrentUserAsync();
|
||||
if (user != null)
|
||||
{
|
||||
var result = await _userManager.ChangePasswordAsync(user, model.OldPassword, model.NewPassword);
|
||||
if (result.Succeeded)
|
||||
{
|
||||
await _signInManager.SignInAsync(user, isPersistent: false);
|
||||
_logger.LogInformation(3, "User changed their password successfully.");
|
||||
return RedirectToAction(nameof(Index), new { Message = ManageMessageId.ChangePasswordSuccess });
|
||||
}
|
||||
AddErrors(result);
|
||||
return View(model);
|
||||
}
|
||||
return RedirectToAction(nameof(Index), new { Message = ManageMessageId.Error });
|
||||
}
|
||||
|
||||
//
|
||||
// GET: /Manage/SetPassword
|
||||
[HttpGet]
|
||||
public IActionResult SetPassword()
|
||||
{
|
||||
return View();
|
||||
}
|
||||
|
||||
//
|
||||
// POST: /Manage/SetPassword
|
||||
[HttpPost]
|
||||
[ValidateAntiForgeryToken]
|
||||
public async Task<IActionResult> SetPassword(SetPasswordViewModel model)
|
||||
{
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
return View(model);
|
||||
}
|
||||
|
||||
var user = await GetCurrentUserAsync();
|
||||
if (user != null)
|
||||
{
|
||||
var result = await _userManager.AddPasswordAsync(user, model.NewPassword);
|
||||
if (result.Succeeded)
|
||||
{
|
||||
await _signInManager.SignInAsync(user, isPersistent: false);
|
||||
return RedirectToAction(nameof(Index), new { Message = ManageMessageId.SetPasswordSuccess });
|
||||
}
|
||||
AddErrors(result);
|
||||
return View(model);
|
||||
}
|
||||
return RedirectToAction(nameof(Index), new { Message = ManageMessageId.Error });
|
||||
}
|
||||
|
||||
//GET: /Manage/ManageLogins
|
||||
[HttpGet]
|
||||
public async Task<IActionResult> ManageLogins(ManageMessageId? message = null)
|
||||
{
|
||||
ViewData["StatusMessage"] =
|
||||
message == ManageMessageId.RemoveLoginSuccess ? "The external login was removed."
|
||||
: message == ManageMessageId.AddLoginSuccess ? "The external login was added."
|
||||
: message == ManageMessageId.Error ? "An error has occurred."
|
||||
: "";
|
||||
var user = await GetCurrentUserAsync();
|
||||
if (user == null)
|
||||
{
|
||||
return View("Error");
|
||||
}
|
||||
var userLogins = await _userManager.GetLoginsAsync(user);
|
||||
var otherLogins = _signInManager.GetExternalAuthenticationSchemes().Where(auth => userLogins.All(ul => auth.AuthenticationScheme != ul.LoginProvider)).ToList();
|
||||
ViewData["ShowRemoveButton"] = user.PasswordHash != null || userLogins.Count > 1;
|
||||
return View(new ManageLoginsViewModel
|
||||
{
|
||||
CurrentLogins = userLogins,
|
||||
OtherLogins = otherLogins
|
||||
});
|
||||
}
|
||||
|
||||
//
|
||||
// POST: /Manage/LinkLogin
|
||||
[HttpPost]
|
||||
[ValidateAntiForgeryToken]
|
||||
public IActionResult LinkLogin(string provider)
|
||||
{
|
||||
// Request a redirect to the external login provider to link a login for the current user
|
||||
var redirectUrl = Url.Action("LinkLoginCallback", "Manage");
|
||||
var properties = _signInManager.ConfigureExternalAuthenticationProperties(provider, redirectUrl, _userManager.GetUserId(User));
|
||||
return Challenge(properties, provider);
|
||||
}
|
||||
|
||||
//
|
||||
// GET: /Manage/LinkLoginCallback
|
||||
[HttpGet]
|
||||
public async Task<ActionResult> LinkLoginCallback()
|
||||
{
|
||||
var user = await GetCurrentUserAsync();
|
||||
if (user == null)
|
||||
{
|
||||
return View("Error");
|
||||
}
|
||||
var info = await _signInManager.GetExternalLoginInfoAsync(await _userManager.GetUserIdAsync(user));
|
||||
if (info == null)
|
||||
{
|
||||
return RedirectToAction(nameof(ManageLogins), new { Message = ManageMessageId.Error });
|
||||
}
|
||||
var result = await _userManager.AddLoginAsync(user, info);
|
||||
var message = result.Succeeded ? ManageMessageId.AddLoginSuccess : ManageMessageId.Error;
|
||||
return RedirectToAction(nameof(ManageLogins), new { Message = message });
|
||||
}
|
||||
|
||||
#region Helpers
|
||||
|
||||
private void AddErrors(IdentityResult result)
|
||||
{
|
||||
foreach (var error in result.Errors)
|
||||
{
|
||||
ModelState.AddModelError(string.Empty, error.Description);
|
||||
}
|
||||
}
|
||||
|
||||
public enum ManageMessageId
|
||||
{
|
||||
AddPhoneSuccess,
|
||||
AddLoginSuccess,
|
||||
ChangePasswordSuccess,
|
||||
SetTwoFactorSuccess,
|
||||
SetPasswordSuccess,
|
||||
RemoveLoginSuccess,
|
||||
RemovePhoneSuccess,
|
||||
Error
|
||||
}
|
||||
|
||||
private Task<ApplicationUser> GetCurrentUserAsync()
|
||||
{
|
||||
return _userManager.GetUserAsync(HttpContext.User);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace eShopOnContainers.Identity.Services
|
||||
{
|
||||
public interface IRedirectService
|
||||
{
|
||||
string ExtractRedirectUriFromReturnUrl(string url);
|
||||
}
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace eShopOnContainers.Identity.Services
|
||||
{
|
||||
public class RedirectService : IRedirectService
|
||||
{
|
||||
public string ExtractRedirectUriFromReturnUrl(string url)
|
||||
{
|
||||
var result = "";
|
||||
var decodedUrl = System.Net.WebUtility.HtmlDecode(url);
|
||||
var results = Regex.Split(decodedUrl, "redirect_uri=");
|
||||
if (results.Length < 2)
|
||||
return "";
|
||||
|
||||
result = results[1];
|
||||
|
||||
var splitKey = "";
|
||||
if (result.Contains("signin-oidc"))
|
||||
splitKey = "signin-oidc";
|
||||
else
|
||||
splitKey = "scope";
|
||||
|
||||
results = Regex.Split(result, splitKey);
|
||||
if (results.Length < 2)
|
||||
return "";
|
||||
|
||||
result = results[0];
|
||||
|
||||
return result.Replace("%3A", ":").Replace("%2F", "/").Replace("&", "");
|
||||
}
|
||||
}
|
||||
}
|
@ -59,6 +59,7 @@ namespace eShopOnContainers.Identity
|
||||
services.AddTransient<IEmailSender, AuthMessageSender>();
|
||||
services.AddTransient<ISmsSender, AuthMessageSender>();
|
||||
services.AddTransient<ILoginService<ApplicationUser>, EFLoginService>();
|
||||
services.AddTransient<IRedirectService, RedirectService>();
|
||||
|
||||
//callbacks urls from config:
|
||||
Dictionary<string, string> clientUrls = new Dictionary<string, string>();
|
||||
|
@ -14,7 +14,7 @@
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="navbar-header col-sm-6 col-xs-8">
|
||||
<a href="~/">
|
||||
<a asp-controller="home" asp-action="ReturnToOriginalApplication" asp-route-returnUrl="@ViewData["ReturnUrl"]">
|
||||
<div class="navbar-brand"></div>
|
||||
</a>
|
||||
</div>
|
||||
|
@ -6,7 +6,7 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
public class NewOrderRequest
|
||||
public class NewOrderCommand
|
||||
:IAsyncRequest<bool>
|
||||
{
|
||||
|
||||
@ -40,7 +40,7 @@
|
||||
_orderItems.Add(item);
|
||||
}
|
||||
|
||||
public NewOrderRequest()
|
||||
public NewOrderCommand()
|
||||
{
|
||||
_orderItems = new List<OrderItem>();
|
||||
}
|
@ -7,13 +7,13 @@
|
||||
using System.Threading.Tasks;
|
||||
using Domain;
|
||||
|
||||
public class NewOrderRequestHandler
|
||||
: IAsyncRequestHandler<NewOrderRequest, bool>
|
||||
public class NewOrderCommandHandler
|
||||
: IAsyncRequestHandler<NewOrderCommand, bool>
|
||||
{
|
||||
private readonly IBuyerRepository _buyerRepository;
|
||||
private readonly IOrderRepository _orderRepository;
|
||||
|
||||
public NewOrderRequestHandler(IBuyerRepository buyerRepository,IOrderRepository orderRepository)
|
||||
public NewOrderCommandHandler(IBuyerRepository buyerRepository,IOrderRepository orderRepository)
|
||||
{
|
||||
if (buyerRepository == null)
|
||||
{
|
||||
@ -28,7 +28,7 @@
|
||||
_buyerRepository = buyerRepository;
|
||||
_orderRepository = orderRepository;
|
||||
}
|
||||
public async Task<bool> Handle(NewOrderRequest message)
|
||||
public async Task<bool> Handle(NewOrderCommand message)
|
||||
{
|
||||
//find buyer/payment or add a new one buyer/payment
|
||||
|
||||
@ -70,7 +70,7 @@
|
||||
|
||||
|
||||
|
||||
Payment GetExistingPaymentOrAddANewOne(Buyer buyer, NewOrderRequest message)
|
||||
Payment GetExistingPaymentOrAddANewOne(Buyer buyer, NewOrderCommand message)
|
||||
{
|
||||
Payment payment = PaymentAlreadyExist(buyer, message);
|
||||
|
||||
@ -84,7 +84,7 @@
|
||||
|
||||
}
|
||||
|
||||
Payment PaymentAlreadyExist(Domain.Buyer buyer, NewOrderRequest message)
|
||||
Payment PaymentAlreadyExist(Domain.Buyer buyer, NewOrderCommand message)
|
||||
{
|
||||
return buyer.Payments
|
||||
.SingleOrDefault(p =>
|
||||
@ -99,7 +99,7 @@
|
||||
});
|
||||
}
|
||||
|
||||
Buyer CreateBuyer(NewOrderRequest message)
|
||||
Buyer CreateBuyer(NewOrderCommand message)
|
||||
{
|
||||
return _buyerRepository.Add(
|
||||
new Buyer(message.Buyer));
|
||||
@ -110,7 +110,7 @@
|
||||
return new Order(buyerId, paymentId);
|
||||
}
|
||||
|
||||
Payment CreatePayment(NewOrderRequest message)
|
||||
Payment CreatePayment(NewOrderCommand message)
|
||||
{
|
||||
return new Payment(message.CardNumber, message.CardSecurityNumber, message.CardHolderName, message.CardExpiration, message.CardTypeId);
|
||||
}
|
@ -43,7 +43,7 @@
|
||||
|
||||
[Route("new")]
|
||||
[HttpPost]
|
||||
public async Task<IActionResult> AddOrder([FromBody]NewOrderRequest order)
|
||||
public async Task<IActionResult> AddOrder([FromBody]NewOrderCommand order)
|
||||
{
|
||||
if (order.CardTypeId == 0)
|
||||
order.CardTypeId = 1;
|
||||
|
@ -16,7 +16,7 @@
|
||||
builder.RegisterAssemblyTypes(typeof(IMediator).GetTypeInfo().Assembly)
|
||||
.AsImplementedInterfaces();
|
||||
|
||||
builder.RegisterAssemblyTypes(typeof(NewOrderRequest).GetTypeInfo().Assembly)
|
||||
builder.RegisterAssemblyTypes(typeof(NewOrderCommand).GetTypeInfo().Assembly)
|
||||
.As(o => o.GetInterfaces()
|
||||
.Where(i => i.IsClosedTypeOf(typeof(IAsyncRequestHandler<,>)))
|
||||
.Select(i => new KeyedService("IAsyncRequestHandler", i)));
|
||||
|
@ -1,118 +0,0 @@
|
||||
namespace Microsoft.eShopOnContainers.Services.Ordering.Application.Commands
|
||||
{
|
||||
using Domain.Repositories;
|
||||
using MediatR;
|
||||
using System.Linq;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Domain;
|
||||
|
||||
public class NewOrderRequestHandler
|
||||
: IAsyncRequestHandler<NewOrderRequest, bool>
|
||||
{
|
||||
private readonly IBuyerRepository _buyerRepository;
|
||||
private readonly IOrderRepository _orderRepository;
|
||||
|
||||
public NewOrderRequestHandler(IBuyerRepository buyerRepository,IOrderRepository orderRepository)
|
||||
{
|
||||
if (buyerRepository == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(buyerRepository));
|
||||
}
|
||||
|
||||
if (orderRepository == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(orderRepository));
|
||||
}
|
||||
|
||||
_buyerRepository = buyerRepository;
|
||||
_orderRepository = orderRepository;
|
||||
}
|
||||
public async Task<bool> Handle(NewOrderRequest message)
|
||||
{
|
||||
//find buyer/payment or add a new one buyer/payment
|
||||
|
||||
var buyer = await _buyerRepository.FindAsync(message.Buyer);
|
||||
|
||||
if (buyer == null)
|
||||
{
|
||||
buyer = CreateBuyer(message);
|
||||
}
|
||||
|
||||
var payment = GetExistingPaymentOrAddANewOne(buyer, message);
|
||||
|
||||
await _buyerRepository.UnitOfWork
|
||||
.SaveChangesAsync();
|
||||
|
||||
//create order for buyer and payment method
|
||||
|
||||
var order = CreateOrder(buyer.Id, payment.Id, 0);
|
||||
order.SetAddress( new Address()
|
||||
{
|
||||
City = message.City,
|
||||
State = message.State,
|
||||
Street = message.Street,
|
||||
ZipCode = message.ZipCode
|
||||
});
|
||||
|
||||
foreach (var item in message.OrderItems)
|
||||
{
|
||||
order.AddOrderItem(item);
|
||||
}
|
||||
|
||||
_orderRepository.Add(order);
|
||||
|
||||
var result = await _orderRepository.UnitOfWork
|
||||
.SaveChangesAsync();
|
||||
|
||||
return result > 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
Payment GetExistingPaymentOrAddANewOne(Buyer buyer, NewOrderRequest message)
|
||||
{
|
||||
Payment payment = PaymentAlreadyExist(buyer, message);
|
||||
|
||||
if (payment == null)
|
||||
{
|
||||
payment = CreatePayment(message);
|
||||
buyer.Payments.Add(payment);
|
||||
}
|
||||
|
||||
return payment;
|
||||
|
||||
}
|
||||
|
||||
Payment PaymentAlreadyExist(Domain.Buyer buyer, NewOrderRequest message)
|
||||
{
|
||||
return buyer.Payments
|
||||
.SingleOrDefault(p =>
|
||||
{
|
||||
return p.CardHolderName == message.CardHolderName
|
||||
&&
|
||||
p.CardNumber == message.CardNumber
|
||||
&&
|
||||
p.Expiration == message.CardExpiration
|
||||
&&
|
||||
p.SecurityNumber == message.CardSecurityNumber;
|
||||
});
|
||||
}
|
||||
|
||||
Buyer CreateBuyer(NewOrderRequest message)
|
||||
{
|
||||
return _buyerRepository.Add(
|
||||
new Buyer(message.Buyer));
|
||||
}
|
||||
|
||||
Order CreateOrder(int buyerId, int paymentId, int addressId)
|
||||
{
|
||||
return new Order(buyerId, paymentId);
|
||||
}
|
||||
|
||||
Payment CreatePayment(NewOrderRequest message)
|
||||
{
|
||||
return new Payment(message.CardNumber, message.CardSecurityNumber, message.CardHolderName, message.CardExpiration, message.CardTypeId);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,48 +0,0 @@
|
||||
namespace Microsoft.eShopOnContainers.Services.Ordering.Application.Commands
|
||||
{
|
||||
using System;
|
||||
using MediatR;
|
||||
using Domain;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
public class NewOrderRequest
|
||||
:IAsyncRequest<bool>
|
||||
{
|
||||
|
||||
private readonly List<OrderItem> _orderItems;
|
||||
public string City { get; set; }
|
||||
|
||||
public string Street { get; set; }
|
||||
|
||||
public string State { get; set; }
|
||||
|
||||
public string Country { get; set; }
|
||||
|
||||
public string ZipCode { get; set; }
|
||||
|
||||
public string CardNumber { get; set; }
|
||||
|
||||
public string CardHolderName { get; set; }
|
||||
|
||||
public DateTime CardExpiration { get; set; }
|
||||
|
||||
public string CardSecurityNumber { get; set; }
|
||||
|
||||
public int CardTypeId { get; set; }
|
||||
|
||||
public string Buyer { get; set; }
|
||||
|
||||
public IEnumerable<OrderItem> OrderItems => _orderItems;
|
||||
|
||||
public void AddOrderItem(OrderItem item)
|
||||
{
|
||||
_orderItems.Add(item);
|
||||
}
|
||||
|
||||
public NewOrderRequest()
|
||||
{
|
||||
_orderItems = new List<OrderItem>();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,34 +0,0 @@
|
||||
namespace Microsoft.eShopOnContainers.Services.Ordering.Application.Decorators
|
||||
{
|
||||
using Extensions.Logging;
|
||||
using MediatR;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
public class LogDecorator<TRequest, TResponse>
|
||||
: IAsyncRequestHandler<TRequest, TResponse>
|
||||
where TRequest : IAsyncRequest<TResponse>
|
||||
{
|
||||
private readonly IAsyncRequestHandler<TRequest, TResponse> _inner;
|
||||
private readonly ILogger<LogDecorator<TRequest, TResponse>> _logger;
|
||||
|
||||
|
||||
public LogDecorator(
|
||||
IAsyncRequestHandler<TRequest, TResponse> inner,
|
||||
ILogger<LogDecorator<TRequest, TResponse>> logger)
|
||||
{
|
||||
_inner = inner;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public async Task<TResponse> Handle(TRequest message)
|
||||
{
|
||||
_logger.LogInformation($"Executing command {_inner.GetType().FullName}");
|
||||
|
||||
var response = await _inner.Handle(message);
|
||||
|
||||
_logger.LogInformation($"Succedded executed command {_inner.GetType().FullName}");
|
||||
|
||||
return response;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,19 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion>
|
||||
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.Props" Condition="'$(VSToolsPath)' != ''" />
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>4193caa3-a1c3-4818-a06f-a2d85fde77e7</ProjectGuid>
|
||||
<RootNamespace>Microsoft.eShopOnContainers.Services.Ordering.Application</RootNamespace>
|
||||
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">.\obj</BaseIntermediateOutputPath>
|
||||
<OutputPath Condition="'$(OutputPath)'=='' ">.\bin\</OutputPath>
|
||||
<TargetFrameworkVersion>v4.5.1</TargetFrameworkVersion>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.targets" Condition="'$(VSToolsPath)' != ''" />
|
||||
</Project>
|
@ -1,19 +0,0 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("Ordering.Application")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("4193caa3-a1c3-4818-a06f-a2d85fde77e7")]
|
@ -1,13 +0,0 @@
|
||||
namespace Microsoft.eShopOnContainers.Services.Ordering.Application.Queries
|
||||
{
|
||||
using System.Threading.Tasks;
|
||||
|
||||
public interface IOrderQueries
|
||||
{
|
||||
Task<dynamic> GetOrder(int id);
|
||||
|
||||
Task<dynamic> GetOrders();
|
||||
|
||||
Task<dynamic> GetCardTypes();
|
||||
}
|
||||
}
|
@ -1,128 +0,0 @@
|
||||
namespace Microsoft.eShopOnContainers.Services.Ordering.Application.Queries
|
||||
{
|
||||
using Dapper;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using System.Data.SqlClient;
|
||||
using System.Threading.Tasks;
|
||||
using System;
|
||||
using System.Dynamic;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
public class OrderQueries
|
||||
: IOrderQueries
|
||||
{
|
||||
private string _connectionString = string.Empty;
|
||||
|
||||
public OrderQueries(IConfiguration configuration)
|
||||
{
|
||||
_connectionString = configuration["ConnectionString"];
|
||||
}
|
||||
|
||||
|
||||
public async Task<dynamic> GetOrder(int id)
|
||||
{
|
||||
using (var connection = new SqlConnection(_connectionString))
|
||||
{
|
||||
connection.Open();
|
||||
|
||||
var result = await connection.QueryAsync<dynamic>(
|
||||
@"select o.[Id] as ordernumber,o.OrderDate as date, os.Name as status,
|
||||
oi.ProductName as productname, oi.Units as units, oi.UnitPrice as unitprice, oi.PictureUrl as pictureurl,
|
||||
oa.Street as street, oa.City as city, oa.Country as country, oa.State as state, oa.ZipCode as zipcode
|
||||
FROM ordering.Orders o
|
||||
LEFT JOIN ordering.Orderitems oi ON o.Id = oi.orderid
|
||||
LEFT JOIN ordering.orderstatus os on o.StatusId = os.Id
|
||||
LEFT JOIN ordering.address oa on o.ShippingAddressId = oa.Id
|
||||
WHERE o.Id=@id"
|
||||
, new { id }
|
||||
);
|
||||
|
||||
if (result.AsList().Count == 0)
|
||||
throw new KeyNotFoundException();
|
||||
|
||||
return MapOrderItems(result);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<dynamic> GetOrders()
|
||||
{
|
||||
using (var connection = new SqlConnection(_connectionString))
|
||||
{
|
||||
connection.Open();
|
||||
|
||||
return await connection.QueryAsync<dynamic>(@"SELECT o.[Id] as ordernumber,o.[OrderDate] as [date],os.[Name] as [status],SUM(oi.units*oi.unitprice) as total
|
||||
FROM [ordering].[Orders] o
|
||||
LEFT JOIN[ordering].[orderitems] oi ON o.Id = oi.orderid
|
||||
LEFT JOIN[ordering].[orderstatus] os on o.StatusId = os.Id
|
||||
GROUP BY o.[Id], o.[OrderDate], os.[Name]");
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<dynamic> GetCardTypes()
|
||||
{
|
||||
using (var connection = new SqlConnection(_connectionString))
|
||||
{
|
||||
connection.Open();
|
||||
|
||||
return await connection.QueryAsync<dynamic>("SELECT * FROM ordering.cardtypes");
|
||||
}
|
||||
}
|
||||
|
||||
private dynamic MapOrderItems(dynamic result)
|
||||
{
|
||||
dynamic order = new ExpandoObject();
|
||||
|
||||
order.ordernumber = result[0].ordernumber;
|
||||
order.date = result[0].date;
|
||||
order.status = result[0].status;
|
||||
order.street = result[0].street;
|
||||
order.city = result[0].city;
|
||||
order.zipcode = result[0].zipcode;
|
||||
order.country = result[0].country;
|
||||
|
||||
order.orderitems = new List<dynamic>();
|
||||
order.total = 0;
|
||||
|
||||
foreach (dynamic item in result)
|
||||
{
|
||||
dynamic orderitem = new ExpandoObject();
|
||||
orderitem.productname = item.productname;
|
||||
orderitem.units = item.units;
|
||||
orderitem.unitprice = item.unitprice;
|
||||
orderitem.pictureurl = item.pictureurl;
|
||||
|
||||
order.total += item.units * item.unitprice;
|
||||
order.orderitems.Add(orderitem);
|
||||
}
|
||||
|
||||
return order;
|
||||
}
|
||||
|
||||
//TODO/CCE: try to use this method instead actual.
|
||||
//private object MapOrderItems(dynamic result)
|
||||
//{
|
||||
// IEnumerable<dynamic> items = (result as System.Collections.IEnumerable).Cast<dynamic>();
|
||||
// var order = new
|
||||
// {
|
||||
// ordernumber = result[0].ordernumbe,
|
||||
// date = result[0].date,
|
||||
// status = result[0].status,
|
||||
// street = result[0].street,
|
||||
// city = result[0].city,
|
||||
// zipcode = result[0].zipcode,
|
||||
// country = result[0].country,
|
||||
// total = items.Select(r => (int)r.units * (int)r.unitprice).Sum(),
|
||||
// orderItems = items.Select(r => new
|
||||
// {
|
||||
// productname = r.productname,
|
||||
// units = r.units,
|
||||
// unitprice = r.unitprice,
|
||||
// pictureurl = r.pictureurl
|
||||
// })
|
||||
// };
|
||||
|
||||
// return order;
|
||||
//}
|
||||
}
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
{
|
||||
"version": "1.0.0-*",
|
||||
|
||||
"dependencies": {
|
||||
"NETStandard.Library": "1.6.0",
|
||||
"MediatR": "2.1.0",
|
||||
"Dapper": "1.50.2",
|
||||
"System.Dynamic.Runtime": "4.0.11",
|
||||
"Microsoft.CSharp": "4.0.1",
|
||||
"Microsoft.Extensions.Configuration": "1.0.0",
|
||||
"System.Data.SqlClient": "4.1.0",
|
||||
"Microsoft.Extensions.Logging.Abstractions": "1.0.0",
|
||||
"Ordering.Domain": "1.0.0-*"
|
||||
},
|
||||
|
||||
"frameworks": {
|
||||
"netstandard1.6": {
|
||||
"imports": "dnxcore50"
|
||||
}
|
||||
}
|
||||
}
|
@ -39,13 +39,8 @@
|
||||
modelBuilder.Entity<CardType>(ConfigureCardTypes);
|
||||
modelBuilder.Entity<OrderStatus>(ConfigureOrderStatus);
|
||||
modelBuilder.Entity<Address>(ConfigureAddress);
|
||||
|
||||
modelBuilder.Entity<Address>()
|
||||
.ToTable("address", DEFAULT_SCHEMA);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void ConfigureBuyer(EntityTypeBuilder<Buyer> buyerConfiguration)
|
||||
{
|
||||
buyerConfiguration.ToTable("buyers", DEFAULT_SCHEMA);
|
||||
|
@ -40,7 +40,7 @@
|
||||
no-universal-selectors: 0
|
||||
no-url-domains: 0
|
||||
no-url-protocols: 0
|
||||
no-vendor-prefixes: 2
|
||||
no-vendor-prefixes: 0
|
||||
no-warn: 2
|
||||
property-units: 0
|
||||
|
||||
|
@ -1,25 +1,27 @@
|
||||
@import './modules/_variables.scss';
|
||||
@import './modules/variables';
|
||||
|
||||
$dist: './fonts/Montserrat-Regular';
|
||||
|
||||
@font-face {
|
||||
font-family: Montserrat;
|
||||
font-weight: 400;
|
||||
src: url("./fonts/Montserrat-Regular.eot?") format("eot"),url("./fonts/Montserrat-Regular.woff") format("woff"),url("./fonts/Montserrat-Regular.ttf") format("truetype"),url("./fonts/Montserrat-Regular.svg#Montserrat") format("svg")
|
||||
src: url('./fonts/Montserrat-Regular.eot?') format('eot'), url('./fonts/Montserrat-Regular.woff') format('woff'), url('./fonts/Montserrat-Regular.ttf') format('truetype'), url('./fonts/Montserrat-Regular.svg#Montserrat') format('svg');
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: Montserrat;
|
||||
font-weight: 700;
|
||||
src: url("./fonts/Montserrat-Bold.eot?") format("eot"),url("./fonts/Montserrat-Bold.woff") format("woff"),url("./fonts/Montserrat-Bold.ttf") format("truetype"),url("./fonts/Montserrat-Bold.svg#Montserrat") format("svg")
|
||||
src: url('./fonts/Montserrat-Bold.eot?') format('eot'), url('./fonts/Montserrat-Bold.woff') format('woff'), url('./fonts/Montserrat-Bold.ttf') format('truetype'), url('./fonts/Montserrat-Bold.svg#Montserrat') format('svg');
|
||||
}
|
||||
|
||||
html,
|
||||
body {
|
||||
font-family: Montserrat,sans-serif;
|
||||
font-family: Montserrat, sans-serif;
|
||||
font-size: 16px;
|
||||
font-weight: $font-weight-normal;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
*,
|
||||
*::after,
|
||||
*::before {
|
||||
@ -39,3 +41,36 @@ body {
|
||||
select::-ms-expand {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 992px) {
|
||||
.form-input {
|
||||
max-width: 360px;
|
||||
width: 360px;
|
||||
}
|
||||
}
|
||||
|
||||
.form-input {
|
||||
border-radius: 0;
|
||||
height: 45px;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.form-input-small {
|
||||
max-width: 100px !important;
|
||||
}
|
||||
|
||||
.form-input-medium {
|
||||
width: 150px !important;
|
||||
}
|
||||
|
||||
.alert {
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
.alert-danger {
|
||||
background-color: transparent;
|
||||
border: 0;
|
||||
color: #FB0D0D;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
@import './_variables.scss';
|
||||
@import './variables';
|
||||
|
||||
.esh-app {
|
||||
&-footer {
|
||||
@ -13,6 +13,7 @@
|
||||
width: 100%;
|
||||
|
||||
$height: 50px;
|
||||
|
||||
&-brand {
|
||||
height: $height;
|
||||
width: 230px;
|
||||
|
@ -1,4 +1,4 @@
|
||||
@import '../../_variables.scss';
|
||||
@import '../../variables';
|
||||
|
||||
.esh-basketstatus {
|
||||
cursor: pointer;
|
||||
|
@ -1,4 +1,4 @@
|
||||
@import '../_variables.scss';
|
||||
@import '../variables';
|
||||
|
||||
.esh-basket {
|
||||
min-height: 80vh;
|
||||
@ -29,6 +29,7 @@
|
||||
}
|
||||
|
||||
$item-height: 8rem;
|
||||
|
||||
&-item {
|
||||
font-size: $font-size-m;
|
||||
font-weight: $font-weight-semilight;
|
||||
@ -56,9 +57,9 @@
|
||||
}
|
||||
|
||||
&-checkout {
|
||||
border: none;
|
||||
border-radius: 0;
|
||||
background-color: $color-secondary;
|
||||
border: 0;
|
||||
border-radius: 0;
|
||||
color: $color-foreground-brighter;
|
||||
display: inline-block;
|
||||
font-size: 1rem;
|
||||
|
@ -12,6 +12,7 @@ import { Observable } from 'rxjs/Observable';
|
||||
import 'rxjs/add/observable/throw';
|
||||
import { Observer } from 'rxjs/Observer';
|
||||
import 'rxjs/add/operator/map';
|
||||
import 'rxjs/add/operator/catch';
|
||||
|
||||
@Injectable()
|
||||
export class BasketService {
|
||||
@ -51,8 +52,7 @@ export class BasketService {
|
||||
}
|
||||
|
||||
dropBasket() {
|
||||
return this.service.delete(this.basketUrl + '/' + this.basket.buyerId).map((response: Response) => {
|
||||
return true;
|
||||
});
|
||||
console.log('drop basket!');
|
||||
this.service.delete(this.basketUrl + '/' + this.basket.buyerId);
|
||||
}
|
||||
}
|
@ -21,26 +21,31 @@
|
||||
</section>
|
||||
|
||||
<div class="container">
|
||||
<esh-pager [model]="paginationInfo" (changed)="onPageChanged($event)"></esh-pager>
|
||||
<div *ngIf="catalog?.data.length > 0">
|
||||
<esh-pager [model]="paginationInfo" (changed)="onPageChanged($event)"></esh-pager>
|
||||
|
||||
<div class="esh-catalog-items row">
|
||||
<div class="esh-catalog-item col-md-4"
|
||||
*ngFor="let item of catalog?.data">
|
||||
<div class="esh-catalog-items row">
|
||||
<div class="esh-catalog-item col-md-4"
|
||||
*ngFor="let item of catalog?.data">
|
||||
|
||||
<img class="esh-catalog-thumbnail" src="{{item.pictureUri}}" />
|
||||
<button class="esh-catalog-button" (click)="addToCart(item)">
|
||||
[ ADD TO CART ]
|
||||
</button>
|
||||
<img class="esh-catalog-thumbnail" src="{{item.pictureUri}}" />
|
||||
<button class="esh-catalog-button" (click)="addToCart(item)">
|
||||
[ ADD TO CART ]
|
||||
</button>
|
||||
|
||||
<div class="esh-catalog-name">
|
||||
<span>{{item.name}}</span>
|
||||
</div>
|
||||
<div class="esh-catalog-price">
|
||||
<span>{{item.price}}</span>
|
||||
<div class="esh-catalog-name">
|
||||
<span>{{item.name}}</span>
|
||||
</div>
|
||||
<div class="esh-catalog-price">
|
||||
<span>{{item.price}}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<esh-pager [model]="paginationInfo" (changed)="onPageChanged($event)"></esh-pager>
|
||||
<esh-pager [model]="paginationInfo" (changed)="onPageChanged($event)"></esh-pager>
|
||||
</div>
|
||||
<div *ngIf="catalog?.data.length == 0">
|
||||
<span>THERE ARE NO RESULTS THAT MATCH YOUR SEARCH</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -25,19 +25,19 @@
|
||||
$filter-padding: .5rem;
|
||||
|
||||
&-filter {
|
||||
-webkit-appearance: none;
|
||||
background-color: transparent;
|
||||
border-color: $color-brand-bright;
|
||||
color: $color-foreground-brighter;
|
||||
cursor: pointer;
|
||||
margin-right: 1rem;
|
||||
margin-top: .5rem;
|
||||
min-width: 140px;
|
||||
outline-color: $color-secondary;
|
||||
padding-bottom: 0;
|
||||
padding-left: $filter-padding;
|
||||
padding-right: $filter-padding;
|
||||
padding-top: $filter-padding * 3;
|
||||
min-width: 140px;
|
||||
-webkit-appearance: none;
|
||||
|
||||
option {
|
||||
background-color: $color-brand;
|
||||
@ -53,8 +53,8 @@
|
||||
color: rgba($color-foreground-brighter, .5);
|
||||
content: attr(data-title);
|
||||
font-size: $font-size-xs;
|
||||
margin-top: $font-size-xs;
|
||||
margin-left: $filter-padding;
|
||||
margin-top: $font-size-xs;
|
||||
position: absolute;
|
||||
text-transform: uppercase;
|
||||
z-index: 1;
|
||||
@ -62,8 +62,8 @@
|
||||
|
||||
&::after {
|
||||
background-image: url('../../images/arrow-down.png');
|
||||
height: 7px; //png height
|
||||
content: '';
|
||||
height: 7px; //png height
|
||||
position: absolute;
|
||||
right: $filter-padding * 3;
|
||||
top: $filter-padding * 5;
|
||||
@ -92,8 +92,8 @@
|
||||
}
|
||||
|
||||
&-item {
|
||||
text-align: center;
|
||||
margin-bottom: 1.5rem;
|
||||
text-align: center;
|
||||
width: 33%;
|
||||
|
||||
@media screen and (max-width: $media-screen-m) {
|
||||
@ -112,7 +112,7 @@
|
||||
|
||||
&-button {
|
||||
background-color: $color-secondary;
|
||||
border: none;
|
||||
border: 0;
|
||||
color: $color-foreground-brighter;
|
||||
cursor: pointer;
|
||||
font-size: $font-size-m;
|
||||
@ -136,9 +136,9 @@
|
||||
}
|
||||
|
||||
&-price {
|
||||
text-align: center;
|
||||
font-weight: 900;
|
||||
font-size: 28px;
|
||||
font-weight: 900;
|
||||
text-align: center;
|
||||
|
||||
&::before {
|
||||
content: '$';
|
||||
|
@ -1,4 +1,4 @@
|
||||
@import '../../_variables.scss';
|
||||
@import '../../variables';
|
||||
|
||||
.esh-orders_detail {
|
||||
min-height: 80vh;
|
||||
@ -32,6 +32,7 @@
|
||||
}
|
||||
|
||||
$item-height: 8rem;
|
||||
|
||||
&-item {
|
||||
font-size: $font-size-m;
|
||||
font-weight: $font-weight-semilight;
|
||||
|
@ -1,4 +1,4 @@
|
||||
@import '../../_variables.scss';
|
||||
@import '../../variables';
|
||||
|
||||
.esh-orders_new {
|
||||
min-height: 80vh;
|
||||
@ -13,8 +13,8 @@
|
||||
&-back {
|
||||
color: rgba($color-foreground-brighter, .4);
|
||||
line-height: $header-height;
|
||||
text-transform: uppercase;
|
||||
text-decoration: none;
|
||||
text-transform: uppercase;
|
||||
transition: color $animation-speed-default;
|
||||
|
||||
&:hover {
|
||||
@ -32,24 +32,26 @@
|
||||
}
|
||||
|
||||
&-placeOrder {
|
||||
float: right;
|
||||
margin-top: 40px;
|
||||
margin-bottom: 40px;
|
||||
background-color: #83d01b;
|
||||
color: #fff;
|
||||
padding: 10px 20px 10px 20px;
|
||||
background-color: $color-secondary;
|
||||
border: 0;
|
||||
border-radius: 0;
|
||||
border: none;
|
||||
width: 255px;
|
||||
color: $color-foreground-brighter;
|
||||
display: inline-block;
|
||||
font-size: 1rem;
|
||||
font-weight: $font-weight-normal;
|
||||
margin-top: 1rem;
|
||||
padding: 1rem 1.5rem;
|
||||
text-align: center;
|
||||
text-transform: uppercase;
|
||||
height: 45px;
|
||||
font-size: 16px;
|
||||
font-weight: normal;
|
||||
transition: all $animation-speed-default;
|
||||
|
||||
&:hover {
|
||||
background-color: $color-secondary-darker;
|
||||
transition: all $animation-speed-default;
|
||||
}
|
||||
}
|
||||
|
||||
&-titles {
|
||||
&-titles {
|
||||
padding-bottom: 1rem;
|
||||
padding-top: 2rem;
|
||||
}
|
||||
@ -70,6 +72,7 @@
|
||||
}
|
||||
|
||||
$item-height: 8rem;
|
||||
|
||||
&-item {
|
||||
font-size: $font-size-m;
|
||||
font-weight: $font-weight-semilight;
|
||||
@ -91,36 +94,3 @@
|
||||
height: $item-height;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@media screen and (min-width: 992px) {
|
||||
.form-input {
|
||||
width: 360px;
|
||||
max-width: 360px;
|
||||
}
|
||||
}
|
||||
|
||||
.form-input {
|
||||
border-radius: 0;
|
||||
padding: 10px;
|
||||
height: 45px;
|
||||
}
|
||||
|
||||
.form-input-small {
|
||||
max-width: 100px!important;
|
||||
}
|
||||
|
||||
.form-input-medium {
|
||||
width: 150px!important;
|
||||
}
|
||||
|
||||
.alert{
|
||||
padding-left: 0px;
|
||||
}
|
||||
|
||||
.alert-danger {
|
||||
background-color:transparent;
|
||||
border:none;
|
||||
color: #fb0d0d;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
@ -47,7 +47,6 @@ export class OrdersNewComponent implements OnInit {
|
||||
this.service.postOrder(this.order).subscribe(res => {
|
||||
//this will emit an observable. Basket service is subscribed to this observable, and will react deleting the basket for the current user.
|
||||
this.basketEvents.orderCreated();
|
||||
|
||||
|
||||
this.router.navigate(['orders']);
|
||||
});
|
||||
|
@ -1,10 +1,11 @@
|
||||
@import '../_variables.scss';
|
||||
@import '../variables';
|
||||
|
||||
.esh-orders {
|
||||
min-height: 80vh;
|
||||
overflow-x: hidden;
|
||||
|
||||
$header-height: 4rem;
|
||||
|
||||
&-header {
|
||||
background-color: #00A69C;
|
||||
height: $header-height;
|
||||
@ -13,8 +14,8 @@
|
||||
&-back {
|
||||
color: rgba($color-foreground-brighter, .4);
|
||||
line-height: $header-height;
|
||||
text-transform: uppercase;
|
||||
text-decoration: none;
|
||||
text-transform: uppercase;
|
||||
transition: color $animation-speed-default;
|
||||
|
||||
&:hover {
|
||||
|
@ -1,4 +1,4 @@
|
||||
@import "../../../variables";
|
||||
@import '../../../variables';
|
||||
|
||||
.esh-header {
|
||||
$header-height: 4rem;
|
||||
@ -9,8 +9,8 @@
|
||||
&-back {
|
||||
color: rgba($color-foreground-brighter, .5);
|
||||
line-height: $header-height;
|
||||
text-transform: uppercase;
|
||||
text-decoration: none;
|
||||
text-transform: uppercase;
|
||||
transition: color $animation-speed-default;
|
||||
|
||||
&:hover {
|
||||
|
@ -1,4 +1,4 @@
|
||||
@import "../../../variables";
|
||||
@import '../../../variables';
|
||||
|
||||
.esh-identity {
|
||||
line-height: 3rem;
|
||||
@ -30,10 +30,10 @@
|
||||
background: $color-background-brighter;
|
||||
height: 0;
|
||||
min-width: 14rem;
|
||||
right: 0;
|
||||
overflow: hidden;
|
||||
padding: .5rem;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 2.5rem;
|
||||
transition: height $animation-speed-default;
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
@import "../../../variables";
|
||||
@import '../../../variables';
|
||||
|
||||
.esh-pager {
|
||||
|
||||
@ -27,4 +27,4 @@
|
||||
margin: 0 $margin / 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,12 +4,13 @@ import { Subject } from 'rxjs/Subject';
|
||||
import { ICatalogItem } from '../models/catalogItem.model';
|
||||
import { IBasketItem } from '../models/basketItem.model';
|
||||
import { IBasket } from '../models/basket.model';
|
||||
import { SecurityService } from '../services/security.service';
|
||||
|
||||
@Injectable()
|
||||
export class BasketWrapperService {
|
||||
public basket: IBasket
|
||||
|
||||
constructor() { }
|
||||
constructor(private identityService: SecurityService) { }
|
||||
|
||||
//observable that is fired when a product is added to the cart
|
||||
private addItemToBasketSource = new Subject<IBasketItem>();
|
||||
@ -19,15 +20,19 @@ export class BasketWrapperService {
|
||||
orderCreated$ = this.orderCreatedSource.asObservable();
|
||||
|
||||
addItemToBasket(item: ICatalogItem) {
|
||||
let basket: IBasketItem = {
|
||||
pictureUrl: item.pictureUri,
|
||||
productId: item.id,
|
||||
productName: item.name,
|
||||
quantity: 1,
|
||||
unitPrice: item.price,
|
||||
id: ''
|
||||
if (this.identityService.IsAuthorized) {
|
||||
let basket: IBasketItem = {
|
||||
pictureUrl: item.pictureUri,
|
||||
productId: item.id,
|
||||
productName: item.name,
|
||||
quantity: 1,
|
||||
unitPrice: item.price,
|
||||
id: ''
|
||||
}
|
||||
this.addItemToBasketSource.next(basket);
|
||||
} else {
|
||||
this.identityService.Authorize();
|
||||
}
|
||||
this.addItemToBasketSource.next(basket);
|
||||
}
|
||||
|
||||
orderCreated() {
|
||||
|
@ -50,8 +50,11 @@ export class DataService {
|
||||
options.headers.append("Authorization", "Bearer " + this.securityService.GetToken());
|
||||
}
|
||||
|
||||
console.log('data.service deleting');
|
||||
return this.http.delete(url, options).map(
|
||||
(res: Response) => {
|
||||
console.log('response from server in delete operation');
|
||||
console.log(res);
|
||||
return res;
|
||||
}).catch(this.handleError);
|
||||
}
|
||||
|
@ -0,0 +1,63 @@
|
||||
|
||||
//namespace FunctionalTests.Services.Basket
|
||||
//{
|
||||
// using Microsoft.eShopOnContainers.Services.Basket.API;
|
||||
// using Microsoft.eShopOnContainers.Services.Basket.API.Model;
|
||||
// using Microsoft.Extensions.Logging;
|
||||
// using Microsoft.Extensions.Options;
|
||||
// using System.Collections.Generic;
|
||||
// using System.Threading.Tasks;
|
||||
// using Xunit;
|
||||
|
||||
|
||||
// public class RedisBasketRepositoryTests
|
||||
// {
|
||||
// [Fact]
|
||||
// public async Task UpdateBasket_return_and_add_basket()
|
||||
// {
|
||||
// var redisBasketRepository = BuildBasketRepository();
|
||||
|
||||
// var basket = await redisBasketRepository.UpdateBasket(new CustomerBasket("customerId")
|
||||
// {
|
||||
// BuyerId = "buyerId",
|
||||
// Items = BuildBasketItems()
|
||||
// });
|
||||
|
||||
// Assert.NotNull(basket);
|
||||
// Assert.Equal(1, basket.Items.Count);
|
||||
// }
|
||||
|
||||
// [Fact]
|
||||
// public async Task GetBasket_return_existing_basket()
|
||||
// {
|
||||
// }
|
||||
|
||||
// RedisBasketRepository BuildBasketRepository()
|
||||
// {
|
||||
// var loggerFactory = new LoggerFactory();
|
||||
|
||||
// var options = Options.Create<BasketSettings>(new BasketSettings()
|
||||
// {
|
||||
// ConnectionString = "127.0.0.1"
|
||||
// });
|
||||
|
||||
// return new RedisBasketRepository(options, loggerFactory);
|
||||
// }
|
||||
|
||||
// List<BasketItem> BuildBasketItems()
|
||||
// {
|
||||
// return new List<BasketItem>()
|
||||
// {
|
||||
// new BasketItem()
|
||||
// {
|
||||
// Id = "basketId",
|
||||
// PictureUrl = "pictureurl",
|
||||
// ProductId = "productId",
|
||||
// ProductName = "productName",
|
||||
// Quantity = 1,
|
||||
// UnitPrice = 1
|
||||
// }
|
||||
// };
|
||||
// }
|
||||
// }
|
||||
//}
|
@ -31,7 +31,7 @@ namespace FunctionalTests.Services.Catalog
|
||||
return $"api/v1/catalog/items?pageIndex={pageIndex}&pageSize={pageCount}";
|
||||
}
|
||||
|
||||
public static string Filtered(int catalogTypeId,int catalogBrandId)
|
||||
public static string Filtered(int catalogTypeId, int catalogBrandId)
|
||||
{
|
||||
return $"api/v1/catalog/items/type/{catalogTypeId}/brand/{catalogBrandId}";
|
||||
}
|
||||
|
@ -4,7 +4,7 @@
|
||||
using Xunit;
|
||||
|
||||
public class CatalogScenarios
|
||||
:CatalogScenarioBase
|
||||
: CatalogScenarioBase
|
||||
{
|
||||
[Fact]
|
||||
public async Task Get_get_all_catalogitems_and_response_ok_status_code()
|
||||
@ -24,7 +24,7 @@
|
||||
using (var server = CreateServer())
|
||||
{
|
||||
var response = await server.CreateClient()
|
||||
.GetAsync(Get.Paginated(0,4));
|
||||
.GetAsync(Get.Paginated(0, 4));
|
||||
|
||||
response.EnsureSuccessStatusCode();
|
||||
}
|
||||
|
@ -56,7 +56,7 @@
|
||||
var content = new StringContent(BuildOrderWithInvalidExperationTime(), UTF8Encoding.UTF8, "application/json");
|
||||
|
||||
var response = await server.CreateClient()
|
||||
.PostAsync(Post.AddNewOrder,content);
|
||||
.PostAsync(Post.AddNewOrder, content);
|
||||
|
||||
Assert.True(response.StatusCode == System.Net.HttpStatusCode.BadRequest);
|
||||
}
|
||||
|
@ -2,14 +2,17 @@
|
||||
"version": "1.0.0-*",
|
||||
|
||||
"dependencies": {
|
||||
"Ordering.API": "1.0.0-*",
|
||||
"Microsoft.NETCore.App": "1.1.0",
|
||||
"Microsoft.AspNetCore.TestHost": "1.1.0",
|
||||
"dotnet-test-xunit": "2.2.0-preview2-build1029",
|
||||
"xunit": "2.2.0-beta4-build3444",
|
||||
"Catalog.API": "1.0.0-*",
|
||||
"xunit": "2.2.0-beta4-build3444"
|
||||
"Ordering.API": "1.0.0-*"
|
||||
},
|
||||
"testRunner": "xunit",
|
||||
"runtimes": {
|
||||
"win10-x64": {}
|
||||
},
|
||||
"frameworks": {
|
||||
"netcoreapp1.0": {
|
||||
"dependencies": {
|
||||
|
@ -1,18 +1,15 @@
|
||||
using MediatR;
|
||||
using Microsoft.eShopOnContainers.Services.Ordering.Api.Application.Commands;
|
||||
using Microsoft.eShopOnContainers.Services.Ordering.Domain;
|
||||
using Microsoft.eShopOnContainers.Services.Ordering.Domain.Repositories;
|
||||
using Microsoft.eShopOnContainers.Services.Ordering.Domain.SeedWork;
|
||||
using Moq;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Xunit;
|
||||
|
||||
namespace UnitTest.Ordering.Application
|
||||
namespace UnitTest.Ordering.Application
|
||||
{
|
||||
using Microsoft.eShopOnContainers.Services.Ordering.Api.Application.Commands;
|
||||
using Microsoft.eShopOnContainers.Services.Ordering.Domain;
|
||||
using Microsoft.eShopOnContainers.Services.Ordering.Domain.Repositories;
|
||||
using Moq;
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Xunit;
|
||||
|
||||
|
||||
public class NewOrderRequestHandlerTest
|
||||
{
|
||||
private readonly Mock<IBuyerRepository> _buyerRepositoryMock;
|
||||
@ -20,25 +17,29 @@ namespace UnitTest.Ordering.Application
|
||||
|
||||
public NewOrderRequestHandlerTest()
|
||||
{
|
||||
//Mocks;
|
||||
|
||||
_buyerRepositoryMock = new Mock<IBuyerRepository>();
|
||||
_orderRepositoryMock = new Mock<IOrderRepository>();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Handle_ReturnsTrue_WhenOrderIsPersistedSuccesfully()
|
||||
public async Task Handle_returns_true_when_order_is_persisted_succesfully()
|
||||
{
|
||||
// Arrange
|
||||
_buyerRepositoryMock.Setup(buyerRepo => buyerRepo.FindAsync(FakeOrderRequestWithBuyer().Buyer))
|
||||
.Returns(Task.FromResult<Buyer>(FakeBuyer()));
|
||||
|
||||
_buyerRepositoryMock.Setup(buyerRepo => buyerRepo.UnitOfWork.SaveChangesAsync(default(CancellationToken)))
|
||||
.Returns(Task.FromResult(1));
|
||||
|
||||
_orderRepositoryMock.Setup(or => or.Add(FakeOrder())).Returns(FakeOrder());
|
||||
_orderRepositoryMock.Setup(or => or.UnitOfWork.SaveChangesAsync(default(CancellationToken))).Returns(Task.FromResult(1));
|
||||
_orderRepositoryMock.Setup(or => or.Add(FakeOrder()))
|
||||
.Returns(FakeOrder());
|
||||
|
||||
_orderRepositoryMock.Setup(or => or.UnitOfWork.SaveChangesAsync(default(CancellationToken)))
|
||||
.Returns(Task.FromResult(1));
|
||||
|
||||
//Act
|
||||
var handler = new NewOrderRequestHandler(_buyerRepositoryMock.Object, _orderRepositoryMock.Object);
|
||||
var handler = new NewOrderCommandHandler(_buyerRepositoryMock.Object, _orderRepositoryMock.Object);
|
||||
var result = await handler.Handle(FakeOrderRequestWithBuyer());
|
||||
|
||||
//Assert
|
||||
@ -46,18 +47,20 @@ namespace UnitTest.Ordering.Application
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Handle_ReturnsFalse_WhenOrderIsNotPersisted()
|
||||
public async Task Handle_return_false_if_order_is_not_persisted()
|
||||
{
|
||||
_buyerRepositoryMock.Setup(buyerRepo => buyerRepo.FindAsync(FakeOrderRequestWithBuyer().Buyer))
|
||||
.Returns(Task.FromResult<Buyer>(FakeBuyer()));
|
||||
|
||||
_buyerRepositoryMock.Setup(buyerRepo => buyerRepo.UnitOfWork.SaveChangesAsync(default(CancellationToken)))
|
||||
.Returns(Task.FromResult(1));
|
||||
|
||||
_orderRepositoryMock.Setup(or => or.Add(FakeOrder())).Returns(FakeOrder());
|
||||
_orderRepositoryMock.Setup(or => or.UnitOfWork.SaveChangesAsync(default(CancellationToken))).Returns(Task.FromResult(0));
|
||||
_orderRepositoryMock.Setup(or => or.UnitOfWork.SaveChangesAsync(default(CancellationToken)))
|
||||
.Returns(Task.FromResult(0));
|
||||
|
||||
//Act
|
||||
var handler = new NewOrderRequestHandler(_buyerRepositoryMock.Object, _orderRepositoryMock.Object);
|
||||
var handler = new NewOrderCommandHandler(_buyerRepositoryMock.Object, _orderRepositoryMock.Object);
|
||||
var result = await handler.Handle(FakeOrderRequestWithBuyer());
|
||||
|
||||
//Assert
|
||||
@ -77,9 +80,9 @@ namespace UnitTest.Ordering.Application
|
||||
};
|
||||
}
|
||||
|
||||
private NewOrderRequest FakeOrderRequestWithBuyer()
|
||||
private NewOrderCommand FakeOrderRequestWithBuyer()
|
||||
{
|
||||
return new NewOrderRequest
|
||||
return new NewOrderCommand
|
||||
{
|
||||
Buyer = "1234",
|
||||
CardNumber = "1234",
|
||||
|
@ -1,136 +0,0 @@
|
||||
using System;
|
||||
using Xunit;
|
||||
using System.Threading.Tasks;
|
||||
using Moq;
|
||||
using MediatR;
|
||||
using Microsoft.eShopOnContainers.Services.Ordering.API.Controllers;
|
||||
using Microsoft.eShopOnContainers.Services.Ordering.Api.Application.Commands;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.eShopOnContainers.Services.Ordering.API.Infrastructure.Services;
|
||||
using Microsoft.eShopOnContainers.Services.Ordering.Api.Application.Queries;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace UnitTest.Ordering.Controllers
|
||||
{
|
||||
public class OrderControllerTest
|
||||
{
|
||||
private readonly Mock<IMediator> _mediatorMock;
|
||||
private readonly Mock<IIdentityService> _identityMock;
|
||||
private readonly Mock<IOrderQueries> _queriesMock;
|
||||
private readonly string _userIdentity;
|
||||
|
||||
public OrderControllerTest()
|
||||
{
|
||||
//Mocks;
|
||||
_mediatorMock = new Mock<IMediator>();
|
||||
_identityMock = new Mock<IIdentityService>();
|
||||
_queriesMock = new Mock<IOrderQueries>();
|
||||
_userIdentity = Guid.NewGuid().ToString();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task AddOrder_ReturnsBadRequestResult_WhenPersitenceOperationFails()
|
||||
{
|
||||
// Arrange
|
||||
var orderRequest = new object() as IAsyncRequest<bool>;
|
||||
|
||||
_mediatorMock.Setup(mediator => mediator.SendAsync(OrderFakeNotExpired()))
|
||||
.Returns(Task.FromResult(false));
|
||||
|
||||
_identityMock.Setup(identity => identity.GetUserIdentity())
|
||||
.Returns(Guid.NewGuid().ToString());
|
||||
|
||||
var controller = new OrdersController(_mediatorMock.Object, _queriesMock.Object, _identityMock.Object);
|
||||
|
||||
// Act
|
||||
var badRequestResult = await controller.AddOrder(OrderFakeNotExpired());
|
||||
|
||||
// Assert
|
||||
Assert.IsType<BadRequestResult>(badRequestResult);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetOrder_ReturnsNotFound_WhenItemNotFound()
|
||||
{
|
||||
// Arrange
|
||||
_queriesMock.Setup(queries => queries.GetOrder(1))
|
||||
.Throws(new KeyNotFoundException());
|
||||
|
||||
var controller = new OrdersController(_mediatorMock.Object, _queriesMock.Object, _identityMock.Object);
|
||||
|
||||
// Act
|
||||
var notFoundResult = await controller.GetOrder(1);
|
||||
|
||||
// Assert
|
||||
Assert.IsType<NotFoundResult>(notFoundResult);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetOrder_ReturnsOkObjecResult_WheItemFound()
|
||||
{
|
||||
// Arrange
|
||||
_queriesMock.Setup(queries => queries.GetOrder(1))
|
||||
.Returns(Task.FromResult(new object()));
|
||||
|
||||
var controller = new OrdersController(_mediatorMock.Object, _queriesMock.Object, _identityMock.Object);
|
||||
|
||||
// Act
|
||||
var OkObjectResult = await controller.GetOrder(1);
|
||||
|
||||
// Assert
|
||||
Assert.IsType<OkObjectResult>(OkObjectResult);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetOrders_ReturnsOkObjectResult()
|
||||
{
|
||||
// Arrange
|
||||
_queriesMock.Setup(queries => queries.GetOrders())
|
||||
.Returns(Task.FromResult(new object()));
|
||||
|
||||
var controller = new OrdersController(_mediatorMock.Object, _queriesMock.Object, _identityMock.Object);
|
||||
|
||||
// Act
|
||||
var OkObjectResult = await controller.GetOrders();
|
||||
|
||||
// Assert
|
||||
Assert.IsType<OkObjectResult>(OkObjectResult);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetCardTypes()
|
||||
{
|
||||
// Arrange
|
||||
_queriesMock.Setup(queries => queries.GetCardTypes())
|
||||
.Returns(Task.FromResult(new object()));
|
||||
|
||||
var controller = new OrdersController(_mediatorMock.Object, _queriesMock.Object, _identityMock.Object);
|
||||
|
||||
// Act
|
||||
var OkObjectResult = await controller.GetCardTypes();
|
||||
|
||||
// Assert
|
||||
Assert.IsType<OkObjectResult>(OkObjectResult);
|
||||
}
|
||||
|
||||
//Fakes
|
||||
private NewOrderRequest OrderFakeNotExpired()
|
||||
{
|
||||
return new NewOrderRequest()
|
||||
{
|
||||
CardTypeId = 1,
|
||||
CardExpiration = new DateTime(2020, 12, 12),
|
||||
Buyer = _userIdentity
|
||||
};
|
||||
}
|
||||
|
||||
private NewOrderRequest OrderFakeExpired()
|
||||
{
|
||||
return new NewOrderRequest()
|
||||
{
|
||||
CardTypeId = 1,
|
||||
CardExpiration = DateTime.Now.AddYears(-1)
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
@ -1,50 +0,0 @@
|
||||
using System;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using Xunit;
|
||||
using System.Threading.Tasks;
|
||||
using Moq;
|
||||
using MediatR;
|
||||
|
||||
namespace UnitTests
|
||||
{
|
||||
public class OrderControllerTest
|
||||
{
|
||||
private readonly Mock<IMediator> _mock;
|
||||
|
||||
public OrderControllerTest()
|
||||
{
|
||||
//config mock;
|
||||
_mock = new Mock<IMediator>();
|
||||
|
||||
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task AddOrder_ReturnsBadRequestResult_WhenPersitenceOperationFails()
|
||||
{
|
||||
//Add order:
|
||||
var orderRequest = new object() as IAsyncRequest<bool>;
|
||||
_mock.Setup(mediator => mediator.SendAsync(orderRequest))
|
||||
.Returns(Task.FromResult(false));
|
||||
|
||||
// Arrange
|
||||
var controller = new OrdersController(mockRepo.Object);
|
||||
controller.ModelState.AddModelError("SessionName", "Required");
|
||||
var newSession = new HomeController.NewSessionModel();
|
||||
|
||||
// Act
|
||||
var result = await controller.Index(newSession);
|
||||
|
||||
// Assert
|
||||
var badRequestResult = Assert.IsType<BadRequestObjectResult>(result);
|
||||
Assert.IsType<SerializableError>(badRequestResult.Value);
|
||||
}
|
||||
|
||||
|
||||
// Implement Fake method for mock.
|
||||
private MediatorMockForAddOrder()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
@ -1,36 +0,0 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("UnitTests")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("UnitTests")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2016")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("ecbb8dc1-22ea-42d2-a45a-4ae800c73356")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
@ -1,117 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{ECBB8DC1-22EA-42D2-A45A-4AE800C73356}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>UnitTests</RootNamespace>
|
||||
<AssemblyName>UnitTests</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<ProjectTypeGuids>{3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
|
||||
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">10.0</VisualStudioVersion>
|
||||
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
|
||||
<ReferencePath>$(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages</ReferencePath>
|
||||
<IsCodedUITest>False</IsCodedUITest>
|
||||
<TestProjectType>UnitTest</TestProjectType>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Castle.Core, Version=3.3.0.0, Culture=neutral, PublicKeyToken=407dd0808d44fbdc, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\..\..\packages\Castle.Core.3.3.3\lib\net45\Castle.Core.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="MediatR, Version=2.1.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\..\..\packages\MediatR.2.1.0\lib\net45\MediatR.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Moq, Version=4.6.38.0, Culture=neutral, PublicKeyToken=69f491c39445e920, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\..\..\packages\Moq.4.6.38-alpha\lib\net45\Moq.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="xunit.abstractions, Version=2.0.0.0, Culture=neutral, PublicKeyToken=8d05b1bb7a6fdb6c, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\..\..\packages\xunit.abstractions.2.0.1\lib\net35\xunit.abstractions.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="xunit.assert, Version=2.2.0.3444, Culture=neutral, PublicKeyToken=8d05b1bb7a6fdb6c, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\..\..\packages\xunit.assert.2.2.0-beta4-build3444\lib\netstandard1.0\xunit.assert.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="xunit.core, Version=2.2.0.3444, Culture=neutral, PublicKeyToken=8d05b1bb7a6fdb6c, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\..\..\packages\xunit.extensibility.core.2.2.0-beta4-build3444\lib\net45\xunit.core.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="xunit.execution.desktop, Version=2.2.0.3444, Culture=neutral, PublicKeyToken=8d05b1bb7a6fdb6c, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\..\..\packages\xunit.extensibility.execution.2.2.0-beta4-build3444\lib\net45\xunit.execution.desktop.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
<Choose>
|
||||
<When Condition="('$(VisualStudioVersion)' == '10.0' or '$(VisualStudioVersion)' == '') and '$(TargetFrameworkVersion)' == 'v3.5'">
|
||||
<ItemGroup>
|
||||
<Reference Include="Microsoft.VisualStudio.QualityTools.UnitTestFramework, Version=10.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL" />
|
||||
</ItemGroup>
|
||||
</When>
|
||||
<Otherwise>
|
||||
<ItemGroup>
|
||||
<Reference Include="Microsoft.VisualStudio.QualityTools.UnitTestFramework" />
|
||||
</ItemGroup>
|
||||
</Otherwise>
|
||||
</Choose>
|
||||
<ItemGroup>
|
||||
<Compile Include="Ordering\OrderControllerTest.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="Catalog\" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<Choose>
|
||||
<When Condition="'$(VisualStudioVersion)' == '10.0' And '$(IsCodedUITest)' == 'True'">
|
||||
<ItemGroup>
|
||||
<Reference Include="Microsoft.VisualStudio.QualityTools.CodedUITestFramework, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.VisualStudio.TestTools.UITest.Common, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.VisualStudio.TestTools.UITest.Extension, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.VisualStudio.TestTools.UITesting, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
</When>
|
||||
</Choose>
|
||||
<Import Project="$(VSToolsPath)\TeamTest\Microsoft.TestTools.targets" Condition="Exists('$(VSToolsPath)\TeamTest\Microsoft.TestTools.targets')" />
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
</Target>
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
@ -1,12 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="Castle.Core" version="3.3.3" targetFramework="net452" />
|
||||
<package id="MediatR" version="2.1.0" targetFramework="net452" />
|
||||
<package id="Moq" version="4.6.38-alpha" targetFramework="net452" />
|
||||
<package id="xunit" version="2.2.0-beta4-build3444" targetFramework="net452" />
|
||||
<package id="xunit.abstractions" version="2.0.1" targetFramework="net452" />
|
||||
<package id="xunit.assert" version="2.2.0-beta4-build3444" targetFramework="net452" />
|
||||
<package id="xunit.core" version="2.2.0-beta4-build3444" targetFramework="net452" />
|
||||
<package id="xunit.extensibility.core" version="2.2.0-beta4-build3444" targetFramework="net452" />
|
||||
<package id="xunit.extensibility.execution" version="2.2.0-beta4-build3444" targetFramework="net452" />
|
||||
</packages>
|