Browse Source

1. Move store owner related base classes to EasyAbp.EShop.Stores.Application.Shared

2. minor refactoring
pull/81/head
RayMMond 6 years ago
parent
commit
0335be9281
  1. 2
      modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Application/EasyAbp.EShop.Orders.Application.csproj
  2. 2
      modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Application/EasyAbp/EShop/Orders/EShopOrdersApplicationModule.cs
  3. 14
      modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Application/EasyAbp/EShop/Orders/Orders/OrderAppService.cs
  4. 2
      modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Application/EasyAbp.EShop.Products.Application.csproj
  5. 2
      modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Application/EasyAbp/EShop/Products/EShopProductsApplicationModule.cs
  6. 10
      modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Application/EasyAbp/EShop/Products/ProductInventories/ProductInventoryAppService.cs
  7. 28
      modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Application/EasyAbp/EShop/Products/Products/ProductAppService.cs
  8. 2
      modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Web/Pages/EShop/Products/Products/Product/Index.cshtml.cs
  9. 12
      modules/EasyAbp.EShop.Stores/src/EasyAbp.EShop.Stores.Application.Contracts/EasyAbp/EShop/Stores/EShopStoresApplicationContractsModule.cs
  10. 23
      modules/EasyAbp.EShop.Stores/src/EasyAbp.EShop.Stores.Application.Contracts/EasyAbp/EShop/Stores/Permissions/StoreOwnerAuthorizationExtensions.cs
  11. 2
      modules/EasyAbp.EShop.Stores/src/EasyAbp.EShop.Stores.Application.Contracts/EasyAbp/EShop/Stores/StoreOwners/Dtos/GetStoreOwnerListDto.cs
  12. 2
      modules/EasyAbp.EShop.Stores/src/EasyAbp.EShop.Stores.Application.Contracts/EasyAbp/EShop/Stores/StoreOwners/Dtos/StoreOwnerDto.cs
  13. 4
      modules/EasyAbp.EShop.Stores/src/EasyAbp.EShop.Stores.Application.Contracts/EasyAbp/EShop/Stores/StoreOwners/StoreOwnerDuplicatedException.cs
  14. 16
      modules/EasyAbp.EShop.Stores/src/EasyAbp.EShop.Stores.Application.Shared/EasyAbp.EShop.Stores.Application.Shared.csproj
  15. 22
      modules/EasyAbp.EShop.Stores/src/EasyAbp.EShop.Stores.Application.Shared/EasyAbp/EShop/Stores/EShopStoresApplicationSharedModule.cs
  16. 0
      modules/EasyAbp.EShop.Stores/src/EasyAbp.EShop.Stores.Application.Shared/EasyAbp/EShop/Stores/Permissions/BasicStorePermissionAuthorizationHandler.cs
  17. 50
      modules/EasyAbp.EShop.Stores/src/EasyAbp.EShop.Stores.Application.Shared/EasyAbp/EShop/Stores/Permissions/StoreOwnerAuthorizationExtensions.cs
  18. 0
      modules/EasyAbp.EShop.Stores/src/EasyAbp.EShop.Stores.Application.Shared/EasyAbp/EShop/Stores/Permissions/StorePermissionAuthorizationRequirement.cs
  19. 125
      modules/EasyAbp.EShop.Stores/src/EasyAbp.EShop.Stores.Application.Shared/EasyAbp/EShop/Stores/Stores/MultiStoreAbstractKeyCrudAppService.cs
  20. 65
      modules/EasyAbp.EShop.Stores/src/EasyAbp.EShop.Stores.Application.Shared/EasyAbp/EShop/Stores/Stores/MultiStoreAbstractKeyReadOnlyAppService.cs
  21. 22
      modules/EasyAbp.EShop.Stores/src/EasyAbp.EShop.Stores.Application.Shared/EasyAbp/EShop/Stores/Stores/MultiStoreCrudAppService.cs
  22. 4
      modules/EasyAbp.EShop.Stores/src/EasyAbp.EShop.Stores.Application.Shared/EasyAbp/EShop/Stores/Stores/MultiStoreReadOnlyAppService.cs
  23. 3
      modules/EasyAbp.EShop.Stores/src/EasyAbp.EShop.Stores.Application.Shared/FodyWeavers.xml
  24. 30
      modules/EasyAbp.EShop.Stores/src/EasyAbp.EShop.Stores.Application.Shared/FodyWeavers.xsd
  25. 1
      modules/EasyAbp.EShop.Stores/src/EasyAbp.EShop.Stores.Application/EasyAbp.EShop.Stores.Application.csproj
  26. 20
      modules/EasyAbp.EShop.Stores/src/EasyAbp.EShop.Stores.Application/EasyAbp/EShop/Stores/StoreOwners/StoreOwnerAppService.cs
  27. 211
      modules/EasyAbp.EShop.Stores/src/EasyAbp.EShop.Stores.Application/EasyAbp/EShop/Stores/Stores/MultiStoreAbstractKeyCrudAppService.cs
  28. 236
      modules/EasyAbp.EShop.Stores/src/EasyAbp.EShop.Stores.Application/EasyAbp/EShop/Stores/Stores/MultiStoreAbstractKeyReadOnlyAppService.cs
  29. 4
      modules/EasyAbp.EShop.Stores/src/EasyAbp.EShop.Stores.Domain/EasyAbp/EShop/Stores/StoreOwners/IStoreOwnerRepository.cs
  30. 6
      modules/EasyAbp.EShop.Stores/src/EasyAbp.EShop.Stores.Domain/EasyAbp/EShop/Stores/StoreOwners/StoreOwner.cs
  31. 4
      modules/EasyAbp.EShop.Stores/src/EasyAbp.EShop.Stores.Domain/EasyAbp/EShop/Stores/StoreOwners/StoreOwnerStore.cs
  32. 6
      modules/EasyAbp.EShop.Stores/src/EasyAbp.EShop.Stores.EntityFrameworkCore/EasyAbp/EShop/Stores/EntityFrameworkCore/StoresDbContextModelCreatingExtensions.cs
  33. 8
      modules/EasyAbp.EShop.Stores/src/EasyAbp.EShop.Stores.EntityFrameworkCore/EasyAbp/EShop/Stores/StoreOwners/StoreOwnerRepository.cs
  34. 36
      modules/EasyAbp.EShop.Stores/src/EasyAbp.EShop.Stores.Web/EasyAbp.EShop.Stores.Web.csproj
  35. 2
      modules/EasyAbp.EShop.Stores/src/EasyAbp.EShop.Stores.Web/Pages/EShop/Stores/StoreOwners/StoreOwner/Index.js
  36. 2
      modules/EasyAbp.EShop.Stores/src/EasyAbp.EShop.Stores.Web/Pages/EShop/Stores/StoreOwners/StoreOwner/ViewModels/CreateStoreOwnerViewModel.cs

2
modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Application/EasyAbp.EShop.Orders.Application.csproj

@ -11,7 +11,7 @@
<PackageReference Include="Volo.Abp.AutoMapper" Version="3.0.5" /> <PackageReference Include="Volo.Abp.AutoMapper" Version="3.0.5" />
<PackageReference Include="Volo.Abp.Ddd.Application" Version="3.0.5" /> <PackageReference Include="Volo.Abp.Ddd.Application" Version="3.0.5" />
<ProjectReference Include="..\..\..\EasyAbp.EShop.Products\src\EasyAbp.EShop.Products.Application.Contracts\EasyAbp.EShop.Products.Application.Contracts.csproj" /> <ProjectReference Include="..\..\..\EasyAbp.EShop.Products\src\EasyAbp.EShop.Products.Application.Contracts\EasyAbp.EShop.Products.Application.Contracts.csproj" />
<ProjectReference Include="..\..\..\EasyAbp.EShop.Stores\src\EasyAbp.EShop.Stores.Application\EasyAbp.EShop.Stores.Application.csproj" /> <ProjectReference Include="..\..\..\EasyAbp.EShop.Stores\src\EasyAbp.EShop.Stores.Application.Shared\EasyAbp.EShop.Stores.Application.Shared.csproj" />
<ProjectReference Include="..\EasyAbp.EShop.Orders.Application.Contracts\EasyAbp.EShop.Orders.Application.Contracts.csproj" /> <ProjectReference Include="..\EasyAbp.EShop.Orders.Application.Contracts\EasyAbp.EShop.Orders.Application.Contracts.csproj" />
<ProjectReference Include="..\EasyAbp.EShop.Orders.Domain\EasyAbp.EShop.Orders.Domain.csproj" /> <ProjectReference Include="..\EasyAbp.EShop.Orders.Domain\EasyAbp.EShop.Orders.Domain.csproj" />
</ItemGroup> </ItemGroup>

2
modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Application/EasyAbp/EShop/Orders/EShopOrdersApplicationModule.cs

@ -1,4 +1,5 @@
using EasyAbp.EShop.Products; using EasyAbp.EShop.Products;
using EasyAbp.EShop.Stores;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.AutoMapper; using Volo.Abp.AutoMapper;
using Volo.Abp.Modularity; using Volo.Abp.Modularity;
@ -10,6 +11,7 @@ namespace EasyAbp.EShop.Orders
typeof(EShopOrdersDomainModule), typeof(EShopOrdersDomainModule),
typeof(EShopOrdersApplicationContractsModule), typeof(EShopOrdersApplicationContractsModule),
typeof(EShopProductsApplicationContractsModule), typeof(EShopProductsApplicationContractsModule),
typeof(EShopStoresDomainSharedModule),
typeof(AbpDddApplicationModule), typeof(AbpDddApplicationModule),
typeof(AbpAutoMapperModule) typeof(AbpAutoMapperModule)
)] )]

14
modules/EasyAbp.EShop.Orders/src/EasyAbp.EShop.Orders.Application/EasyAbp/EShop/Orders/Orders/OrderAppService.cs

@ -67,15 +67,7 @@ namespace EasyAbp.EShop.Orders.Orders
{ {
if (input.CustomerUserId != CurrentUser.GetId()) if (input.CustomerUserId != CurrentUser.GetId())
{ {
if (input.StoreId.HasValue) await CheckMultiStorePolicyAsync(input.StoreId, GetListPolicyName);
{
await CheckMultiStorePolicyAsync(input.StoreId.Value, GetListPolicyName);
}
else
{
throw new AbpAuthorizationException("Authorization failed! Given policy has not granted: " +
GetListPolicyName);
}
} }
return await base.GetListAsync(input); return await base.GetListAsync(input);
@ -146,7 +138,7 @@ namespace EasyAbp.EShop.Orders.Orders
if (order.CustomerUserId != CurrentUser.GetId()) if (order.CustomerUserId != CurrentUser.GetId())
{ {
await AuthorizationService.CheckStoreOwnerAsync(order.StoreId, OrdersPermissions.Orders.Manage); await CheckMultiStorePolicyAsync(order.StoreId, OrdersPermissions.Orders.Manage);
} }
return MapToGetOutputDto(order); return MapToGetOutputDto(order);
@ -159,7 +151,7 @@ namespace EasyAbp.EShop.Orders.Orders
if (order.CustomerUserId != CurrentUser.GetId()) if (order.CustomerUserId != CurrentUser.GetId())
{ {
await AuthorizationService.CheckStoreOwnerAsync(order.StoreId, OrdersPermissions.Orders.Manage); await CheckMultiStorePolicyAsync(order.StoreId, OrdersPermissions.Orders.Manage);
} }
order = await _orderManager.CompleteAsync(order); order = await _orderManager.CompleteAsync(order);

2
modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Application/EasyAbp.EShop.Products.Application.csproj

@ -11,7 +11,7 @@
<PackageReference Include="EasyAbp.Abp.Trees.Application" Version="1.0.0" /> <PackageReference Include="EasyAbp.Abp.Trees.Application" Version="1.0.0" />
<PackageReference Include="Volo.Abp.AutoMapper" Version="3.0.5" /> <PackageReference Include="Volo.Abp.AutoMapper" Version="3.0.5" />
<PackageReference Include="Volo.Abp.Ddd.Application" Version="3.0.5" /> <PackageReference Include="Volo.Abp.Ddd.Application" Version="3.0.5" />
<ProjectReference Include="..\..\..\EasyAbp.EShop.Stores\src\EasyAbp.EShop.Stores.Application.Contracts\EasyAbp.EShop.Stores.Application.Contracts.csproj" /> <ProjectReference Include="..\..\..\EasyAbp.EShop.Stores\src\EasyAbp.EShop.Stores.Application.Shared\EasyAbp.EShop.Stores.Application.Shared.csproj" />
<ProjectReference Include="..\EasyAbp.EShop.Products.Application.Contracts\EasyAbp.EShop.Products.Application.Contracts.csproj" /> <ProjectReference Include="..\EasyAbp.EShop.Products.Application.Contracts\EasyAbp.EShop.Products.Application.Contracts.csproj" />
<ProjectReference Include="..\EasyAbp.EShop.Products.Domain\EasyAbp.EShop.Products.Domain.csproj" /> <ProjectReference Include="..\EasyAbp.EShop.Products.Domain\EasyAbp.EShop.Products.Domain.csproj" />
</ItemGroup> </ItemGroup>

2
modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Application/EasyAbp/EShop/Products/EShopProductsApplicationModule.cs

@ -1,4 +1,5 @@
using EasyAbp.Abp.Trees; using EasyAbp.Abp.Trees;
using EasyAbp.EShop.Stores;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.AutoMapper; using Volo.Abp.AutoMapper;
using Volo.Abp.Modularity; using Volo.Abp.Modularity;
@ -9,6 +10,7 @@ namespace EasyAbp.EShop.Products
[DependsOn( [DependsOn(
typeof(EShopProductsDomainModule), typeof(EShopProductsDomainModule),
typeof(EShopProductsApplicationContractsModule), typeof(EShopProductsApplicationContractsModule),
typeof(EShopStoresDomainSharedModule),
typeof(AbpDddApplicationModule), typeof(AbpDddApplicationModule),
typeof(AbpAutoMapperModule), typeof(AbpAutoMapperModule),
typeof(AbpTreesApplicationModule) typeof(AbpTreesApplicationModule)

10
modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Application/EasyAbp/EShop/Products/ProductInventories/ProductInventoryAppService.cs

@ -52,7 +52,9 @@ namespace EasyAbp.EShop.Products.ProductInventories
throw new AbpValidationException("StoreId should not be null."); throw new AbpValidationException("StoreId should not be null.");
} }
await AuthorizationService.CheckStoreOwnerAsync(input.StoreId.Value, ProductsPermissions.ProductInventory.Update); await AuthorizationService.CheckMultiStorePolicyAsync(input.StoreId.Value,
ProductsPermissions.ProductInventory.CrossStore,
ProductsPermissions.ProductInventory.Update);
await _productStoreRepository.GetAsync(input.ProductId, input.StoreId.Value); await _productStoreRepository.GetAsync(input.ProductId, input.StoreId.Value);
} }
@ -76,7 +78,8 @@ namespace EasyAbp.EShop.Products.ProductInventories
{ {
if (changedInventory >= 0) if (changedInventory >= 0)
{ {
if (!await _productInventoryProvider.TryIncreaseInventoryAsync(productInventory, changedInventory, false)) if (!await _productInventoryProvider.TryIncreaseInventoryAsync(productInventory, changedInventory,
false))
{ {
throw new InventoryChangeFailedException(productInventory.ProductId, productInventory.ProductSkuId, throw new InventoryChangeFailedException(productInventory.ProductId, productInventory.ProductSkuId,
productInventory.Inventory, changedInventory); productInventory.Inventory, changedInventory);
@ -84,7 +87,8 @@ namespace EasyAbp.EShop.Products.ProductInventories
} }
else else
{ {
if (!await _productInventoryProvider.TryReduceInventoryAsync(productInventory, -changedInventory, false)) if (!await _productInventoryProvider.TryReduceInventoryAsync(productInventory, -changedInventory, false)
)
{ {
throw new InventoryChangeFailedException(productInventory.ProductId, productInventory.ProductSkuId, throw new InventoryChangeFailedException(productInventory.ProductId, productInventory.ProductSkuId,
productInventory.Inventory, changedInventory); productInventory.Inventory, changedInventory);

28
modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Application/EasyAbp/EShop/Products/Products/ProductAppService.cs

@ -14,7 +14,8 @@ using Volo.Abp.Domain.Entities;
namespace EasyAbp.EShop.Products.Products namespace EasyAbp.EShop.Products.Products
{ {
public class ProductAppService : CrudAppService<Product, ProductDto, Guid, GetProductListDto, CreateUpdateProductDto, CreateUpdateProductDto>, public class ProductAppService : CrudAppService<Product, ProductDto, Guid, GetProductListDto, CreateUpdateProductDto
, CreateUpdateProductDto>,
IProductAppService IProductAppService
{ {
protected override string CreatePolicyName { get; set; } = ProductsPermissions.Products.Create; protected override string CreatePolicyName { get; set; } = ProductsPermissions.Products.Create;
@ -110,9 +111,11 @@ namespace EasyAbp.EShop.Products.Products
var usedAttributeOptionIds = new HashSet<Guid>(); var usedAttributeOptionIds = new HashSet<Guid>();
foreach (var serializedAttributeOptionIds in product.ProductSkus.Select(sku => sku.SerializedAttributeOptionIds)) foreach (var serializedAttributeOptionIds in product.ProductSkus.Select(sku =>
sku.SerializedAttributeOptionIds))
{ {
foreach (var attributeOptionId in await _attributeOptionIdsSerializer.DeserializeAsync(serializedAttributeOptionIds)) foreach (var attributeOptionId in await _attributeOptionIdsSerializer.DeserializeAsync(
serializedAttributeOptionIds))
{ {
usedAttributeOptionIds.Add(attributeOptionId); usedAttributeOptionIds.Add(attributeOptionId);
} }
@ -120,7 +123,8 @@ namespace EasyAbp.EShop.Products.Products
foreach (var attributeDto in input.ProductAttributes) foreach (var attributeDto in input.ProductAttributes)
{ {
var attribute = product.ProductAttributes.FirstOrDefault(a => a.DisplayName == attributeDto.DisplayName); var attribute =
product.ProductAttributes.FirstOrDefault(a => a.DisplayName == attributeDto.DisplayName);
if (attribute == null) if (attribute == null)
{ {
@ -137,7 +141,8 @@ namespace EasyAbp.EShop.Products.Products
foreach (var optionDto in attributeDto.ProductAttributeOptions) foreach (var optionDto in attributeDto.ProductAttributeOptions)
{ {
var option = attribute.ProductAttributeOptions.FirstOrDefault(o => o.DisplayName == optionDto.DisplayName); var option =
attribute.ProductAttributeOptions.FirstOrDefault(o => o.DisplayName == optionDto.DisplayName);
if (option == null) if (option == null)
{ {
@ -203,7 +208,7 @@ namespace EasyAbp.EShop.Products.Products
await LoadDtoInventoryDataAsync(product, dto, storeId); await LoadDtoInventoryDataAsync(product, dto, storeId);
await LoadDtoPriceAsync(product, dto, storeId); await LoadDtoPriceAsync(product, dto, storeId);
await LoadDtosProductTypeUniqueNameAsync(new[] { dto }); await LoadDtosProductTypeUniqueNameAsync(new[] {dto});
return dto; return dto;
} }
@ -240,7 +245,10 @@ namespace EasyAbp.EShop.Products.Products
{ {
await CheckGetListPolicyAsync(); await CheckGetListPolicyAsync();
var isCurrentUserStoreAdmin = await AuthorizationService.IsStoreOwnerGrantedAsync(input.StoreId, ProductsPermissions.Products.Default); var isCurrentUserStoreAdmin =
await AuthorizationService.IsMultiStoreGrantedAsync(input.StoreId,
ProductsPermissions.Products.CrossStore,
ProductsPermissions.Products.Default);
if (input.ShowHidden && !isCurrentUserStoreAdmin) if (input.ShowHidden && !isCurrentUserStoreAdmin)
{ {
@ -279,7 +287,8 @@ namespace EasyAbp.EShop.Products.Products
return new PagedResultDto<ProductDto>(totalCount, items); return new PagedResultDto<ProductDto>(totalCount, items);
} }
protected virtual async Task<ProductDto> LoadDtoInventoryDataAsync(Product product, ProductDto productDto, Guid storeId) protected virtual async Task<ProductDto> LoadDtoInventoryDataAsync(Product product, ProductDto productDto,
Guid storeId)
{ {
var inventoryDataDict = await _productInventoryProvider.GetInventoryDataDictionaryAsync(product, storeId); var inventoryDataDict = await _productInventoryProvider.GetInventoryDataDictionaryAsync(product, storeId);
@ -354,7 +363,8 @@ namespace EasyAbp.EShop.Products.Products
return ObjectMapper.Map<Product, ProductDto>(product); return ObjectMapper.Map<Product, ProductDto>(product);
} }
public async Task<ProductDto> UpdateSkuAsync(Guid productId, Guid productSkuId, Guid storeId, UpdateProductSkuDto input) public async Task<ProductDto> UpdateSkuAsync(Guid productId, Guid productSkuId, Guid storeId,
UpdateProductSkuDto input)
{ {
await CheckUpdatePolicyAsync(); await CheckUpdatePolicyAsync();

2
modules/EasyAbp.EShop.Products/src/EasyAbp.EShop.Products.Web/Pages/EShop/Products/Products/Product/Index.cshtml.cs

@ -35,7 +35,7 @@ namespace EasyAbp.EShop.Products.Web.Pages.EShop.Products.Products.Product
{ {
var storeOwners = await _storeOwnerAppService.GetListAsync(new GetStoreOwnerListDto var storeOwners = await _storeOwnerAppService.GetListAsync(new GetStoreOwnerListDto
{ {
OwnerId = CurrentUser.Id.Value, OwnerUserId = CurrentUser.Id.Value,
}); });
StoreId = storeOwners.Items.FirstOrDefault()?.StoreId; StoreId = storeOwners.Items.FirstOrDefault()?.StoreId;

12
modules/EasyAbp.EShop.Stores/src/EasyAbp.EShop.Stores.Application.Contracts/EasyAbp/EShop/Stores/EShopStoresApplicationContractsModule.cs

@ -1,10 +1,6 @@
using EasyAbp.EShop.Stores.Permissions; using Volo.Abp.Application;
using Microsoft.AspNetCore.Authorization;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.Application;
using Volo.Abp.Modularity;
using Volo.Abp.VirtualFileSystem;
using Volo.Abp.Authorization; using Volo.Abp.Authorization;
using Volo.Abp.Modularity;
namespace EasyAbp.EShop.Stores namespace EasyAbp.EShop.Stores
{ {
@ -15,9 +11,5 @@ namespace EasyAbp.EShop.Stores
)] )]
public class EShopStoresApplicationContractsModule : AbpModule public class EShopStoresApplicationContractsModule : AbpModule
{ {
public override void ConfigureServices(ServiceConfigurationContext context)
{
context.Services.AddSingleton<IAuthorizationHandler, BasicStorePermissionAuthorizationHandler>();
}
} }
} }

23
modules/EasyAbp.EShop.Stores/src/EasyAbp.EShop.Stores.Application.Contracts/EasyAbp/EShop/Stores/Permissions/StoreOwnerAuthorizationExtensions.cs

@ -1,23 +0,0 @@
using Microsoft.AspNetCore.Authorization;
using System;
using System.Threading.Tasks;
namespace EasyAbp.EShop.Stores.Permissions
{
public static class StoreOwnerAuthorizationExtensions
{
public static Task<bool> IsStoreOwnerGrantedAsync(this IAuthorizationService authorizationService,
Guid storeId, string policyName = null, object resource = null)
{
return authorizationService.IsGrantedAsync(resource,
new StorePermissionAuthorizationRequirement(storeId, policyName));
}
public static Task CheckStoreOwnerAsync(this IAuthorizationService authorizationService,
Guid storeId, string policyName = null, object resource = null)
{
return authorizationService.CheckAsync(resource,
new StorePermissionAuthorizationRequirement(storeId, policyName));
}
}
}

2
modules/EasyAbp.EShop.Stores/src/EasyAbp.EShop.Stores.Application.Contracts/EasyAbp/EShop/Stores/StoreOwners/Dtos/GetStoreOwnerListDto.cs

@ -8,6 +8,6 @@ namespace EasyAbp.EShop.Stores.StoreOwners.Dtos
{ {
public Guid? StoreId { get; set; } public Guid? StoreId { get; set; }
public Guid? OwnerId { get; set; } public Guid? OwnerUserId { get; set; }
} }
} }

2
modules/EasyAbp.EShop.Stores/src/EasyAbp.EShop.Stores.Application.Contracts/EasyAbp/EShop/Stores/StoreOwners/Dtos/StoreOwnerDto.cs

@ -11,6 +11,6 @@ namespace EasyAbp.EShop.Stores.StoreOwners.Dtos
public Guid StoreId { get; set; } public Guid StoreId { get; set; }
[Required] [Required]
public Guid OwnerId { get; set; } public Guid OwnerUserId { get; set; }
} }
} }

4
modules/EasyAbp.EShop.Stores/src/EasyAbp.EShop.Stores.Application.Contracts/EasyAbp/EShop/Stores/StoreOwners/StoreOwnerDuplicatedException.cs

@ -5,8 +5,8 @@ namespace EasyAbp.EShop.Stores.StoreOwners
{ {
public class StoreOwnerDuplicatedException : BusinessException public class StoreOwnerDuplicatedException : BusinessException
{ {
public StoreOwnerDuplicatedException(Guid storeId, Guid ownerId) : base( public StoreOwnerDuplicatedException(Guid storeId, Guid ownerUserId) : base(
message: $"Owner {ownerId} is duplicate for the store {storeId}") message: $"Owner {ownerUserId} is duplicate for the store {storeId}")
{ {
} }
} }

16
modules/EasyAbp.EShop.Stores/src/EasyAbp.EShop.Stores.Application.Shared/EasyAbp.EShop.Stores.Application.Shared.csproj

@ -0,0 +1,16 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\..\..\common.props" />
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<RootNamespace />
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Volo.Abp.AutoMapper" Version="3.0.5" />
<PackageReference Include="Volo.Abp.Ddd.Application" Version="3.0.5" />
<ProjectReference Include="..\EasyAbp.EShop.Stores.Domain.Shared\EasyAbp.EShop.Stores.Domain.Shared.csproj" />
</ItemGroup>
</Project>

22
modules/EasyAbp.EShop.Stores/src/EasyAbp.EShop.Stores.Application.Shared/EasyAbp/EShop/Stores/EShopStoresApplicationSharedModule.cs

@ -0,0 +1,22 @@
using EasyAbp.EShop.Stores.Permissions;
using Microsoft.AspNetCore.Authorization;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.Application;
using Volo.Abp.AutoMapper;
using Volo.Abp.Modularity;
namespace EasyAbp.EShop.Stores
{
[DependsOn(
typeof(EShopStoresDomainSharedModule),
typeof(AbpDddApplicationModule),
typeof(AbpAutoMapperModule)
)]
public class EShopStoresApplicationSharedModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
context.Services.AddSingleton<IAuthorizationHandler, BasicStorePermissionAuthorizationHandler>();
}
}
}

0
modules/EasyAbp.EShop.Stores/src/EasyAbp.EShop.Stores.Application.Contracts/EasyAbp/EShop/Stores/Permissions/BasicStorePermissionAuthorizationHandler.cs → modules/EasyAbp.EShop.Stores/src/EasyAbp.EShop.Stores.Application.Shared/EasyAbp/EShop/Stores/Permissions/BasicStorePermissionAuthorizationHandler.cs

50
modules/EasyAbp.EShop.Stores/src/EasyAbp.EShop.Stores.Application.Shared/EasyAbp/EShop/Stores/Permissions/StoreOwnerAuthorizationExtensions.cs

@ -0,0 +1,50 @@
using Microsoft.AspNetCore.Authorization;
using System;
using System.Threading.Tasks;
using Volo.Abp.Authorization;
namespace EasyAbp.EShop.Stores.Permissions
{
public static class StoreOwnerAuthorizationExtensions
{
public static Task<bool> IsStoreOwnerGrantedAsync(this IAuthorizationService authorizationService,
Guid storeId, string policyName = null, object resource = null)
{
return authorizationService.IsGrantedAsync(resource,
new StorePermissionAuthorizationRequirement(storeId, policyName));
}
public static async Task<bool> IsMultiStoreGrantedAsync(this IAuthorizationService authorizationService,
Guid? storeId, string crossStorePolicyName, string policyName, object resource = null)
{
if (storeId.HasValue
&& await authorizationService.IsStoreOwnerGrantedAsync(storeId.Value, policyName))
{
return true;
}
return await authorizationService.IsGrantedAsync(resource, crossStorePolicyName)
&& await authorizationService.IsGrantedAsync(resource, policyName);
}
public static async Task CheckMultiStorePolicyAsync(this IAuthorizationService authorizationService,
Guid? storeId, string crossStorePolicyName, string policyName, object resource = null)
{
if (storeId.HasValue
&& await authorizationService.IsStoreOwnerGrantedAsync(storeId.Value, policyName))
{
return;
}
await authorizationService.CheckAsync(resource, crossStorePolicyName);
await authorizationService.CheckAsync(resource, policyName);
}
public static Task CheckStoreOwnerAsync(this IAuthorizationService authorizationService,
Guid storeId, string policyName = null, object resource = null)
{
return authorizationService.CheckAsync(resource,
new StorePermissionAuthorizationRequirement(storeId, policyName));
}
}
}

0
modules/EasyAbp.EShop.Stores/src/EasyAbp.EShop.Stores.Application.Contracts/EasyAbp/EShop/Stores/Permissions/StorePermissionAuthorizationRequirement.cs → modules/EasyAbp.EShop.Stores/src/EasyAbp.EShop.Stores.Application.Shared/EasyAbp/EShop/Stores/Permissions/StorePermissionAuthorizationRequirement.cs

125
modules/EasyAbp.EShop.Stores/src/EasyAbp.EShop.Stores.Application.Shared/EasyAbp/EShop/Stores/Stores/MultiStoreAbstractKeyCrudAppService.cs

@ -0,0 +1,125 @@
using System;
using System.Threading.Tasks;
using EasyAbp.EShop.Stores.Permissions;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services;
using Volo.Abp.Domain.Entities;
using Volo.Abp.Domain.Repositories;
namespace EasyAbp.EShop.Stores.Stores
{
public abstract class MultiStoreAbstractKeyCrudAppService<TEntity, TEntityDto, TKey>
: MultiStoreAbstractKeyCrudAppService<TEntity, TEntityDto, TKey, PagedAndSortedResultRequestDto>
where TEntity : class, IEntity, IMultiStore
where TEntityDto : IMultiStore
{
protected MultiStoreAbstractKeyCrudAppService(IRepository<TEntity> repository)
: base(repository)
{
}
}
public abstract class MultiStoreAbstractKeyCrudAppService<TEntity, TEntityDto, TKey, TGetListInput>
: MultiStoreAbstractKeyCrudAppService<TEntity, TEntityDto, TKey, TGetListInput, TEntityDto, TEntityDto>
where TEntity : class, IEntity, IMultiStore
where TEntityDto : IMultiStore
{
protected MultiStoreAbstractKeyCrudAppService(IRepository<TEntity> repository)
: base(repository)
{
}
}
public abstract class MultiStoreAbstractKeyCrudAppService<TEntity, TEntityDto, TKey, TGetListInput, TCreateInput>
: MultiStoreAbstractKeyCrudAppService<TEntity, TEntityDto, TKey, TGetListInput, TCreateInput, TCreateInput>
where TEntity : class, IEntity, IMultiStore
where TCreateInput : IMultiStore
{
protected MultiStoreAbstractKeyCrudAppService(IRepository<TEntity> repository)
: base(repository)
{
}
}
public abstract class MultiStoreAbstractKeyCrudAppService<TEntity, TEntityDto, TKey, TGetListInput, TCreateInput,
TUpdateInput>
: MultiStoreAbstractKeyCrudAppService<TEntity, TEntityDto, TEntityDto, TKey, TGetListInput, TCreateInput,
TUpdateInput>
where TEntity : class, IEntity, IMultiStore
where TCreateInput : IMultiStore
{
protected MultiStoreAbstractKeyCrudAppService(IRepository<TEntity> repository)
: base(repository)
{
}
}
public abstract class MultiStoreAbstractKeyCrudAppService<TEntity, TGetOutputDto, TGetListOutputDto, TKey,
TGetListInput, TCreateInput, TUpdateInput>
: AbstractKeyCrudAppService<TEntity, TGetOutputDto, TGetListOutputDto, TKey,
TGetListInput, TCreateInput, TUpdateInput>
where TEntity : class, IEntity, IMultiStore
where TCreateInput : IMultiStore
{
protected virtual string CrossStorePolicyName { get; set; }
protected MultiStoreAbstractKeyCrudAppService(IRepository<TEntity> repository)
: base(repository)
{
}
public override async Task<TGetOutputDto> GetAsync(TKey id)
{
var entity = await GetEntityByIdAsync(id);
await CheckMultiStorePolicyAsync(entity.StoreId, GetPolicyName);
return MapToGetOutputDto(entity);
}
public override async Task<TGetOutputDto> CreateAsync(TCreateInput input)
{
await CheckMultiStorePolicyAsync(input.StoreId, CreatePolicyName);
var entity = MapToEntity(input);
TryToSetTenantId(entity);
await Repository.InsertAsync(entity, autoSave: true);
return MapToGetOutputDto(entity);
}
public override async Task<TGetOutputDto> UpdateAsync(TKey id, TUpdateInput input)
{
var entity = await GetEntityByIdAsync(id);
await CheckMultiStorePolicyAsync(entity.StoreId, UpdatePolicyName);
MapToEntity(input, entity);
await Repository.UpdateAsync(entity, autoSave: true);
return MapToGetOutputDto(entity);
}
public override async Task DeleteAsync(TKey id)
{
var entity = await GetEntityByIdAsync(id);
await CheckMultiStorePolicyAsync(entity.StoreId, DeletePolicyName);
await DeleteByIdAsync(id);
}
protected virtual async Task CheckMultiStorePolicyAsync(Guid? storeId, string policyName)
{
if (storeId.HasValue
&& await AuthorizationService.IsStoreOwnerGrantedAsync(storeId.Value, policyName))
{
return;
}
await CheckPolicyAsync(CrossStorePolicyName);
await CheckPolicyAsync(policyName);
}
}
}

65
modules/EasyAbp.EShop.Stores/src/EasyAbp.EShop.Stores.Application.Shared/EasyAbp/EShop/Stores/Stores/MultiStoreAbstractKeyReadOnlyAppService.cs

@ -0,0 +1,65 @@
using System;
using System.Threading.Tasks;
using EasyAbp.EShop.Stores.Permissions;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services;
using Volo.Abp.Domain.Entities;
using Volo.Abp.Domain.Repositories;
namespace EasyAbp.EShop.Stores.Stores
{
public abstract class MultiStoreAbstractKeyReadOnlyAppService<TEntity, TEntityDto, TKey>
: MultiStoreAbstractKeyReadOnlyAppService<TEntity, TEntityDto, TEntityDto, TKey, PagedAndSortedResultRequestDto>
where TEntity : class, IEntity, IMultiStore
{
protected MultiStoreAbstractKeyReadOnlyAppService(IReadOnlyRepository<TEntity> repository)
: base(repository)
{
}
}
public abstract class MultiStoreAbstractKeyReadOnlyAppService<TEntity, TEntityDto, TKey, TGetListInput>
: MultiStoreAbstractKeyReadOnlyAppService<TEntity, TEntityDto, TEntityDto, TKey, TGetListInput>
where TEntity : class, IEntity, IMultiStore
{
protected MultiStoreAbstractKeyReadOnlyAppService(IReadOnlyRepository<TEntity> repository)
: base(repository)
{
}
}
public abstract class MultiStoreAbstractKeyReadOnlyAppService<TEntity, TGetOutputDto, TGetListOutputDto, TKey,
TGetListInput>
: AbstractKeyReadOnlyAppService<TEntity, TGetOutputDto, TGetListOutputDto, TKey,
TGetListInput>
where TEntity : class, IEntity, IMultiStore
{
protected virtual string CrossStorePolicyName { get; set; }
protected MultiStoreAbstractKeyReadOnlyAppService(IReadOnlyRepository<TEntity> repository)
: base(repository)
{
}
public override async Task<TGetOutputDto> GetAsync(TKey id)
{
var entity = await GetEntityByIdAsync(id);
await CheckMultiStorePolicyAsync(entity.StoreId, GetPolicyName);
return MapToGetOutputDto(entity);
}
protected virtual async Task CheckMultiStorePolicyAsync(Guid? storeId, string policyName)
{
if (storeId.HasValue
&& await AuthorizationService.IsStoreOwnerGrantedAsync(storeId.Value, policyName))
{
return;
}
await CheckPolicyAsync(CrossStorePolicyName);
await CheckPolicyAsync(policyName);
}
}
}

22
modules/EasyAbp.EShop.Stores/src/EasyAbp.EShop.Stores.Application/EasyAbp/EShop/Stores/Stores/MultiStoreCrudAppService.cs → modules/EasyAbp.EShop.Stores/src/EasyAbp.EShop.Stores.Application.Shared/EasyAbp/EShop/Stores/Stores/MultiStoreCrudAppService.cs

@ -52,22 +52,10 @@ namespace EasyAbp.EShop.Stores.Stores
: base(repository) : base(repository)
{ {
} }
protected override Task<TEntityDto> MapToGetListOutputDtoAsync(TEntity entity)
{
return base.MapToGetOutputDtoAsync(entity);
}
protected override TEntityDto MapToGetListOutputDto(TEntity entity)
{
return MapToGetOutputDto(entity);
}
} }
public abstract class MultiStoreCrudAppService<TEntity, TGetOutputDto, TGetListOutputDto, TKey, TGetListInput, public abstract class MultiStoreCrudAppService<TEntity, TGetOutputDto, TGetListOutputDto, TKey, TGetListInput, TCreateInput, TUpdateInput>
TCreateInput, TUpdateInput> : MultiStoreAbstractKeyCrudAppService<TEntity, TGetOutputDto, TGetListOutputDto, TKey, TGetListInput, TCreateInput, TUpdateInput>
: MultiStoreAbstractKeyCrudAppService<TEntity, TGetOutputDto, TGetListOutputDto, TKey, TGetListInput,
TCreateInput, TUpdateInput>
where TEntity : class, IEntity<TKey>, IMultiStore where TEntity : class, IEntity<TKey>, IMultiStore
where TGetOutputDto : IEntityDto<TKey> where TGetOutputDto : IEntityDto<TKey>
where TGetListOutputDto : IEntityDto<TKey> where TGetListOutputDto : IEntityDto<TKey>
@ -103,9 +91,9 @@ namespace EasyAbp.EShop.Stores.Stores
protected override IQueryable<TEntity> ApplyDefaultSorting(IQueryable<TEntity> query) protected override IQueryable<TEntity> ApplyDefaultSorting(IQueryable<TEntity> query)
{ {
if (typeof(TEntity).IsAssignableTo<IHasCreationTime>()) if (typeof(TEntity).IsAssignableTo<ICreationAuditedObject>())
{ {
return query.OrderByDescending(e => ((IHasCreationTime) e).CreationTime); return query.OrderByDescending(e => ((ICreationAuditedObject)e).CreationTime);
} }
else else
{ {

4
modules/EasyAbp.EShop.Stores/src/EasyAbp.EShop.Stores.Application/EasyAbp/EShop/Stores/Stores/MultiStoreReadOnlyAppService.cs → modules/EasyAbp.EShop.Stores/src/EasyAbp.EShop.Stores.Application.Shared/EasyAbp/EShop/Stores/Stores/MultiStoreReadOnlyAppService.cs

@ -36,7 +36,7 @@ namespace EasyAbp.EShop.Stores.Stores
where TGetOutputDto : IEntityDto<TKey> where TGetOutputDto : IEntityDto<TKey>
where TGetListOutputDto : IEntityDto<TKey> where TGetListOutputDto : IEntityDto<TKey>
{ {
protected new IReadOnlyRepository<TEntity, TKey> Repository { get; } protected IReadOnlyRepository<TEntity, TKey> Repository { get; }
protected MultiStoreReadOnlyAppService(IReadOnlyRepository<TEntity, TKey> repository) protected MultiStoreReadOnlyAppService(IReadOnlyRepository<TEntity, TKey> repository)
: base(repository) : base(repository)
@ -53,7 +53,7 @@ namespace EasyAbp.EShop.Stores.Stores
{ {
if (typeof(TEntity).IsAssignableTo<ICreationAuditedObject>()) if (typeof(TEntity).IsAssignableTo<ICreationAuditedObject>())
{ {
return query.OrderByDescending(e => ((ICreationAuditedObject) e).CreationTime); return query.OrderByDescending(e => ((ICreationAuditedObject)e).CreationTime);
} }
else else
{ {

3
modules/EasyAbp.EShop.Stores/src/EasyAbp.EShop.Stores.Application.Shared/FodyWeavers.xml

@ -0,0 +1,3 @@
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
<ConfigureAwait ContinueOnCapturedContext="false" />
</Weavers>

30
modules/EasyAbp.EShop.Stores/src/EasyAbp.EShop.Stores.Application.Shared/FodyWeavers.xsd

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<!-- This file was generated by Fody. Manual changes to this file will be lost when your project is rebuilt. -->
<xs:element name="Weavers">
<xs:complexType>
<xs:all>
<xs:element name="ConfigureAwait" minOccurs="0" maxOccurs="1">
<xs:complexType>
<xs:attribute name="ContinueOnCapturedContext" type="xs:boolean" />
</xs:complexType>
</xs:element>
</xs:all>
<xs:attribute name="VerifyAssembly" type="xs:boolean">
<xs:annotation>
<xs:documentation>'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="VerifyIgnoreCodes" type="xs:string">
<xs:annotation>
<xs:documentation>A comma-separated list of error codes that can be safely ignored in assembly verification.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="GenerateXsd" type="xs:boolean">
<xs:annotation>
<xs:documentation>'false' to turn off automatic generation of the XML Schema file.</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
</xs:element>
</xs:schema>

1
modules/EasyAbp.EShop.Stores/src/EasyAbp.EShop.Stores.Application/EasyAbp.EShop.Stores.Application.csproj

@ -11,6 +11,7 @@
<PackageReference Include="Volo.Abp.AutoMapper" Version="3.0.5" /> <PackageReference Include="Volo.Abp.AutoMapper" Version="3.0.5" />
<PackageReference Include="Volo.Abp.Ddd.Application" Version="3.0.5" /> <PackageReference Include="Volo.Abp.Ddd.Application" Version="3.0.5" />
<ProjectReference Include="..\EasyAbp.EShop.Stores.Application.Contracts\EasyAbp.EShop.Stores.Application.Contracts.csproj" /> <ProjectReference Include="..\EasyAbp.EShop.Stores.Application.Contracts\EasyAbp.EShop.Stores.Application.Contracts.csproj" />
<ProjectReference Include="..\EasyAbp.EShop.Stores.Application.Shared\EasyAbp.EShop.Stores.Application.Shared.csproj" />
<ProjectReference Include="..\EasyAbp.EShop.Stores.Domain\EasyAbp.EShop.Stores.Domain.csproj" /> <ProjectReference Include="..\EasyAbp.EShop.Stores.Domain\EasyAbp.EShop.Stores.Domain.csproj" />
</ItemGroup> </ItemGroup>

20
modules/EasyAbp.EShop.Stores/src/EasyAbp.EShop.Stores.Application/EasyAbp/EShop/Stores/StoreOwners/StoreOwnerAppService.cs

@ -4,6 +4,7 @@ using System.Threading.Tasks;
using EasyAbp.EShop.Stores.Permissions; using EasyAbp.EShop.Stores.Permissions;
using EasyAbp.EShop.Stores.StoreOwners.Dtos; using EasyAbp.EShop.Stores.StoreOwners.Dtos;
using EasyAbp.EShop.Stores.Stores; using EasyAbp.EShop.Stores.Stores;
using Volo.Abp.Application.Dtos;
namespace EasyAbp.EShop.Stores.StoreOwners namespace EasyAbp.EShop.Stores.StoreOwners
{ {
@ -18,34 +19,37 @@ namespace EasyAbp.EShop.Stores.StoreOwners
protected override string CrossStorePolicyName { get; set; } = StoresPermissions.Stores.CrossStore; protected override string CrossStorePolicyName { get; set; } = StoresPermissions.Stores.CrossStore;
private readonly IStoreOwnerRepository _repository; private readonly IStoreOwnerRepository _repository;
private readonly IStoreOwnerStore _storeOwnerStore;
public StoreOwnerAppService(IStoreOwnerRepository repository) : base(repository) public StoreOwnerAppService(IStoreOwnerRepository repository,
IStoreOwnerStore storeOwnerStore) : base(repository)
{ {
_repository = repository; _repository = repository;
_storeOwnerStore = storeOwnerStore;
} }
public override async Task<StoreOwnerDto> CreateAsync(StoreOwnerDto input) public override async Task<StoreOwnerDto> CreateAsync(StoreOwnerDto input)
{ {
if (await _repository.IsExistAsync(input.StoreId, input.OwnerId)) if (await _repository.IsExistAsync(input.StoreId, input.OwnerUserId))
{ {
throw new StoreOwnerDuplicatedException(input.StoreId, input.OwnerId); throw new StoreOwnerDuplicatedException(input.StoreId, input.OwnerUserId);
} }
return await base.CreateAsync(input); return await base.CreateAsync(input);
} }
protected override IQueryable<StoreOwner> CreateFilteredQuery(GetStoreOwnerListDto input) protected override IQueryable<StoreOwner> CreateFilteredQuery(GetStoreOwnerListDto input)
{ {
var queryable = Repository.AsQueryable(); var queryable = Repository.AsQueryable();
if (input.StoreId.HasValue) if (input.OwnerUserId.HasValue)
{ {
queryable = queryable.Where(x => x.StoreId == input.StoreId); queryable = queryable.Where(x => x.OwnerUserId == input.OwnerUserId);
} }
if (input.OwnerId.HasValue) if (input.StoreId.HasValue)
{ {
queryable = queryable.Where(x => x.OwnerId == input.OwnerId); queryable = queryable.Where(x => x.StoreId == input.StoreId);
} }
return queryable; return queryable;

211
modules/EasyAbp.EShop.Stores/src/EasyAbp.EShop.Stores.Application/EasyAbp/EShop/Stores/Stores/MultiStoreAbstractKeyCrudAppService.cs

@ -1,211 +0,0 @@
using System;
using System.Threading.Tasks;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services;
using Volo.Abp.Domain.Entities;
using Volo.Abp.Domain.Repositories;
using Volo.Abp.MultiTenancy;
using Volo.Abp.ObjectMapping;
namespace EasyAbp.EShop.Stores.Stores
{
public abstract class MultiStoreAbstractKeyCrudAppService<TEntity, TEntityDto, TKey>
: MultiStoreAbstractKeyCrudAppService<TEntity, TEntityDto, TKey, PagedAndSortedResultRequestDto>
where TEntity : class, IEntity, IMultiStore
where TEntityDto : IMultiStore
{
protected MultiStoreAbstractKeyCrudAppService(IRepository<TEntity> repository)
: base(repository)
{
}
}
public abstract class MultiStoreAbstractKeyCrudAppService<TEntity, TEntityDto, TKey, TGetListInput>
: MultiStoreAbstractKeyCrudAppService<TEntity, TEntityDto, TKey, TGetListInput, TEntityDto, TEntityDto>
where TEntity : class, IEntity, IMultiStore
where TEntityDto : IMultiStore
{
protected MultiStoreAbstractKeyCrudAppService(IRepository<TEntity> repository)
: base(repository)
{
}
}
public abstract class MultiStoreAbstractKeyCrudAppService<TEntity, TEntityDto, TKey, TGetListInput, TCreateInput>
: MultiStoreAbstractKeyCrudAppService<TEntity, TEntityDto, TKey, TGetListInput, TCreateInput, TCreateInput>
where TEntity : class, IEntity, IMultiStore
where TCreateInput : IMultiStore
{
protected MultiStoreAbstractKeyCrudAppService(IRepository<TEntity> repository)
: base(repository)
{
}
}
public abstract class MultiStoreAbstractKeyCrudAppService<TEntity, TEntityDto, TKey, TGetListInput, TCreateInput,
TUpdateInput>
: MultiStoreAbstractKeyCrudAppService<TEntity, TEntityDto, TEntityDto, TKey, TGetListInput, TCreateInput,
TUpdateInput>
where TEntity : class, IEntity, IMultiStore
where TCreateInput : IMultiStore
{
protected MultiStoreAbstractKeyCrudAppService(IRepository<TEntity> repository)
: base(repository)
{
}
protected override Task<TEntityDto> MapToGetListOutputDtoAsync(TEntity entity)
{
return MapToGetOutputDtoAsync(entity);
}
protected override TEntityDto MapToGetListOutputDto(TEntity entity)
{
return MapToGetOutputDto(entity);
}
}
public abstract class MultiStoreAbstractKeyCrudAppService<TEntity, TGetOutputDto, TGetListOutputDto, TKey,
TGetListInput, TCreateInput, TUpdateInput>
: MultiStoreAbstractKeyReadOnlyAppService<TEntity, TGetOutputDto, TGetListOutputDto, TKey, TGetListInput>,
ICrudAppService<TGetOutputDto, TGetListOutputDto, TKey, TGetListInput, TCreateInput, TUpdateInput>
where TEntity : class, IEntity, IMultiStore
where TCreateInput : IMultiStore
{
protected IRepository<TEntity> Repository { get; }
protected virtual string CreatePolicyName { get; set; }
protected virtual string UpdatePolicyName { get; set; }
protected virtual string DeletePolicyName { get; set; }
protected MultiStoreAbstractKeyCrudAppService(IRepository<TEntity> repository)
: base(repository)
{
Repository = repository;
}
public virtual async Task<TGetOutputDto> CreateAsync(TCreateInput input)
{
await CheckMultiStorePolicyAsync(input.StoreId, CreatePolicyName);
var entity = await MapToEntityAsync(input);
TryToSetTenantId(entity);
await Repository.InsertAsync(entity, autoSave: true);
return await MapToGetOutputDtoAsync(entity);
}
public virtual async Task<TGetOutputDto> UpdateAsync(TKey id, TUpdateInput input)
{
var entity = await GetEntityByIdAsync(id);
await CheckMultiStorePolicyAsync(entity.StoreId, UpdatePolicyName);
//TODO: Check if input has id different than given id and normalize if it's default value, throw ex otherwise
await MapToEntityAsync(input, entity);
await Repository.UpdateAsync(entity, autoSave: true);
return await MapToGetOutputDtoAsync(entity);
}
public virtual async Task DeleteAsync(TKey id)
{
var entity = await GetEntityByIdAsync(id);
await CheckMultiStorePolicyAsync(entity.StoreId, DeletePolicyName);
await DeleteByIdAsync(id);
}
protected abstract Task DeleteByIdAsync(TKey id);
/// <summary>
/// Maps <see cref="TCreateInput"/> to <see cref="TEntity"/> to create a new entity.
/// It uses <see cref="MapToEntity(TCreateInput)"/> by default.
/// It can be overriden for custom mapping.
/// Overriding this has higher priority than overriding the <see cref="MapToEntity(TCreateInput)"/>
/// </summary>
protected virtual Task<TEntity> MapToEntityAsync(TCreateInput createInput)
{
return Task.FromResult(MapToEntity(createInput));
}
/// <summary>
/// Maps <see cref="TCreateInput"/> to <see cref="TEntity"/> to create a new entity.
/// It uses <see cref="IObjectMapper"/> by default.
/// It can be overriden for custom mapping.
/// </summary>
protected virtual TEntity MapToEntity(TCreateInput createInput)
{
var entity = ObjectMapper.Map<TCreateInput, TEntity>(createInput);
SetIdForGuids(entity);
return entity;
}
/// <summary>
/// Sets Id value for the entity if <see cref="TKey"/> is <see cref="Guid"/>.
/// It's used while creating a new entity.
/// </summary>
protected virtual void SetIdForGuids(TEntity entity)
{
if (entity is IEntity<Guid> entityWithGuidId && entityWithGuidId.Id == Guid.Empty)
{
EntityHelper.TrySetId(
entityWithGuidId,
() => GuidGenerator.Create(),
true
);
}
}
/// <summary>
/// Maps <see cref="TUpdateInput"/> to <see cref="TEntity"/> to update the entity.
/// It uses <see cref="MapToEntity(TUpdateInput, TEntity)"/> by default.
/// It can be overriden for custom mapping.
/// Overriding this has higher priority than overriding the <see cref="MapToEntity(TUpdateInput, TEntity)"/>
/// </summary>
protected virtual Task MapToEntityAsync(TUpdateInput updateInput, TEntity entity)
{
MapToEntity(updateInput, entity);
return Task.CompletedTask;
}
/// <summary>
/// Maps <see cref="TUpdateInput"/> to <see cref="TEntity"/> to update the entity.
/// It uses <see cref="IObjectMapper"/> by default.
/// It can be overriden for custom mapping.
/// </summary>
protected virtual void MapToEntity(TUpdateInput updateInput, TEntity entity)
{
ObjectMapper.Map(updateInput, entity);
}
protected virtual void TryToSetTenantId(TEntity entity)
{
if (entity is IMultiTenant && HasTenantIdProperty(entity))
{
var tenantId = CurrentTenant.Id;
if (!tenantId.HasValue)
{
return;
}
var propertyInfo = entity.GetType().GetProperty(nameof(IMultiTenant.TenantId));
if (propertyInfo == null || propertyInfo.GetSetMethod(true) == null)
{
return;
}
propertyInfo.SetValue(entity, tenantId);
}
}
protected virtual bool HasTenantIdProperty(TEntity entity)
{
return entity.GetType().GetProperty(nameof(IMultiTenant.TenantId)) != null;
}
}
}

236
modules/EasyAbp.EShop.Stores/src/EasyAbp.EShop.Stores.Application/EasyAbp/EShop/Stores/Stores/MultiStoreAbstractKeyReadOnlyAppService.cs

@ -1,236 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Dynamic.Core;
using System.Threading.Tasks;
using EasyAbp.EShop.Stores.Permissions;
using Volo.Abp;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services;
using Volo.Abp.Auditing;
using Volo.Abp.Domain.Entities;
using Volo.Abp.Domain.Repositories;
using Volo.Abp.ObjectMapping;
namespace EasyAbp.EShop.Stores.Stores
{
public abstract class MultiStoreAbstractKeyReadOnlyAppService<TEntity, TEntityDto, TKey>
: MultiStoreAbstractKeyReadOnlyAppService<TEntity, TEntityDto, TEntityDto, TKey, PagedAndSortedResultRequestDto>
where TEntity : class, IEntity, IMultiStore
{
protected MultiStoreAbstractKeyReadOnlyAppService(IReadOnlyRepository<TEntity> repository)
: base(repository)
{
}
}
public abstract class MultiStoreAbstractKeyReadOnlyAppService<TEntity, TEntityDto, TKey, TGetListInput>
: MultiStoreAbstractKeyReadOnlyAppService<TEntity, TEntityDto, TEntityDto, TKey, TGetListInput>
where TEntity : class, IEntity, IMultiStore
{
protected MultiStoreAbstractKeyReadOnlyAppService(IReadOnlyRepository<TEntity> repository)
: base(repository)
{
}
}
public abstract class MultiStoreAbstractKeyReadOnlyAppService<TEntity, TGetOutputDto, TGetListOutputDto, TKey,
TGetListInput>
: ApplicationService
, IReadOnlyAppService<TGetOutputDto, TGetListOutputDto, TKey, TGetListInput>
where TEntity : class, IEntity, IMultiStore
{
protected IReadOnlyRepository<TEntity> ReadOnlyRepository { get; }
protected virtual string GetPolicyName { get; set; }
protected virtual string GetListPolicyName { get; set; }
protected virtual string CrossStorePolicyName { get; set; }
protected MultiStoreAbstractKeyReadOnlyAppService(IReadOnlyRepository<TEntity> repository)
{
ReadOnlyRepository = repository;
}
public virtual async Task<TGetOutputDto> GetAsync(TKey id)
{
var entity = await GetEntityByIdAsync(id);
await CheckMultiStorePolicyAsync(entity.StoreId, GetPolicyName);
return await MapToGetOutputDtoAsync(entity);
}
public virtual async Task<PagedResultDto<TGetListOutputDto>> GetListAsync(TGetListInput input)
{
await CheckGetListPolicyAsync();
var query = CreateFilteredQuery(input);
var totalCount = await AsyncExecuter.CountAsync(query);
query = ApplySorting(query, input);
query = ApplyPaging(query, input);
var entities = await AsyncExecuter.ToListAsync(query);
var entityDtos = await MapToGetListOutputDtosAsync(entities);
return new PagedResultDto<TGetListOutputDto>(
totalCount,
entityDtos
);
}
protected virtual async Task CheckGetListPolicyAsync()
{
await CheckPolicyAsync(GetListPolicyName);
}
protected abstract Task<TEntity> GetEntityByIdAsync(TKey id);
protected virtual async Task CheckMultiStorePolicyAsync(Guid storeId, string policyName)
{
if (!await AuthorizationService.IsStoreOwnerGrantedAsync(storeId, policyName))
{
await CheckPolicyAsync(CrossStorePolicyName);
await CheckPolicyAsync(policyName);
}
}
/// <summary>
/// Should apply sorting if needed.
/// </summary>
/// <param name="query">The query.</param>
/// <param name="input">The input.</param>
protected virtual IQueryable<TEntity> ApplySorting(IQueryable<TEntity> query, TGetListInput input)
{
//Try to sort query if available
if (input is ISortedResultRequest sortInput)
{
if (!sortInput.Sorting.IsNullOrWhiteSpace())
{
return query.OrderBy(sortInput.Sorting);
}
}
//IQueryable.Task requires sorting, so we should sort if Take will be used.
if (input is ILimitedResultRequest)
{
return ApplyDefaultSorting(query);
}
//No sorting
return query;
}
/// <summary>
/// Applies sorting if no sorting specified but a limited result requested.
/// </summary>
/// <param name="query">The query.</param>
protected virtual IQueryable<TEntity> ApplyDefaultSorting(IQueryable<TEntity> query)
{
if (typeof(TEntity).IsAssignableTo<IHasCreationTime>())
{
return query.OrderByDescending(e => ((IHasCreationTime) e).CreationTime);
}
throw new AbpException(
"No sorting specified but this query requires sorting. Override the ApplyDefaultSorting method for your application service derived from AbstractKeyReadOnlyAppService!");
}
/// <summary>
/// Should apply paging if needed.
/// </summary>
/// <param name="query">The query.</param>
/// <param name="input">The input.</param>
protected virtual IQueryable<TEntity> ApplyPaging(IQueryable<TEntity> query, TGetListInput input)
{
//Try to use paging if available
if (input is IPagedResultRequest pagedInput)
{
return query.PageBy(pagedInput);
}
//Try to limit query result if available
if (input is ILimitedResultRequest limitedInput)
{
return query.Take(limitedInput.MaxResultCount);
}
//No paging
return query;
}
/// <summary>
/// This method should create <see cref="IQueryable{TEntity}"/> based on given input.
/// It should filter query if needed, but should not do sorting or paging.
/// Sorting should be done in <see cref="ApplySorting"/> and paging should be done in <see cref="ApplyPaging"/>
/// methods.
/// </summary>
/// <param name="input">The input.</param>
protected virtual IQueryable<TEntity> CreateFilteredQuery(TGetListInput input)
{
return ReadOnlyRepository;
}
/// <summary>
/// Maps <see cref="TEntity"/> to <see cref="TGetOutputDto"/>.
/// It internally calls the <see cref="MapToGetOutputDto"/> by default.
/// It can be overriden for custom mapping.
/// Overriding this has higher priority than overriding the <see cref="MapToGetOutputDto"/>
/// </summary>
protected virtual Task<TGetOutputDto> MapToGetOutputDtoAsync(TEntity entity)
{
return Task.FromResult(MapToGetOutputDto(entity));
}
/// <summary>
/// Maps <see cref="TEntity"/> to <see cref="TGetOutputDto"/>.
/// It uses <see cref="IObjectMapper"/> by default.
/// It can be overriden for custom mapping.
/// </summary>
protected virtual TGetOutputDto MapToGetOutputDto(TEntity entity)
{
return ObjectMapper.Map<TEntity, TGetOutputDto>(entity);
}
/// <summary>
/// Maps a list of <see cref="TEntity"/> to <see cref="TGetListOutputDto"/> objects.
/// It uses <see cref="MapToGetListOutputDtoAsync"/> method for each item in the list.
/// </summary>
protected virtual async Task<List<TGetListOutputDto>> MapToGetListOutputDtosAsync(List<TEntity> entities)
{
var dtos = new List<TGetListOutputDto>();
foreach (var entity in entities)
{
dtos.Add(await MapToGetListOutputDtoAsync(entity));
}
return dtos;
}
/// <summary>
/// Maps <see cref="TEntity"/> to <see cref="TGetListOutputDto"/>.
/// It internally calls the <see cref="MapToGetListOutputDto"/> by default.
/// It can be overriden for custom mapping.
/// Overriding this has higher priority than overriding the <see cref="MapToGetListOutputDto"/>
/// </summary>
protected virtual Task<TGetListOutputDto> MapToGetListOutputDtoAsync(TEntity entity)
{
return Task.FromResult(MapToGetListOutputDto(entity));
}
/// <summary>
/// Maps <see cref="TEntity"/> to <see cref="TGetListOutputDto"/>.
/// It uses <see cref="IObjectMapper"/> by default.
/// It can be overriden for custom mapping.
/// </summary>
protected virtual TGetListOutputDto MapToGetListOutputDto(TEntity entity)
{
return ObjectMapper.Map<TEntity, TGetListOutputDto>(entity);
}
}
}

4
modules/EasyAbp.EShop.Stores/src/EasyAbp.EShop.Stores.Domain/EasyAbp/EShop/Stores/StoreOwners/IStoreOwnerRepository.cs

@ -10,8 +10,8 @@ namespace EasyAbp.EShop.Stores.StoreOwners
{ {
Task<List<StoreOwner>> GetListByStoreIdAsync(Guid storeId, CancellationToken cancellationToken = default); Task<List<StoreOwner>> GetListByStoreIdAsync(Guid storeId, CancellationToken cancellationToken = default);
Task<List<StoreOwner>> GetListByOwnerIdAsync(Guid ownerId, CancellationToken cancellationToken = default); Task<List<StoreOwner>> GetListByOwnerUserIdAsync(Guid ownerUserId, CancellationToken cancellationToken = default);
Task<bool> IsExistAsync(Guid storeId, Guid ownerId, CancellationToken cancellationToken = default); Task<bool> IsExistAsync(Guid storeId, Guid ownerUserId, CancellationToken cancellationToken = default);
} }
} }

6
modules/EasyAbp.EShop.Stores/src/EasyAbp.EShop.Stores.Domain/EasyAbp/EShop/Stores/StoreOwners/StoreOwner.cs

@ -11,16 +11,16 @@ namespace EasyAbp.EShop.Stores.StoreOwners
public virtual Guid StoreId { get; protected set; } public virtual Guid StoreId { get; protected set; }
public virtual Guid OwnerId { get; protected set; } public virtual Guid OwnerUserId { get; protected set; }
protected StoreOwner() protected StoreOwner()
{ {
} }
public StoreOwner(Guid id, Guid storeId, Guid ownerId, Guid? tenantId = null) : base(id) public StoreOwner(Guid id, Guid storeId, Guid ownerUserId, Guid? tenantId = null) : base(id)
{ {
StoreId = storeId; StoreId = storeId;
OwnerId = ownerId; OwnerUserId = ownerUserId;
TenantId = tenantId; TenantId = tenantId;
} }
} }

4
modules/EasyAbp.EShop.Stores/src/EasyAbp.EShop.Stores.Domain/EasyAbp/EShop/Stores/StoreOwners/StoreOwnerStore.cs

@ -60,10 +60,10 @@ namespace EasyAbp.EShop.Stores.StoreOwners
var cacheItems = new Dictionary<string, StoreOwnerCacheItem>(); var cacheItems = new Dictionary<string, StoreOwnerCacheItem>();
foreach (var storeOwner in storeOwners) foreach (var storeOwner in storeOwners)
{ {
cacheItems.Add(CalculateCacheKey(storeOwner.StoreId, storeOwner.OwnerId), cacheItems.Add(CalculateCacheKey(storeOwner.StoreId, storeOwner.OwnerUserId),
new StoreOwnerCacheItem(true)); new StoreOwnerCacheItem(true));
if (storeOwner.StoreId == storeId && storeOwner.OwnerId == userId) if (storeOwner.OwnerUserId == userId && storeOwner.StoreId == storeId)
{ {
currentCacheItem.IsOwner = true; currentCacheItem.IsOwner = true;
} }

6
modules/EasyAbp.EShop.Stores/src/EasyAbp.EShop.Stores.EntityFrameworkCore/EasyAbp/EShop/Stores/EntityFrameworkCore/StoresDbContextModelCreatingExtensions.cs

@ -45,7 +45,7 @@ namespace EasyAbp.EShop.Stores.EntityFrameworkCore
builder.Entity<Store>(b => builder.Entity<Store>(b =>
{ {
b.ToTable(options.TablePrefix + "Stores", options.Schema); b.ToTable(options.TablePrefix + "Stores", options.Schema);
b.ConfigureByConvention(); b.ConfigureByConvention();
/* Configure more properties here */ /* Configure more properties here */
}); });
@ -55,9 +55,9 @@ namespace EasyAbp.EShop.Stores.EntityFrameworkCore
b.ConfigureByConvention(); b.ConfigureByConvention();
/* Configure more properties here */ /* Configure more properties here */
b.HasIndex(x => new {x.StoreId, x.OwnerId}) b.HasIndex(x => new {x.OwnerUserId, x.StoreId})
.IsUnique(); .IsUnique();
}); });
} }
} }
} }

8
modules/EasyAbp.EShop.Stores/src/EasyAbp.EShop.Stores.EntityFrameworkCore/EasyAbp/EShop/Stores/StoreOwners/StoreOwnerRepository.cs

@ -22,16 +22,16 @@ namespace EasyAbp.EShop.Stores.StoreOwners
return await GetQueryable().Where(pc => pc.StoreId == storeId).ToListAsync(cancellationToken); return await GetQueryable().Where(pc => pc.StoreId == storeId).ToListAsync(cancellationToken);
} }
public async Task<List<StoreOwner>> GetListByOwnerIdAsync(Guid ownerId, public async Task<List<StoreOwner>> GetListByOwnerUserIdAsync(Guid ownerUserId,
CancellationToken cancellationToken = default) CancellationToken cancellationToken = default)
{ {
return await GetQueryable().Where(pc => pc.OwnerId == ownerId).ToListAsync(cancellationToken); return await GetQueryable().Where(pc => pc.OwnerUserId == ownerUserId).ToListAsync(cancellationToken);
} }
public async Task<bool> IsExistAsync(Guid storeId, Guid ownerId, CancellationToken cancellationToken = default) public async Task<bool> IsExistAsync(Guid storeId, Guid ownerUserId, CancellationToken cancellationToken = default)
{ {
var storeOwner = await GetQueryable().FirstOrDefaultAsync( var storeOwner = await GetQueryable().FirstOrDefaultAsync(
x => x.StoreId == storeId && x.OwnerId == ownerId, x => x.OwnerUserId == ownerUserId && x.StoreId == storeId,
cancellationToken: cancellationToken); cancellationToken: cancellationToken);
return storeOwner != null; return storeOwner != null;

36
modules/EasyAbp.EShop.Stores/src/EasyAbp.EShop.Stores.Web/EasyAbp.EShop.Stores.Web.csproj

@ -24,7 +24,7 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.Extensions.FileProviders.Embedded" Version="3.1.5" /> <PackageReference Include="Microsoft.Extensions.FileProviders.Embedded" Version="3.1.5" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<EmbeddedResource Include="Pages\**\*.css" /> <EmbeddedResource Include="Pages\**\*.css" />
<EmbeddedResource Include="Pages\**\*.js" /> <EmbeddedResource Include="Pages\**\*.js" />
@ -32,44 +32,10 @@
<Content Remove="Pages\**\*.css" /> <Content Remove="Pages\**\*.css" />
<Content Remove="Pages\**\*.js" /> <Content Remove="Pages\**\*.js" />
<Content Remove="wwwroot\**\*.*" /> <Content Remove="wwwroot\**\*.*" />
<Content Update="Pages\EShop\Stores\Stores\StoreOwner\CreateModal.cshtml">
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
<Content Update="Pages\EShop\Stores\Stores\StoreOwner\EditModal.cshtml">
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
<Content Update="Pages\EShop\Stores\Stores\StoreOwner\Index.cshtml">
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Folder Include="Pages\EShop\Stores\StoreOwners" />
<Folder Include="wwwroot\" /> <Folder Include="wwwroot\" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<Compile Update="Pages\EShop\Stores\Stores\StoreOwner\CreateModal.cshtml.cs">
<DependentUpon>CreateModal.cshtml</DependentUpon>
</Compile>
<Compile Update="Pages\EShop\Stores\Stores\StoreOwner\EditModal.cshtml.cs">
<DependentUpon>EditModal.cshtml</DependentUpon>
</Compile>
<Compile Update="Pages\EShop\Stores\Stores\StoreOwner\Index.cshtml.cs">
<DependentUpon>Index.cshtml</DependentUpon>
</Compile>
<Compile Update="Pages\EShop\Stores\StoreOwners\StoreOwner\CreateModal.cshtml.cs">
<DependentUpon>CreateModal.cshtml</DependentUpon>
</Compile>
<Compile Update="Pages\EShop\Stores\StoreOwners\StoreOwner\EditModal.cshtml.cs">
<DependentUpon>EditModal.cshtml</DependentUpon>
</Compile>
<Compile Update="Pages\EShop\Stores\StoreOwners\StoreOwner\Index.cshtml.cs">
<DependentUpon>Index.cshtml</DependentUpon>
</Compile>
</ItemGroup>
</Project> </Project>

2
modules/EasyAbp.EShop.Stores/src/EasyAbp.EShop.Stores.Web/Pages/EShop/Stores/StoreOwners/StoreOwner/Index.js

@ -58,7 +58,7 @@ $(function () {
} }
}, },
{ {
data: "ownerId", data: "ownerUserId",
render: function (data, type, row, meta) { render: function (data, type, row, meta) {
var currentCell = $("#StoreOwnerTable").DataTable().cells({"row":meta.row, "column":meta.col}).nodes(0); var currentCell = $("#StoreOwnerTable").DataTable().cells({"row":meta.row, "column":meta.col}).nodes(0);
userService.get(data).then( userService.get(data).then(

2
modules/EasyAbp.EShop.Stores/src/EasyAbp.EShop.Stores.Web/Pages/EShop/Stores/StoreOwners/StoreOwner/ViewModels/CreateStoreOwnerViewModel.cs

@ -12,6 +12,6 @@ namespace EasyAbp.EShop.Stores.Web.Pages.EShop.Stores.StoreOwners.StoreOwner.Vie
[Required] [Required]
public Guid OwnerId { get; set; } public Guid MultiStoreCrudAppService { get; set; }
} }
} }
Loading…
Cancel
Save