Browse Source

Merge pull request #73 from abpframework/gterdem/basket_service_refactor

eShopOnAbp: Refactor Basket service
pull/76/head
Halil İbrahim Kalkan 5 years ago
committed by GitHub
parent
commit
8eb2e432ac
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      apps/angular/src/environments/environment.ts
  2. 38
      apps/public-web/src/EShopOnAbp.PublicWeb/ServiceProviders/UserBasketProvider.cs
  3. 26
      apps/public-web/src/EShopOnAbp.PublicWeb/wwwroot/client-proxies/basket-proxy.js
  4. 4
      services/basket/src/EShopOnAbp.BasketService.Application.Contracts/IBasketAppService.cs
  5. 53
      services/basket/src/EShopOnAbp.BasketService.Application/BasketAppService.cs
  6. 2
      services/basket/src/EShopOnAbp.BasketService.Application/BasketProductService.cs
  7. 1
      services/basket/src/EShopOnAbp.BasketService.Domain.Shared/BasketServiceDomainErrorCodes.cs
  8. 3
      services/basket/src/EShopOnAbp.BasketService.Domain.Shared/Localization/BasketService/en.json
  9. 3
      services/basket/src/EShopOnAbp.BasketService.Domain.Shared/Localization/BasketService/tr.json
  10. 9
      services/basket/src/EShopOnAbp.BasketService.Domain/Basket.cs
  11. 53
      services/basket/src/EShopOnAbp.BasketService.HttpApi.Client/ClientProxies/BasketClientProxy.Generated.cs
  12. 7
      services/basket/src/EShopOnAbp.BasketService.HttpApi.Client/ClientProxies/BasketClientProxy.cs
  13. 69
      services/basket/src/EShopOnAbp.BasketService.HttpApi.Client/ClientProxies/basket-generate-proxy.json
  14. 9
      services/catalog/src/EShopOnAbp.CatalogService.Application/Products/ProductAppService.cs
  15. 3
      services/identity/src/EShopOnAbp.IdentityService.HttpApi.Host/DbMigrations/IdentityServerDataSeeder.cs

2
apps/angular/src/environments/environment.ts

@ -13,7 +13,7 @@ export const environment = {
redirectUri: baseUrl,
clientId: 'Web',
//responseType: 'code',
scope: 'offline_access openid profile email phone AccountService IdentityService AdministrationService',
scope: 'offline_access openid profile email phone AccountService IdentityService AdministrationService CatalogService',
//requireHttps: true,
},
apis: {

38
apps/public-web/src/EShopOnAbp.PublicWeb/ServiceProviders/UserBasketProvider.cs

@ -11,23 +11,20 @@ namespace EShopOnAbp.PublicWeb.ServiceProviders
{
public class UserBasketProvider : ITransientDependency
{
protected HttpContext HttpContext => httpContextAccessor.HttpContext;
private HttpContext HttpContext => _httpContextAccessor.HttpContext;
private readonly IHttpContextAccessor httpContextAccessor;
protected readonly ILogger<UserBasketProvider> logger;
protected readonly IBasketAppService basketAppService;
protected readonly ICurrentUser currentUser;
private readonly IHttpContextAccessor _httpContextAccessor;
private readonly ILogger<UserBasketProvider> _logger;
private readonly IBasketAppService _basketAppService;
public UserBasketProvider(
IHttpContextAccessor httpContextAccessor,
ILogger<UserBasketProvider> logger,
IBasketAppService basketAppService,
ICurrentUser currentUser)
IBasketAppService basketAppService)
{
this.httpContextAccessor = httpContextAccessor;
this.logger = logger;
this.basketAppService = basketAppService;
this.currentUser = currentUser;
_httpContextAccessor = httpContextAccessor;
_logger = logger;
_basketAppService = basketAppService;
}
public virtual async Task<BasketDto> GetBasketAsync()
@ -38,26 +35,11 @@ namespace EShopOnAbp.PublicWeb.ServiceProviders
HttpContext.Request.Cookies.TryGetValue(EShopConstants.AnonymousUserClaimName,
out string anonymousUserId);
if (!currentUser.IsAuthenticated)
{
logger.LogInformation($"Getting basket for anonymous user id:{anonymousUserId}.");
return await basketAppService.GetByAnonymousUserIdAsync(Guid.Parse(anonymousUserId));
}
//TODO: Merge with anonymously stored cart if exist
var userClaimValue = currentUser.FindClaimValue(EShopConstants.AnonymousUserClaimName);
// Fall-back for having trouble when setting claim on user login
if (string.IsNullOrEmpty(userClaimValue))
{
return await basketAppService.GetAsync();
}
return await basketAppService.MergeBasketsAsync();
return await _basketAppService.GetAsync(Guid.Parse(anonymousUserId));
}
catch (Exception ex)
{
logger.LogError(ex, ex.Message);
_logger.LogError(ex, ex.Message);
return null;
}
}

26
apps/public-web/src/EShopOnAbp.PublicWeb/wwwroot/client-proxies/basket-proxy.js

@ -11,27 +11,13 @@
abp.utils.createNamespace(window, 'eShopOnAbp.basketService.basket');
eShopOnAbp.basketService.basket.get = function(ajaxParams) {
eShopOnAbp.basketService.basket.get = function(anonymousUserId, ajaxParams) {
return abp.ajax($.extend(true, {
url: abp.appPath + 'api/basket/basket',
url: abp.appPath + 'api/basket/basket' + abp.utils.buildQueryString([{ name: 'anonymousUserId', value: anonymousUserId }]) + '',
type: 'GET'
}, ajaxParams));
};
eShopOnAbp.basketService.basket.getByAnonymousUserId = function(id, ajaxParams) {
return abp.ajax($.extend(true, {
url: abp.appPath + 'api/basket/basket/' + id + '/by-anonymous-user-id',
type: 'GET'
}, ajaxParams));
};
eShopOnAbp.basketService.basket.mergeBaskets = function(ajaxParams) {
return abp.ajax($.extend(true, {
url: abp.appPath + 'api/basket/basket/merge-baskets',
type: 'POST'
}, ajaxParams));
};
eShopOnAbp.basketService.basket.addProduct = function(input, ajaxParams) {
return abp.ajax($.extend(true, {
url: abp.appPath + 'api/basket/basket/product',
@ -47,14 +33,6 @@
}, ajaxParams));
};
eShopOnAbp.basketService.basket.purchase = function(ajaxParams) {
return abp.ajax($.extend(true, {
url: abp.appPath + 'api/basket/basket/purchase',
type: 'POST',
dataType: null
}, ajaxParams));
};
})();
})();

4
services/basket/src/EShopOnAbp.BasketService.Application.Contracts/IBasketAppService.cs

@ -6,9 +6,7 @@ namespace EShopOnAbp.BasketService;
public interface IBasketAppService : IApplicationService
{
Task<BasketDto> GetAsync();
Task<BasketDto> GetByAnonymousUserIdAsync(Guid id);
Task<BasketDto> MergeBasketsAsync();
Task<BasketDto> GetAsync(Guid? anonymousUserId);
Task<BasketDto> AddProductAsync(AddProductDto input);
Task<BasketDto> RemoveProductAsync(RemoveProductDto input);
}

53
services/basket/src/EShopOnAbp.BasketService.Application/BasketAppService.cs

@ -2,12 +2,9 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Volo.Abp.Users;
using EShopOnAbp.CatalogService.Products;
using Microsoft.Extensions.Logging;
using Volo.Abp;
using Volo.Abp.EventBus.Distributed;
namespace EShopOnAbp.BasketService;
@ -15,59 +12,37 @@ public class BasketAppService : BasketServiceAppService, IBasketAppService
{
private readonly IBasketRepository _basketRepository;
private readonly IBasketProductService _basketProductService;
private readonly IDistributedEventBus _distributedEventBus;
public BasketAppService(
IBasketRepository basketRepository,
IBasketProductService basketProductService,
IDistributedEventBus distributedEventBus)
IBasketProductService basketProductService)
{
_basketRepository = basketRepository;
_basketProductService = basketProductService;
_distributedEventBus = distributedEventBus;
}
public async Task<BasketDto> GetAsync()
public async Task<BasketDto> GetAsync(Guid? anonymousUserId)
{
var basket = await _basketRepository.GetAsync(CurrentUser.GetId());
return await GetBasketDtoAsync(basket);
}
if (anonymousUserId != null && CurrentUser.IsAuthenticated)
{
var userBasket = await _basketRepository.GetAsync(CurrentUser.GetId());
var anonymousUserBasket = await _basketRepository.GetAsync(anonymousUserId.Value);
public async Task<BasketDto> GetByAnonymousUserIdAsync(Guid id)
{
var basket = await _basketRepository.GetAsync(id);
return await GetBasketDtoAsync(basket);
}
userBasket.Merge(anonymousUserBasket);
await _basketRepository.UpdateAsync(userBasket);
public async Task<BasketDto> MergeBasketsAsync()
{
//TODO: move to custom shared project
var anonymousUserIdString = CurrentUser.FindClaimValue("anonymous_id");
if (!Guid.TryParse(anonymousUserIdString, out Guid anonymousUserId))
{
Logger.LogError($"Couldn't parse anonymous Id from claim!{anonymousUserIdString}");
}
anonymousUserBasket.Clear();
await _basketRepository.UpdateAsync(anonymousUserBasket);
Basket anonymousUserBasket = await _basketRepository.GetAsync(anonymousUserId);
if (!CurrentUser.IsAuthenticated)
{
Logger.LogWarning($"User is not authenticated! Merging baskets failed!");
return await GetBasketDtoAsync(anonymousUserBasket);
return await GetBasketDtoAsync(userBasket);
}
var userBasket = await _basketRepository.GetAsync(CurrentUser.GetId());
foreach (var item in anonymousUserBasket.Items)
if (anonymousUserId != null && !CurrentUser.IsAuthenticated)
{
userBasket.AddProduct(item.ProductId, item.Count);
return await GetBasketDtoAsync(await _basketRepository.GetAsync(anonymousUserId.Value));
}
await _basketRepository.UpdateAsync(userBasket);
anonymousUserBasket.Clear();
await _basketRepository.UpdateAsync(anonymousUserBasket);
return await GetBasketDtoAsync(userBasket);
return await GetBasketDtoAsync(await _basketRepository.GetAsync(CurrentUser.GetId()));
}
public async Task<BasketDto> AddProductAsync(AddProductDto input)

2
services/basket/src/EShopOnAbp.BasketService.Application/BasketProductService.cs

@ -31,6 +31,6 @@ public class BasketProductService : IBasketProductService, ITransientDependency
private Task<ProductDto> GetProductAsync(Guid productId)
{
return _productAppService.GetAsync(productId) ??
throw new UserFriendlyException("Could not find the product!"); //TODO: Business exception with localization;
throw new UserFriendlyException(BasketServiceDomainErrorCodes.ProductNotFound);
}
}

1
services/basket/src/EShopOnAbp.BasketService.Domain.Shared/BasketServiceDomainErrorCodes.cs

@ -3,5 +3,6 @@
public static class BasketServiceDomainErrorCodes
{
/* You can add your business exception error codes here, as constants */
public const string ProductNotFound = "ProductNotFound";
}
}

3
services/basket/src/EShopOnAbp.BasketService.Domain.Shared/Localization/BasketService/en.json

@ -6,6 +6,7 @@
"LongWelcomeMessage": "Welcome to the application. This is a startup project based on the ABP framework. For more information, visit abp.io.",
"Toolbar:Cart": "My Cart",
"Toolbar:BasketNotLoaded": "Couldn't Load!",
"Toolbar:CartEmpty": "Cart is Empty!"
"Toolbar:CartEmpty": "Cart is Empty!",
"ProductNotFound": "Could not find the product!"
}
}

3
services/basket/src/EShopOnAbp.BasketService.Domain.Shared/Localization/BasketService/tr.json

@ -6,6 +6,7 @@
"LongWelcomeMessage": "Uygulamaya hoşgeldiniz. Bu, ABP framework'ü üzerine bina edilmiş bir başlangıç projesidir. Daha fazla bilgi için abp.io adresini ziyaret edebilirsiniz.",
"Toolbar:Cart": "Sepetim",
"Toolbar:BasketNotLoaded": "Sepet Hatası!",
"Toolbar:CartEmpty": "Sepetiniz Boş"
"Toolbar:CartEmpty": "Sepetiniz Boş",
"ProductNotFound": "Bu ürün bulunamadı!"
}
}

9
services/basket/src/EShopOnAbp.BasketService.Domain/Basket.cs

@ -11,7 +11,6 @@ public class Basket : AggregateRoot<Guid>
private Basket()
{
}
public Basket(Guid id)
@ -70,4 +69,12 @@ public class Basket : AggregateRoot<Guid>
{
Items.Clear();
}
public void Merge(Basket basket)
{
foreach (var item in basket.Items)
{
AddProduct(item.ProductId, item.Count);
}
}
}

53
services/basket/src/EShopOnAbp.BasketService.HttpApi.Client/ClientProxies/BasketClientProxy.Generated.cs

@ -9,44 +9,33 @@ using Volo.Abp.Http.Client.ClientProxying;
using EShopOnAbp.BasketService;
// ReSharper disable once CheckNamespace
namespace EShopOnAbp.BasketService.ClientProxies
namespace EShopOnAbp.BasketService.ClientProxies;
[Dependency(ReplaceServices = true)]
[ExposeServices(typeof(IBasketAppService), typeof(BasketClientProxy))]
public partial class BasketClientProxy : ClientProxyBase<IBasketAppService>, IBasketAppService
{
[Dependency(ReplaceServices = true)]
[ExposeServices(typeof(IBasketAppService), typeof(BasketClientProxy))]
public partial class BasketClientProxy : ClientProxyBase<IBasketAppService>, IBasketAppService
public virtual async Task<BasketDto> GetAsync(Guid? anonymousUserId)
{
public virtual async Task<BasketDto> GetAsync()
{
return await RequestAsync<BasketDto>(nameof(GetAsync));
}
public virtual async Task<BasketDto> GetByAnonymousUserIdAsync(Guid id)
{
return await RequestAsync<BasketDto>(nameof(GetByAnonymousUserIdAsync), new ClientProxyRequestTypeValue
{
{ typeof(Guid), id }
});
}
public virtual async Task<BasketDto> MergeBasketsAsync()
return await RequestAsync<BasketDto>(nameof(GetAsync), new ClientProxyRequestTypeValue
{
return await RequestAsync<BasketDto>(nameof(MergeBasketsAsync));
}
{ typeof(Guid?), anonymousUserId }
});
}
public virtual async Task<BasketDto> AddProductAsync(AddProductDto input)
public virtual async Task<BasketDto> AddProductAsync(AddProductDto input)
{
return await RequestAsync<BasketDto>(nameof(AddProductAsync), new ClientProxyRequestTypeValue
{
return await RequestAsync<BasketDto>(nameof(AddProductAsync), new ClientProxyRequestTypeValue
{
{ typeof(AddProductDto), input }
});
}
{ typeof(AddProductDto), input }
});
}
public virtual async Task<BasketDto> RemoveProductAsync(RemoveProductDto input)
public virtual async Task<BasketDto> RemoveProductAsync(RemoveProductDto input)
{
return await RequestAsync<BasketDto>(nameof(RemoveProductAsync), new ClientProxyRequestTypeValue
{
return await RequestAsync<BasketDto>(nameof(RemoveProductAsync), new ClientProxyRequestTypeValue
{
{ typeof(RemoveProductDto), input }
});
}
{ typeof(RemoveProductDto), input }
});
}
}

7
services/basket/src/EShopOnAbp.BasketService.HttpApi.Client/ClientProxies/BasketClientProxy.cs

@ -1,8 +1,7 @@
// This file is part of BasketClientProxy, you can customize it here
// ReSharper disable once CheckNamespace
namespace EShopOnAbp.BasketService.ClientProxies
namespace EShopOnAbp.BasketService.ClientProxies;
public partial class BasketClientProxy
{
public partial class BasketClientProxy
{
}
}

69
services/basket/src/EShopOnAbp.BasketService.HttpApi.Client/ClientProxies/basket-generate-proxy.json

@ -23,48 +23,33 @@
}
],
"actions": {
"GetAsync": {
"uniqueName": "GetAsync",
"GetAsyncByAnonymousUserId": {
"uniqueName": "GetAsyncByAnonymousUserId",
"name": "GetAsync",
"httpMethod": "GET",
"url": "api/basket/basket",
"supportedVersions": [],
"parametersOnMethod": [],
"parameters": [],
"returnValue": {
"type": "EShopOnAbp.BasketService.BasketDto",
"typeSimple": "EShopOnAbp.BasketService.BasketDto"
},
"allowAnonymous": null,
"implementFrom": "EShopOnAbp.BasketService.IBasketAppService"
},
"GetByAnonymousUserIdAsyncById": {
"uniqueName": "GetByAnonymousUserIdAsyncById",
"name": "GetByAnonymousUserIdAsync",
"httpMethod": "GET",
"url": "api/basket/basket/{id}/by-anonymous-user-id",
"supportedVersions": [],
"parametersOnMethod": [
{
"name": "id",
"typeAsString": "System.Guid, System.Private.CoreLib",
"type": "System.Guid",
"typeSimple": "string",
"name": "anonymousUserId",
"typeAsString": "System.Nullable`1[[System.Guid, System.Private.CoreLib, Version=6.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]], System.Private.CoreLib",
"type": "System.Guid?",
"typeSimple": "string?",
"isOptional": false,
"defaultValue": null
}
],
"parameters": [
{
"nameOnMethod": "id",
"name": "id",
"nameOnMethod": "anonymousUserId",
"name": "anonymousUserId",
"jsonName": null,
"type": "System.Guid",
"typeSimple": "string",
"type": "System.Guid?",
"typeSimple": "string?",
"isOptional": false,
"defaultValue": null,
"constraintTypes": [],
"bindingSourceId": "Path",
"constraintTypes": null,
"bindingSourceId": "ModelBinding",
"descriptorName": ""
}
],
@ -75,21 +60,6 @@
"allowAnonymous": null,
"implementFrom": "EShopOnAbp.BasketService.IBasketAppService"
},
"MergeBasketsAsync": {
"uniqueName": "MergeBasketsAsync",
"name": "MergeBasketsAsync",
"httpMethod": "POST",
"url": "api/basket/basket/merge-baskets",
"supportedVersions": [],
"parametersOnMethod": [],
"parameters": [],
"returnValue": {
"type": "EShopOnAbp.BasketService.BasketDto",
"typeSimple": "EShopOnAbp.BasketService.BasketDto"
},
"allowAnonymous": null,
"implementFrom": "EShopOnAbp.BasketService.IBasketAppService"
},
"AddProductAsyncByInput": {
"uniqueName": "AddProductAsyncByInput",
"name": "AddProductAsync",
@ -187,21 +157,6 @@
},
"allowAnonymous": null,
"implementFrom": "EShopOnAbp.BasketService.IBasketAppService"
},
"PurchaseAsync": {
"uniqueName": "PurchaseAsync",
"name": "PurchaseAsync",
"httpMethod": "POST",
"url": "api/basket/basket/purchase",
"supportedVersions": [],
"parametersOnMethod": [],
"parameters": [],
"returnValue": {
"type": "System.Void",
"typeSimple": "System.Void"
},
"allowAnonymous": null,
"implementFrom": "EShopOnAbp.BasketService.IBasketAppService"
}
}
}

9
services/catalog/src/EShopOnAbp.CatalogService.Application/Products/ProductAppService.cs

@ -11,7 +11,7 @@ using Volo.Abp.Domain.Repositories;
namespace EShopOnAbp.CatalogService.Products
{
//[Authorize(CatalogServicePermissions.Products.Default)] //TODO: Temporary removed authorization (I needed to use swagger but the auth didn't work)
[Authorize(CatalogServicePermissions.Products.Default)]
public class ProductAppService : ApplicationService, IProductAppService
{
private readonly ProductManager _productManager;
@ -23,18 +23,17 @@ namespace EShopOnAbp.CatalogService.Products
_productRepository = productRepository;
}
//TODO: Is this method used?
public async Task<PagedResultDto<ProductDto>> GetListPagedAsync(PagedAndSortedResultRequestDto input)
{
var queryable = await _productRepository.GetQueryableAsync();
var products = await AsyncExecuter.ToListAsync(
queryable
.OrderBy(input.Sorting ?? "Name")
.Skip(input.SkipCount)
.Take(input.MaxResultCount)
);
var totalCount = await _productRepository.GetCountAsync();
return new PagedResultDto<ProductDto>(
@ -71,7 +70,7 @@ namespace EShopOnAbp.CatalogService.Products
return ObjectMapper.Map<Product, ProductDto>(product);
}
//[Authorize(CatalogServicePermissions.Products.Update)] //TODO: Temporary removed authorization (I needed to use swagger but the auth didn't work)
[Authorize(CatalogServicePermissions.Products.Update)]
public async Task<ProductDto> UpdateAsync(Guid id, UpdateProductDto input)
{
var product = await _productRepository.GetAsync(id);

3
services/identity/src/EShopOnAbp.IdentityService.HttpApi.Host/DbMigrations/IdentityServerDataSeeder.cs

@ -261,7 +261,8 @@ namespace EShopOnAbp.IdentityService.DbMigrations
{
"AccountService",
"IdentityService",
"AdministrationService"
"AdministrationService",
"CatalogService"
}),
grantTypes: new[] {"authorization_code", "LinkLogin", "password"},
secret: "1q2w3e*".Sha256(),

Loading…
Cancel
Save