Skip to content

Commit a18cec2

Browse files
committed
Missing aggregator project
1 parent 8cfb74f commit a18cec2

34 files changed

Lines changed: 970 additions & 7 deletions

docker-compose.override.yml

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ services:
5858
- BasketApiClient=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5103
5959
- OrderingApiClient=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5102
6060
- MobileShoppingAggClient=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5120
61+
- WebShoppingAggClient=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5121
6162
- UseCustomizationData=True
6263
- ApplicationInsights__InstrumentationKey=${INSTRUMENTATION_KEY}
6364
- OrchestratorType=${ORCHESTRATOR_TYPE}
@@ -262,4 +263,14 @@ services:
262263
- urls__orders=http://ordering.api
263264
- urls__identity=http://identity.api #Local: You need to open your local dev-machine firewall at range 5100-5110.
264265
ports:
265-
- "5120:80"
266+
- "5120:80"
267+
268+
webshoppingagg:
269+
environment:
270+
- ASPNETCORE_ENVIRONMENT=Development
271+
- urls__basket=http://basket.api
272+
- urls__catalog=http://catalog.api
273+
- urls__orders=http://ordering.api
274+
- urls__identity=http://identity.api #Local: You need to open your local dev-machine firewall at range 5100-5110.
275+
ports:
276+
- "5121:80"

docker-compose.prod.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ services:
6565
- BasketApiClient=http://${ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP}:5103
6666
- OrderingApiClient=http://${ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP}:5102
6767
- MobileShoppingAggClient=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5120
68+
- WebShoppingAggClient=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5120
6869
- UseCustomizationData=True
6970
- ApplicationInsights__InstrumentationKey=${INSTRUMENTATION_KEY}
7071
- OrchestratorType=${ORCHESTRATOR_TYPE}

docker-compose.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,3 +138,9 @@ services:
138138
context: .
139139
dockerfile: src/Aggregators/Mobile.Shopping.HttpAggregator/Dockerfile
140140

141+
webshoppingagg:
142+
image: eshop/webshoppingagg
143+
build:
144+
context: .
145+
dockerfile: src/Aggregators/Mobile.Shopping.HttpAggregator/Dockerfile
146+

eShopOnContainers-ServicesAndWebApps.sln

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Aggregators", "Aggregators"
105105
EndProject
106106
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Mobile.Shopping.HttpAggregator", "src\Aggregators\Mobile.Shopping.HttpAggregator\Mobile.Shopping.HttpAggregator.csproj", "{6E99F232-1536-424F-A28C-91692C8FD325}"
107107
EndProject
108+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Web.Shopping.HttpAggregator", "src\Aggregators\Web.Shopping.HttpAggregator\Web.Shopping.HttpAggregator.csproj", "{714CE0A1-E8BE-4CF1-8948-C1202E1526E2}"
109+
EndProject
108110
Global
109111
GlobalSection(SolutionConfigurationPlatforms) = preSolution
110112
Ad-Hoc|Any CPU = Ad-Hoc|Any CPU
@@ -1415,6 +1417,54 @@ Global
14151417
{6E99F232-1536-424F-A28C-91692C8FD325}.Release|x64.Build.0 = Release|Any CPU
14161418
{6E99F232-1536-424F-A28C-91692C8FD325}.Release|x86.ActiveCfg = Release|Any CPU
14171419
{6E99F232-1536-424F-A28C-91692C8FD325}.Release|x86.Build.0 = Release|Any CPU
1420+
{714CE0A1-E8BE-4CF1-8948-C1202E1526E2}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU
1421+
{714CE0A1-E8BE-4CF1-8948-C1202E1526E2}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU
1422+
{714CE0A1-E8BE-4CF1-8948-C1202E1526E2}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU
1423+
{714CE0A1-E8BE-4CF1-8948-C1202E1526E2}.Ad-Hoc|ARM.Build.0 = Debug|Any CPU
1424+
{714CE0A1-E8BE-4CF1-8948-C1202E1526E2}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU
1425+
{714CE0A1-E8BE-4CF1-8948-C1202E1526E2}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU
1426+
{714CE0A1-E8BE-4CF1-8948-C1202E1526E2}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
1427+
{714CE0A1-E8BE-4CF1-8948-C1202E1526E2}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
1428+
{714CE0A1-E8BE-4CF1-8948-C1202E1526E2}.Ad-Hoc|x64.ActiveCfg = Debug|Any CPU
1429+
{714CE0A1-E8BE-4CF1-8948-C1202E1526E2}.Ad-Hoc|x64.Build.0 = Debug|Any CPU
1430+
{714CE0A1-E8BE-4CF1-8948-C1202E1526E2}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU
1431+
{714CE0A1-E8BE-4CF1-8948-C1202E1526E2}.Ad-Hoc|x86.Build.0 = Debug|Any CPU
1432+
{714CE0A1-E8BE-4CF1-8948-C1202E1526E2}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU
1433+
{714CE0A1-E8BE-4CF1-8948-C1202E1526E2}.AppStore|Any CPU.Build.0 = Debug|Any CPU
1434+
{714CE0A1-E8BE-4CF1-8948-C1202E1526E2}.AppStore|ARM.ActiveCfg = Debug|Any CPU
1435+
{714CE0A1-E8BE-4CF1-8948-C1202E1526E2}.AppStore|ARM.Build.0 = Debug|Any CPU
1436+
{714CE0A1-E8BE-4CF1-8948-C1202E1526E2}.AppStore|iPhone.ActiveCfg = Debug|Any CPU
1437+
{714CE0A1-E8BE-4CF1-8948-C1202E1526E2}.AppStore|iPhone.Build.0 = Debug|Any CPU
1438+
{714CE0A1-E8BE-4CF1-8948-C1202E1526E2}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU
1439+
{714CE0A1-E8BE-4CF1-8948-C1202E1526E2}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU
1440+
{714CE0A1-E8BE-4CF1-8948-C1202E1526E2}.AppStore|x64.ActiveCfg = Debug|Any CPU
1441+
{714CE0A1-E8BE-4CF1-8948-C1202E1526E2}.AppStore|x64.Build.0 = Debug|Any CPU
1442+
{714CE0A1-E8BE-4CF1-8948-C1202E1526E2}.AppStore|x86.ActiveCfg = Debug|Any CPU
1443+
{714CE0A1-E8BE-4CF1-8948-C1202E1526E2}.AppStore|x86.Build.0 = Debug|Any CPU
1444+
{714CE0A1-E8BE-4CF1-8948-C1202E1526E2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
1445+
{714CE0A1-E8BE-4CF1-8948-C1202E1526E2}.Debug|Any CPU.Build.0 = Debug|Any CPU
1446+
{714CE0A1-E8BE-4CF1-8948-C1202E1526E2}.Debug|ARM.ActiveCfg = Debug|Any CPU
1447+
{714CE0A1-E8BE-4CF1-8948-C1202E1526E2}.Debug|ARM.Build.0 = Debug|Any CPU
1448+
{714CE0A1-E8BE-4CF1-8948-C1202E1526E2}.Debug|iPhone.ActiveCfg = Debug|Any CPU
1449+
{714CE0A1-E8BE-4CF1-8948-C1202E1526E2}.Debug|iPhone.Build.0 = Debug|Any CPU
1450+
{714CE0A1-E8BE-4CF1-8948-C1202E1526E2}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
1451+
{714CE0A1-E8BE-4CF1-8948-C1202E1526E2}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
1452+
{714CE0A1-E8BE-4CF1-8948-C1202E1526E2}.Debug|x64.ActiveCfg = Debug|Any CPU
1453+
{714CE0A1-E8BE-4CF1-8948-C1202E1526E2}.Debug|x64.Build.0 = Debug|Any CPU
1454+
{714CE0A1-E8BE-4CF1-8948-C1202E1526E2}.Debug|x86.ActiveCfg = Debug|Any CPU
1455+
{714CE0A1-E8BE-4CF1-8948-C1202E1526E2}.Debug|x86.Build.0 = Debug|Any CPU
1456+
{714CE0A1-E8BE-4CF1-8948-C1202E1526E2}.Release|Any CPU.ActiveCfg = Release|Any CPU
1457+
{714CE0A1-E8BE-4CF1-8948-C1202E1526E2}.Release|Any CPU.Build.0 = Release|Any CPU
1458+
{714CE0A1-E8BE-4CF1-8948-C1202E1526E2}.Release|ARM.ActiveCfg = Release|Any CPU
1459+
{714CE0A1-E8BE-4CF1-8948-C1202E1526E2}.Release|ARM.Build.0 = Release|Any CPU
1460+
{714CE0A1-E8BE-4CF1-8948-C1202E1526E2}.Release|iPhone.ActiveCfg = Release|Any CPU
1461+
{714CE0A1-E8BE-4CF1-8948-C1202E1526E2}.Release|iPhone.Build.0 = Release|Any CPU
1462+
{714CE0A1-E8BE-4CF1-8948-C1202E1526E2}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
1463+
{714CE0A1-E8BE-4CF1-8948-C1202E1526E2}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
1464+
{714CE0A1-E8BE-4CF1-8948-C1202E1526E2}.Release|x64.ActiveCfg = Release|Any CPU
1465+
{714CE0A1-E8BE-4CF1-8948-C1202E1526E2}.Release|x64.Build.0 = Release|Any CPU
1466+
{714CE0A1-E8BE-4CF1-8948-C1202E1526E2}.Release|x86.ActiveCfg = Release|Any CPU
1467+
{714CE0A1-E8BE-4CF1-8948-C1202E1526E2}.Release|x86.Build.0 = Release|Any CPU
14181468
EndGlobalSection
14191469
GlobalSection(SolutionProperties) = preSolution
14201470
HideSolutionNode = FALSE
@@ -1465,6 +1515,7 @@ Global
14651515
{E0C5162E-DF26-4341-9E51-14AE800D7505} = {7A58AA20-67F3-48F3-88C8-24EBFE621792}
14661516
{EA378316-9D49-4A6B-858E-D4A25F948A74} = {932D8224-11F6-4D07-B109-DA28AD288A63}
14671517
{6E99F232-1536-424F-A28C-91692C8FD325} = {EA378316-9D49-4A6B-858E-D4A25F948A74}
1518+
{714CE0A1-E8BE-4CF1-8948-C1202E1526E2} = {EA378316-9D49-4A6B-858E-D4A25F948A74}
14681519
EndGlobalSection
14691520
GlobalSection(ExtensibilityGlobals) = postSolution
14701521
SolutionGuid = {25728519-5F0F-4973-8A64-0A81EB4EA8D9}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Threading.Tasks;
5+
6+
namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Config
7+
{
8+
public class UrlsConfig
9+
{
10+
public class CatalogOperations
11+
{
12+
public static string GetItemById(int id) => $"/api/v1/catalog/items/{id}";
13+
public static string GetItemsById(IEnumerable<int> ids) => $"/api/v1/catalog/items?ids={string.Join(',', ids)}";
14+
}
15+
16+
public class BasketOperations
17+
{
18+
public static string GetItemById(string id) => $"/api/v1/basket/{id}";
19+
public static string UpdateBasket() => "/api/v1/basket";
20+
}
21+
22+
public class OrdersOperations
23+
{
24+
public static string GetOrderDraft() => "/api/v1/orders/draft";
25+
}
26+
27+
public string Basket { get; set; }
28+
public string Catalog { get; set; }
29+
public string Orders { get; set; }
30+
}
31+
}
Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
using Microsoft.AspNetCore.Authorization;
2+
using Microsoft.AspNetCore.Mvc;
3+
using Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Models;
4+
using Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Services;
5+
using System;
6+
using System.Collections.Generic;
7+
using System.Linq;
8+
using System.Threading.Tasks;
9+
10+
namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Controllers
11+
{
12+
[Route("api/v1/[controller]")]
13+
[Authorize]
14+
public class BasketController : Controller
15+
{
16+
private readonly ICatalogService _catalog;
17+
private readonly IBasketService _basket;
18+
public BasketController(ICatalogService catalogService, IBasketService basketService)
19+
{
20+
_catalog = catalogService;
21+
_basket = basketService;
22+
}
23+
24+
[HttpPost]
25+
[HttpPut]
26+
public async Task<IActionResult> UpdateAllBasket([FromBody] UpdateBasketRequest data)
27+
{
28+
29+
if (data.Items == null || !data.Items.Any())
30+
{
31+
return BadRequest("Need to pass at least one basket line");
32+
}
33+
34+
// Retrieve the current basket
35+
var currentBasket = await _basket.GetById(data.BuyerId);
36+
if (currentBasket == null)
37+
{
38+
currentBasket = new BasketData(data.BuyerId);
39+
}
40+
41+
var catalogItems = await _catalog.GetCatalogItems(data.Items.Select(x => x.ProductId));
42+
var newBasket = new BasketData(data.BuyerId);
43+
44+
foreach (var bitem in data.Items)
45+
{
46+
var catalogItem = catalogItems.SingleOrDefault(ci => ci.Id == bitem.ProductId);
47+
if (catalogItem == null)
48+
{
49+
return BadRequest($"Basket refers to a non-existing catalog item ({bitem.ProductId})");
50+
}
51+
52+
newBasket.Items.Add(new BasketDataItem()
53+
{
54+
Id = bitem.Id,
55+
ProductId = catalogItem.Id.ToString(),
56+
ProductName = catalogItem.Name,
57+
PictureUrl = catalogItem.PictureUri,
58+
UnitPrice = catalogItem.Price,
59+
Quantity = bitem.Quantity
60+
});
61+
}
62+
63+
await _basket.Update(newBasket);
64+
return Ok(newBasket);
65+
}
66+
67+
[HttpPut]
68+
[Route("items")]
69+
public async Task<IActionResult> UpdateQuantities([FromBody] UpdateBasketItemsRequest data)
70+
{
71+
if (!data.Updates.Any())
72+
{
73+
return BadRequest("No updates sent");
74+
}
75+
76+
// Retrieve the current basket
77+
var currentBasket = await _basket.GetById(data.BasketId);
78+
if (currentBasket == null)
79+
{
80+
return BadRequest($"Basket with id {data.BasketId} not found.");
81+
}
82+
83+
// Update with new quantities
84+
foreach (var update in data.Updates)
85+
{
86+
var basketItem = currentBasket.Items.SingleOrDefault(bitem => bitem.Id == update.BasketItemId);
87+
if (basketItem == null)
88+
{
89+
return BadRequest($"Basket item with id {update.BasketItemId} not found");
90+
}
91+
basketItem.Quantity = update.NewQty;
92+
}
93+
94+
// Save the updated basket
95+
await _basket.Update(currentBasket);
96+
return Ok(currentBasket);
97+
}
98+
99+
[HttpPost]
100+
[Route("items")]
101+
public async Task<IActionResult> AddBasketItem([FromBody] AddBasketItemRequest data)
102+
{
103+
if (data == null || data.Quantity == 0)
104+
{
105+
return BadRequest("Invalid payload");
106+
}
107+
108+
// Step 1: Get the item from catalog
109+
var item = await _catalog.GetCatalogItem(data.CatalogItemId);
110+
111+
//item.PictureUri =
112+
113+
// Step 2: Get current basket status
114+
var currentBasket = (await _basket.GetById(data.BasketId)) ?? new BasketData(data.BasketId);
115+
// Step 3: Merge current status with new product
116+
currentBasket.Items.Add(new BasketDataItem()
117+
{
118+
UnitPrice = item.Price,
119+
PictureUrl = item.PictureUri,
120+
ProductId = item.Id.ToString(),
121+
ProductName = item.Name,
122+
Quantity = data.Quantity,
123+
Id = Guid.NewGuid().ToString()
124+
});
125+
126+
// Step 4: Update basket
127+
await _basket.Update(currentBasket);
128+
129+
130+
return Ok();
131+
}
132+
}
133+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
using Microsoft.AspNetCore.Mvc;
2+
using System;
3+
using System.Collections.Generic;
4+
using System.Linq;
5+
using System.Threading.Tasks;
6+
7+
namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Controllers
8+
{
9+
[Route("")]
10+
public class HomeController : Controller
11+
{
12+
[HttpGet()]
13+
public IActionResult Index()
14+
{
15+
return new RedirectResult("~/swagger");
16+
}
17+
}
18+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
using Microsoft.AspNetCore.Authorization;
2+
using Microsoft.AspNetCore.Mvc;
3+
using Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Services;
4+
using System;
5+
using System.Collections.Generic;
6+
using System.Linq;
7+
using System.Threading.Tasks;
8+
9+
namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Controllers
10+
{
11+
[Route("api/v1/[controller]")]
12+
[Authorize]
13+
public class OrderController : Controller
14+
{
15+
private readonly IBasketService _basketService;
16+
private readonly IOrderApiClient _orderClient;
17+
public OrderController(IBasketService basketService, IOrderApiClient orderClient)
18+
{
19+
_basketService = basketService;
20+
_orderClient = orderClient;
21+
}
22+
23+
[Route("draft/{basketId}")]
24+
[HttpGet]
25+
public async Task<IActionResult> GetOrderDraft(string basketId)
26+
{
27+
if (string.IsNullOrEmpty(basketId))
28+
{
29+
return BadRequest("Need a valid basketid");
30+
}
31+
// Get the basket data and build a order draft based on it
32+
var basket = await _basketService.GetById(basketId);
33+
if (basket == null)
34+
{
35+
return BadRequest($"No basket found for id {basketId}");
36+
}
37+
38+
var orderDraft = await _orderClient.GetOrderDraftFromBasket(basket);
39+
return Ok(orderDraft);
40+
}
41+
}
42+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
FROM microsoft/aspnetcore:2.0.5 AS base
2+
WORKDIR /app
3+
EXPOSE 80
4+
5+
FROM microsoft/aspnetcore-build:2.0 AS build
6+
WORKDIR /src
7+
COPY . .
8+
RUN dotnet restore -nowarn:msb3202,nu1503
9+
WORKDIR /src/src/Aggregators/Web.Shopping.HttpAggregator
10+
RUN dotnet build --no-restore -c Release -o /app
11+
12+
FROM build AS publish
13+
RUN dotnet publish --no-restore -c Release -o /app
14+
15+
FROM base AS final
16+
WORKDIR /app
17+
COPY --from=publish /app .
18+
ENTRYPOINT ["dotnet", "Web.Shopping.HttpAggregator.dll"]
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Filters
2+
{
3+
using Microsoft.AspNetCore.Authorization;
4+
using Swashbuckle.AspNetCore.Swagger;
5+
using Swashbuckle.AspNetCore.SwaggerGen;
6+
using System.Collections.Generic;
7+
using System.Linq;
8+
9+
namespace Basket.API.Infrastructure.Filters
10+
{
11+
public class AuthorizeCheckOperationFilter : IOperationFilter
12+
{
13+
public void Apply(Operation operation, OperationFilterContext context)
14+
{
15+
// Check for authorize attribute
16+
var hasAuthorize = context.ApiDescription.ControllerAttributes().OfType<AuthorizeAttribute>().Any() ||
17+
context.ApiDescription.ActionAttributes().OfType<AuthorizeAttribute>().Any();
18+
19+
if (hasAuthorize)
20+
{
21+
operation.Responses.Add("401", new Response { Description = "Unauthorized" });
22+
operation.Responses.Add("403", new Response { Description = "Forbidden" });
23+
24+
operation.Security = new List<IDictionary<string, IEnumerable<string>>>();
25+
operation.Security.Add(new Dictionary<string, IEnumerable<string>>
26+
{
27+
{ "oauth2", new [] { "Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator" } }
28+
});
29+
}
30+
}
31+
}
32+
}
33+
}

0 commit comments

Comments
 (0)