Added tenantmanagement and users modules

pull/301/head
Halil ibrahim Kalkan 7 years ago
parent f3d06500f1
commit 745d891134

@ -0,0 +1,2 @@
# abp-tenantmanagement
Tenant management module for ABP framework.

@ -0,0 +1,116 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.27428.1
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{799CA525-4748-421A-9892-05C68BB2FA13}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{C6941869-A9FC-4BEA-AD3F-C1E104826ECA}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.TenantManagement.Domain.Shared", "src\Volo.Abp.TenantManagement.Domain.Shared\Volo.Abp.TenantManagement.Domain.Shared.csproj", "{44BBBCA1-2E6A-419E-87E6-A04468E887D1}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.TenantManagement.Domain", "src\Volo.Abp.TenantManagement.Domain\Volo.Abp.TenantManagement.Domain.csproj", "{FBFB1FD6-10B5-4416-BFD1-21A62754AD33}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.TenantManagement.Application.Contracts", "src\Volo.Abp.TenantManagement.Application.Contracts\Volo.Abp.TenantManagement.Application.Contracts.csproj", "{0C93BFF5-8B86-4CE7-86D8-893B0C44192F}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.TenantManagement.Application", "src\Volo.Abp.TenantManagement.Application\Volo.Abp.TenantManagement.Application.csproj", "{57E7A9DA-4149-4CE4-B9DC-75A064A9648B}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.TenantManagement.EntityFrameworkCore", "src\Volo.Abp.TenantManagement.EntityFrameworkCore\Volo.Abp.TenantManagement.EntityFrameworkCore.csproj", "{1BCA75A2-10DB-4200-A006-7C003767F0D9}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.TenantManagement.HttpApi", "src\Volo.Abp.TenantManagement.HttpApi\Volo.Abp.TenantManagement.HttpApi.csproj", "{996C1AB4-1F0A-4D6A-BB30-21245C7112D0}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.TenantManagement.HttpApi.Client", "src\Volo.Abp.TenantManagement.HttpApi.Client\Volo.Abp.TenantManagement.HttpApi.Client.csproj", "{3B042AC5-29F1-4037-BF17-4025092FCB7A}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.TenantManagement.Web", "src\Volo.Abp.TenantManagement.Web\Volo.Abp.TenantManagement.Web.csproj", "{2AE28C0A-1B8A-4D78-A9A1-7F2271A6F2D2}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.TenantManagement.Application.Tests", "test\Volo.Abp.TenantManagement.Application.Tests\Volo.Abp.TenantManagement.Application.Tests.csproj", "{72445B2D-07FA-4A35-A3D6-FF4ACE299BF4}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.TenantManagement.EntityFrameworkCore.Tests", "test\Volo.Abp.TenantManagement.EntityFrameworkCore.Tests\Volo.Abp.TenantManagement.EntityFrameworkCore.Tests.csproj", "{A2BB8897-EBDB-46BB-B885-F8635B21F376}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.TenantManagement.MongoDB", "src\Volo.Abp.TenantManagement.MongoDB\Volo.Abp.TenantManagement.MongoDB.csproj", "{ED95242E-3C31-4A89-9C62-93B306EFEB15}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.TenantManagement.MongoDB.Tests", "test\Volo.Abp.TenantManagement.MongoDB.Tests\Volo.Abp.TenantManagement.MongoDB.Tests.csproj", "{F75B4C54-A5F1-4101-99F5-A5B868A5146B}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.TenantManagement.TestBase", "test\Volo.Abp.TenantManagement.TestBase\Volo.Abp.TenantManagement.TestBase.csproj", "{C3BAD6E8-00CD-4283-9416-64287BB5B265}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{44BBBCA1-2E6A-419E-87E6-A04468E887D1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{44BBBCA1-2E6A-419E-87E6-A04468E887D1}.Debug|Any CPU.Build.0 = Debug|Any CPU
{44BBBCA1-2E6A-419E-87E6-A04468E887D1}.Release|Any CPU.ActiveCfg = Release|Any CPU
{44BBBCA1-2E6A-419E-87E6-A04468E887D1}.Release|Any CPU.Build.0 = Release|Any CPU
{FBFB1FD6-10B5-4416-BFD1-21A62754AD33}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FBFB1FD6-10B5-4416-BFD1-21A62754AD33}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FBFB1FD6-10B5-4416-BFD1-21A62754AD33}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FBFB1FD6-10B5-4416-BFD1-21A62754AD33}.Release|Any CPU.Build.0 = Release|Any CPU
{0C93BFF5-8B86-4CE7-86D8-893B0C44192F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0C93BFF5-8B86-4CE7-86D8-893B0C44192F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0C93BFF5-8B86-4CE7-86D8-893B0C44192F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0C93BFF5-8B86-4CE7-86D8-893B0C44192F}.Release|Any CPU.Build.0 = Release|Any CPU
{57E7A9DA-4149-4CE4-B9DC-75A064A9648B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{57E7A9DA-4149-4CE4-B9DC-75A064A9648B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{57E7A9DA-4149-4CE4-B9DC-75A064A9648B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{57E7A9DA-4149-4CE4-B9DC-75A064A9648B}.Release|Any CPU.Build.0 = Release|Any CPU
{1BCA75A2-10DB-4200-A006-7C003767F0D9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1BCA75A2-10DB-4200-A006-7C003767F0D9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1BCA75A2-10DB-4200-A006-7C003767F0D9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1BCA75A2-10DB-4200-A006-7C003767F0D9}.Release|Any CPU.Build.0 = Release|Any CPU
{996C1AB4-1F0A-4D6A-BB30-21245C7112D0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{996C1AB4-1F0A-4D6A-BB30-21245C7112D0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{996C1AB4-1F0A-4D6A-BB30-21245C7112D0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{996C1AB4-1F0A-4D6A-BB30-21245C7112D0}.Release|Any CPU.Build.0 = Release|Any CPU
{3B042AC5-29F1-4037-BF17-4025092FCB7A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3B042AC5-29F1-4037-BF17-4025092FCB7A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3B042AC5-29F1-4037-BF17-4025092FCB7A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3B042AC5-29F1-4037-BF17-4025092FCB7A}.Release|Any CPU.Build.0 = Release|Any CPU
{2AE28C0A-1B8A-4D78-A9A1-7F2271A6F2D2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2AE28C0A-1B8A-4D78-A9A1-7F2271A6F2D2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2AE28C0A-1B8A-4D78-A9A1-7F2271A6F2D2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2AE28C0A-1B8A-4D78-A9A1-7F2271A6F2D2}.Release|Any CPU.Build.0 = Release|Any CPU
{72445B2D-07FA-4A35-A3D6-FF4ACE299BF4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{72445B2D-07FA-4A35-A3D6-FF4ACE299BF4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{72445B2D-07FA-4A35-A3D6-FF4ACE299BF4}.Release|Any CPU.ActiveCfg = Release|Any CPU
{72445B2D-07FA-4A35-A3D6-FF4ACE299BF4}.Release|Any CPU.Build.0 = Release|Any CPU
{A2BB8897-EBDB-46BB-B885-F8635B21F376}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A2BB8897-EBDB-46BB-B885-F8635B21F376}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A2BB8897-EBDB-46BB-B885-F8635B21F376}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A2BB8897-EBDB-46BB-B885-F8635B21F376}.Release|Any CPU.Build.0 = Release|Any CPU
{ED95242E-3C31-4A89-9C62-93B306EFEB15}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{ED95242E-3C31-4A89-9C62-93B306EFEB15}.Debug|Any CPU.Build.0 = Debug|Any CPU
{ED95242E-3C31-4A89-9C62-93B306EFEB15}.Release|Any CPU.ActiveCfg = Release|Any CPU
{ED95242E-3C31-4A89-9C62-93B306EFEB15}.Release|Any CPU.Build.0 = Release|Any CPU
{F75B4C54-A5F1-4101-99F5-A5B868A5146B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F75B4C54-A5F1-4101-99F5-A5B868A5146B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F75B4C54-A5F1-4101-99F5-A5B868A5146B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F75B4C54-A5F1-4101-99F5-A5B868A5146B}.Release|Any CPU.Build.0 = Release|Any CPU
{C3BAD6E8-00CD-4283-9416-64287BB5B265}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C3BAD6E8-00CD-4283-9416-64287BB5B265}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C3BAD6E8-00CD-4283-9416-64287BB5B265}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C3BAD6E8-00CD-4283-9416-64287BB5B265}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{44BBBCA1-2E6A-419E-87E6-A04468E887D1} = {799CA525-4748-421A-9892-05C68BB2FA13}
{FBFB1FD6-10B5-4416-BFD1-21A62754AD33} = {799CA525-4748-421A-9892-05C68BB2FA13}
{0C93BFF5-8B86-4CE7-86D8-893B0C44192F} = {799CA525-4748-421A-9892-05C68BB2FA13}
{57E7A9DA-4149-4CE4-B9DC-75A064A9648B} = {799CA525-4748-421A-9892-05C68BB2FA13}
{1BCA75A2-10DB-4200-A006-7C003767F0D9} = {799CA525-4748-421A-9892-05C68BB2FA13}
{996C1AB4-1F0A-4D6A-BB30-21245C7112D0} = {799CA525-4748-421A-9892-05C68BB2FA13}
{3B042AC5-29F1-4037-BF17-4025092FCB7A} = {799CA525-4748-421A-9892-05C68BB2FA13}
{2AE28C0A-1B8A-4D78-A9A1-7F2271A6F2D2} = {799CA525-4748-421A-9892-05C68BB2FA13}
{72445B2D-07FA-4A35-A3D6-FF4ACE299BF4} = {C6941869-A9FC-4BEA-AD3F-C1E104826ECA}
{A2BB8897-EBDB-46BB-B885-F8635B21F376} = {C6941869-A9FC-4BEA-AD3F-C1E104826ECA}
{ED95242E-3C31-4A89-9C62-93B306EFEB15} = {799CA525-4748-421A-9892-05C68BB2FA13}
{F75B4C54-A5F1-4101-99F5-A5B868A5146B} = {C6941869-A9FC-4BEA-AD3F-C1E104826ECA}
{C3BAD6E8-00CD-4283-9416-64287BB5B265} = {C6941869-A9FC-4BEA-AD3F-C1E104826ECA}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {7C258726-2CE0-44D3-A2D7-71812E8F505C}
EndGlobalSection
EndGlobal

@ -0,0 +1,16 @@
<Project>
<PropertyGroup>
<LangVersion>latest</LangVersion>
<Version>0.3.0</Version>
<NoWarn>$(NoWarn);CS1591</NoWarn>
<PackageIconUrl>http://www.aspnetboilerplate.com/images/abp_nupkg.png</PackageIconUrl>
<PackageProjectUrl>http://abp.io</PackageProjectUrl>
<RepositoryType>git</RepositoryType>
<RepositoryUrl>https://github.com/volosoft/abp/</RepositoryUrl>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="SourceLink.Create.CommandLine" Version="2.8.1" PrivateAssets="All" />
</ItemGroup>
</Project>

@ -0,0 +1,26 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\common.props" />
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<AssemblyName>Volo.Abp.TenantManagement.Application.Contracts</AssemblyName>
<PackageId>Volo.Abp.TenantManagement.Application.Contracts</PackageId>
<AssetTargetFallback>$(AssetTargetFallback);portable-net45+win8+wp8+wpa81;</AssetTargetFallback>
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute>
<GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute>
<GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute>
<RootNamespace />
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Volo.Abp.TenantManagement.Domain.Shared\Volo.Abp.TenantManagement.Domain.Shared.csproj" />
<ProjectReference Include="..\..\..\abp\src\Volo.Abp.Ddd.Application\Volo.Abp.Ddd.Application.csproj" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Volo\Abp\TenantManagement\Localization\ApplicationContracts\*.json" />
</ItemGroup>
</Project>

@ -0,0 +1,37 @@
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.Application;
using Volo.Abp.Authorization.Permissions;
using Volo.Abp.Localization;
using Volo.Abp.Modularity;
using Volo.Abp.TenantManagement.Localization;
using Volo.Abp.VirtualFileSystem;
namespace Volo.Abp.TenantManagement
{
[DependsOn(typeof(AbpDddApplicationModule))]
[DependsOn(typeof(AbpTenantManagementDomainSharedModule))]
public class AbpTenantManagementApplicationContractsModule : AbpModule
{
public override void ConfigureServices(IServiceCollection services)
{
services.Configure<PermissionOptions>(options =>
{
options.DefinitionProviders.Add<AbpTenantManagementPermissionDefinitionProvider>();
});
services.Configure<VirtualFileSystemOptions>(options =>
{
options.FileSets.AddEmbedded<AbpTenantManagementApplicationContractsModule>();
});
services.Configure<AbpLocalizationOptions>(options =>
{
options.Resources
.Get<AbpTenantManagementResource>()
.AddVirtualJson("/Volo/Abp/TenantManagement/Localization/ApplicationContracts");
});
services.AddAssemblyOf<AbpTenantManagementApplicationContractsModule>();
}
}
}

@ -0,0 +1,24 @@
using Volo.Abp.Authorization.Permissions;
using Volo.Abp.Localization;
using Volo.Abp.TenantManagement.Localization;
namespace Volo.Abp.TenantManagement
{
public class AbpTenantManagementPermissionDefinitionProvider : PermissionDefinitionProvider
{
public override void Define(IPermissionDefinitionContext context)
{
var identityGroup = context.AddGroup(TenantManagementPermissions.GroupName, L("Permission:TenantManagement"));
var rolesPermission = identityGroup.AddPermission(TenantManagementPermissions.Tenants.Default, L("Permission:TenantManagement"));
rolesPermission.AddChild(TenantManagementPermissions.Tenants.Create, L("Permission:Create"));
rolesPermission.AddChild(TenantManagementPermissions.Tenants.Update, L("Permission:Edit"));
rolesPermission.AddChild(TenantManagementPermissions.Tenants.Delete, L("Permission:Delete"));
}
private static LocalizableString L(string name)
{
return LocalizableString.Create<AbpTenantManagementResource>(name);
}
}
}

@ -0,0 +1,9 @@
using Volo.Abp.Application.Dtos;
namespace Volo.Abp.TenantManagement
{
public class GetTenantsInput : PagedAndSortedResultRequestDto
{
public string Filter { get; set; }
}
}

@ -0,0 +1,10 @@
using System;
using Volo.Abp.Application.Services;
namespace Volo.Abp.TenantManagement
{
public interface ITenantAppService : IAsyncCrudAppService<TenantDto, Guid, GetTenantsInput, TenantCreateDto, TenantUpdateDto>
{
//TODO: Manage connection strings
}
}

@ -0,0 +1,9 @@
{
"culture": "en",
"texts": {
"Permission:TenantManagement": "Tenant management",
"Permission:Create": "Create",
"Permission:Edit": "Edit",
"Permission:Delete": "Delete"
}
}

@ -0,0 +1,9 @@
{
"culture": "tr",
"texts": {
"Permission:TenantManagement": "Müşteri yönetimi",
"Permission:Create": "Oluşturma",
"Permission:Edit": "Düzenleme",
"Permission:Delete": "Silme"
}
}

@ -0,0 +1,7 @@
namespace Volo.Abp.TenantManagement
{
public class TenantCreateDto : TenantCreateOrUpdateDtoBase
{
}
}

@ -0,0 +1,7 @@
namespace Volo.Abp.TenantManagement
{
public abstract class TenantCreateOrUpdateDtoBase
{
public string Name { get; set; }
}
}

@ -0,0 +1,10 @@
using System;
using Volo.Abp.Application.Dtos;
namespace Volo.Abp.TenantManagement
{
public class TenantDto : EntityDto<Guid>
{
public string Name { get; set; }
}
}

@ -0,0 +1,15 @@
namespace Volo.Abp.TenantManagement
{
public static class TenantManagementPermissions
{
public const string GroupName = "AbpTenantManagement";
public static class Tenants
{
public const string Default = GroupName + ".Tenants";
public const string Create = Default + ".Create";
public const string Update = Default + ".Update";
public const string Delete = Default + ".Delete";
}
}
}

@ -0,0 +1,7 @@
namespace Volo.Abp.TenantManagement
{
public class TenantUpdateDto : TenantCreateOrUpdateDtoBase
{
}
}

@ -0,0 +1,23 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\common.props" />
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<AssemblyName>Volo.Abp.TenantManagement.Application</AssemblyName>
<PackageId>Volo.Abp.TenantManagement.Application</PackageId>
<AssetTargetFallback>$(AssetTargetFallback);portable-net45+win8+wp8+wpa81;</AssetTargetFallback>
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute>
<GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute>
<GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute>
<RootNamespace />
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Volo.Abp.TenantManagement.Application.Contracts\Volo.Abp.TenantManagement.Application.Contracts.csproj" />
<ProjectReference Include="..\Volo.Abp.TenantManagement.Domain\Volo.Abp.TenantManagement.Domain.csproj" />
<ProjectReference Include="..\..\..\abp\src\Volo.Abp.UI\Volo.Abp.UI.csproj" />
</ItemGroup>
</Project>

@ -0,0 +1,12 @@
using AutoMapper;
namespace Volo.Abp.TenantManagement
{
public class AbpTenantManagementApplicationAutoMapperProfile : Profile
{
public AbpTenantManagementApplicationAutoMapperProfile()
{
CreateMap<Tenant, TenantDto>();
}
}
}

@ -0,0 +1,21 @@
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.AutoMapper;
using Volo.Abp.Modularity;
namespace Volo.Abp.TenantManagement
{
[DependsOn(typeof(AbpTenantManagementDomainModule))]
[DependsOn(typeof(AbpTenantManagementApplicationContractsModule))]
public class AbpTenantManagementApplicationModule : AbpModule
{
public override void ConfigureServices(IServiceCollection services)
{
services.Configure<AbpAutoMapperOptions>(options =>
{
options.AddProfile<AbpTenantManagementApplicationAutoMapperProfile>(validate: true);
});
services.AddAssemblyOf<AbpTenantManagementApplicationModule>();
}
}
}

@ -0,0 +1,68 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Volo.Abp.Application.Dtos;
namespace Volo.Abp.TenantManagement
{
[Authorize(TenantManagementPermissions.Tenants.Default)]
public class TenantAppService : TenantManagementAppServiceBase, ITenantAppService
{
private readonly ITenantRepository _tenantRepository;
private readonly ITenantManager _tenantManager;
public TenantAppService(ITenantRepository tenantRepository, ITenantManager tenantManager)
{
_tenantRepository = tenantRepository;
_tenantManager = tenantManager;
}
public async Task<TenantDto> GetAsync(Guid id)
{
return ObjectMapper.Map<Tenant, TenantDto>(
await _tenantRepository.GetAsync(id)
);
}
public async Task<PagedResultDto<TenantDto>> GetListAsync(GetTenantsInput input)
{
var count = await _tenantRepository.GetCountAsync();
var list = await _tenantRepository.GetListAsync(input.Sorting, input.MaxResultCount, input.SkipCount, input.Filter);
return new PagedResultDto<TenantDto>(
count,
ObjectMapper.Map<List<Tenant>, List<TenantDto>>(list)
);
}
[Authorize(TenantManagementPermissions.Tenants.Create)]
public async Task<TenantDto> CreateAsync(TenantCreateDto input)
{
var tenant = await _tenantManager.CreateAsync(input.Name);
await _tenantRepository.InsertAsync(tenant);
return ObjectMapper.Map<Tenant, TenantDto>(tenant);
}
[Authorize(TenantManagementPermissions.Tenants.Update)]
public async Task<TenantDto> UpdateAsync(Guid id, TenantUpdateDto input)
{
var tenant = await _tenantRepository.GetAsync(id);
await _tenantManager.ChangeNameAsync(tenant, input.Name);
await _tenantRepository.UpdateAsync(tenant);
return ObjectMapper.Map<Tenant, TenantDto>(tenant);
}
[Authorize(TenantManagementPermissions.Tenants.Delete)]
public async Task DeleteAsync(Guid id)
{
var tenant = await _tenantRepository.FindAsync(id);
if (tenant == null)
{
return;
}
await _tenantRepository.DeleteAsync(tenant);
}
}
}

@ -0,0 +1,9 @@
using Volo.Abp.Application.Services;
namespace Volo.Abp.TenantManagement
{
public class TenantManagementAppServiceBase : ApplicationService
{
}
}

@ -0,0 +1,20 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\common.props" />
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<AssemblyName>Volo.Abp.TenantManagement.Domain.Shared</AssemblyName>
<PackageId>Volo.Abp.TenantManagement.Domain.Shared</PackageId>
<AssetTargetFallback>$(AssetTargetFallback);portable-net45+win8+wp8+wpa81;</AssetTargetFallback>
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute>
<GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute>
<GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute>
<RootNamespace />
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\abp\src\Volo.Abp.Localization\Volo.Abp.Localization.csproj" />
</ItemGroup>
</Project>

@ -0,0 +1,20 @@
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.Localization;
using Volo.Abp.Modularity;
using Volo.Abp.TenantManagement.Localization;
namespace Volo.Abp.TenantManagement
{
public class AbpTenantManagementDomainSharedModule : AbpModule
{
public override void ConfigureServices(IServiceCollection services)
{
services.Configure<AbpLocalizationOptions>(options =>
{
options.Resources.Add<AbpTenantManagementResource>("en");
});
services.AddAssemblyOf<AbpTenantManagementDomainSharedModule>();
}
}
}

@ -0,0 +1,10 @@
using Volo.Abp.Localization;
namespace Volo.Abp.TenantManagement.Localization
{
[LocalizationResourceName("AbpTenantManagement")]
public class AbpTenantManagementResource
{
}
}

@ -0,0 +1,9 @@
namespace Volo.Abp.TenantManagement
{
public static class TenantConnectionStringConsts
{
public const int MaxNameLength = 128;
public const int MaxValueLength = 1024;
}
}

@ -0,0 +1,7 @@
namespace Volo.Abp.TenantManagement
{
public static class TenantConsts
{
public const int MaxNameLength = 64;
}
}

@ -0,0 +1,26 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\common.props" />
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<AssemblyName>Volo.Abp.TenantManagement.Domain</AssemblyName>
<PackageId>Volo.Abp.TenantManagement.Domain</PackageId>
<AssetTargetFallback>$(AssetTargetFallback);portable-net45+win8+wp8+wpa81;</AssetTargetFallback>
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute>
<GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute>
<GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute>
<RootNamespace />
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Volo.Abp.TenantManagement.Domain.Shared\Volo.Abp.TenantManagement.Domain.Shared.csproj" />
<ProjectReference Include="..\..\..\abp\src\Volo.Abp.AutoMapper\Volo.Abp.AutoMapper.csproj" />
<ProjectReference Include="..\..\..\abp\src\Volo.Abp.Data\Volo.Abp.Data.csproj" />
<ProjectReference Include="..\..\..\abp\src\Volo.Abp.Ddd.Domain\Volo.Abp.Ddd.Domain.csproj" />
<ProjectReference Include="..\..\..\abp\src\Volo.Abp.MultiTenancy.Abstractions\Volo.Abp.MultiTenancy.Abstractions.csproj" />
<ProjectReference Include="..\..\..\abp\src\Volo.Abp.UI\Volo.Abp.UI.csproj" />
</ItemGroup>
</Project>

@ -0,0 +1,2 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:String x:Key="/Default/CodeInspection/CSharpLanguageProject/LanguageLevel/@EntryValue">CSharp71</s:String></wpf:ResourceDictionary>

@ -0,0 +1,9 @@
namespace Volo.Abp.TenantManagement
{
public static class AbpTenantManagementConsts
{
public const string DefaultDbTablePrefix = "Abp";
public const string DefaultDbSchema = null;
}
}

@ -0,0 +1,28 @@
using AutoMapper;
using Volo.Abp.Data;
using Volo.Abp.MultiTenancy;
namespace Volo.Abp.TenantManagement
{
public class AbpTenantManagementDomainMappingProfile : Profile
{
public AbpTenantManagementDomainMappingProfile()
{
CreateMap<Tenant, TenantInfo>()
.ForMember(ti => ti.ConnectionStrings, opts =>
{
opts.ResolveUsing(tenant =>
{
var connStrings = new ConnectionStrings();
foreach (var connectionString in tenant.ConnectionStrings)
{
connStrings[connectionString.Name] = connectionString.Value;
}
return connStrings;
});
});
}
}
}

@ -0,0 +1,29 @@
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.AutoMapper;
using Volo.Abp.Data;
using Volo.Abp.Domain;
using Volo.Abp.Modularity;
using Volo.Abp.MultiTenancy;
using Volo.Abp.UI;
namespace Volo.Abp.TenantManagement
{
[DependsOn(typeof(AbpMultiTenancyAbstractionsModule))]
[DependsOn(typeof(AbpTenantManagementDomainSharedModule))]
[DependsOn(typeof(AbpDataModule))]
[DependsOn(typeof(AbpDddDomainModule))]
[DependsOn(typeof(AbpAutoMapperModule))]
[DependsOn(typeof(AbpUiModule))] //TODO: It's not good to depend on the UI module. However, UserFriendlyException is inside it!
public class AbpTenantManagementDomainModule : AbpModule
{
public override void ConfigureServices(IServiceCollection services)
{
services.Configure<AbpAutoMapperOptions>(options =>
{
options.AddProfile<AbpTenantManagementDomainMappingProfile>(validate: true);
});
services.AddAssemblyOf<AbpTenantManagementDomainModule>();
}
}
}

@ -0,0 +1,14 @@
using System.Threading.Tasks;
using JetBrains.Annotations;
using Volo.Abp.Domain.Services;
namespace Volo.Abp.TenantManagement
{
public interface ITenantManager : IDomainService
{
[NotNull]
Task<Tenant> CreateAsync([NotNull] string name);
Task ChangeNameAsync([NotNull] Tenant tenant, [NotNull] string name);
}
}

@ -0,0 +1,26 @@
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Volo.Abp.Domain.Repositories;
namespace Volo.Abp.TenantManagement
{
public interface ITenantRepository : IBasicRepository<Tenant, Guid>
{
Task<Tenant> FindByNameAsync(
string name,
bool includeDetails = true,
CancellationToken cancellationToken = default);
Task<List<Tenant>> GetListAsync(
string sorting = null,
int maxResultCount = int.MaxValue,
int skipCount = 0,
string filter = null,
bool includeDetails = false,
CancellationToken cancellationToken = default);
Task<long> GetCountAsync(CancellationToken cancellationToken = default);
}
}

@ -0,0 +1,53 @@
using System;
using System.Collections.Generic;
using System.Linq;
using JetBrains.Annotations;
using Volo.Abp.Data;
using Volo.Abp.Domain.Entities;
namespace Volo.Abp.TenantManagement
{
public class Tenant : AggregateRoot<Guid>, IHasExtraProperties
{
public virtual string Name { get; protected set; }
public virtual List<TenantConnectionString> ConnectionStrings { get; protected set; }
public Dictionary<string, object> ExtraProperties { get; }
protected Tenant()
{
ExtraProperties = new Dictionary<string, object>();
}
protected internal Tenant(Guid id, [NotNull] string name)
{
Check.NotNull(name, nameof(name));
Id = id;
Name = name;
ConnectionStrings = new List<TenantConnectionString>();
ExtraProperties = new Dictionary<string, object>();
}
[CanBeNull]
public virtual string FindDefaultConnectionString()
{
return FindConnectionString(Data.ConnectionStrings.DefaultConnectionStringName);
}
[CanBeNull]
public virtual string FindConnectionString(string name)
{
return ConnectionStrings.FirstOrDefault(c => c.Name == name)?.Value;
}
internal void SetName([NotNull] string name)
{
Check.NotNull(name, nameof(name));
Name = name;
}
}
}

@ -0,0 +1,30 @@
using System;
using JetBrains.Annotations;
using Volo.Abp.Domain.Entities;
namespace Volo.Abp.TenantManagement
{
public class TenantConnectionString : Entity
{
public virtual Guid TenantId { get; protected set; }
public virtual string Name { get; protected set; }
public virtual string Value { get; protected set; }
protected TenantConnectionString()
{
}
public TenantConnectionString(Guid tenantId, [NotNull] string name, [NotNull] string value)
{
Check.NotNull(name, nameof(name));
Check.NotNull(value, nameof(value));
TenantId = tenantId;
Name = name;
Value = value;
}
}
}

@ -0,0 +1,43 @@
using System;
using System.Threading.Tasks;
using Volo.Abp.Domain.Services;
using Volo.Abp.UI;
namespace Volo.Abp.TenantManagement
{
public class TenantManager : DomainService, ITenantManager
{
private readonly ITenantRepository _tenantRepository;
public TenantManager(ITenantRepository tenantRepository)
{
_tenantRepository = tenantRepository;
}
public async Task<Tenant> CreateAsync(string name)
{
Check.NotNull(name, nameof(name));
await ValidateNameAsync(name);
return new Tenant(GuidGenerator.Create(), name);
}
public async Task ChangeNameAsync(Tenant tenant, string name)
{
Check.NotNull(tenant, nameof(tenant));
Check.NotNull(name, nameof(name));
await ValidateNameAsync(name, tenant.Id);
tenant.SetName(name);
}
protected virtual async Task ValidateNameAsync(string name, Guid? expectedId = null)
{
var tenant = await _tenantRepository.FindByNameAsync(name);
if (tenant != null && tenant.Id != expectedId)
{
throw new UserFriendlyException("Duplicate tenancy name: " + name); //TODO: A domain exception would be better..?
}
}
}
}

@ -0,0 +1,55 @@
using System;
using System.Threading.Tasks;
using Volo.Abp.DependencyInjection;
using Volo.Abp.MultiTenancy;
using Volo.Abp.ObjectMapping;
namespace Volo.Abp.TenantManagement
{
//TODO: This class should use caching instead of querying everytime!
public class TenantStore : ITenantStore, ITransientDependency
{
private readonly ITenantRepository _tenantRepository;
private readonly IObjectMapper _objectMapper;
private readonly ICurrentTenant _currentTenant;
public TenantStore(
ITenantRepository tenantRepository,
IObjectMapper objectMapper,
ICurrentTenant currentTenant)
{
_tenantRepository = tenantRepository;
_objectMapper = objectMapper;
_currentTenant = currentTenant;
}
public async Task<TenantInfo> FindAsync(string name)
{
using (_currentTenant.Change(null)) //TODO: No need this if we can implement to define host side (or tenant-independent) entities!
{
var tenant = await _tenantRepository.FindByNameAsync(name);
if (tenant == null)
{
return null;
}
return _objectMapper.Map<Tenant, TenantInfo>(tenant);
}
}
public async Task<TenantInfo> FindAsync(Guid id)
{
using (_currentTenant.Change(null)) //TODO: No need this if we can implement to define host side (or tenant-independent) entities!
{
var tenant = await _tenantRepository.FindAsync(id);
if (tenant == null)
{
return null;
}
return _objectMapper.Map<Tenant, TenantInfo>(tenant);
}
}
}
}

@ -0,0 +1,22 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\common.props" />
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<AssemblyName>Volo.Abp.TenantManagement.EntityFrameworkCore</AssemblyName>
<PackageId>Volo.Abp.TenantManagement.EntityFrameworkCore</PackageId>
<AssetTargetFallback>$(AssetTargetFallback);portable-net45+win8+wp8+wpa81;</AssetTargetFallback>
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute>
<GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute>
<GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute>
<RootNamespace />
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Volo.Abp.TenantManagement.Domain\Volo.Abp.TenantManagement.Domain.csproj" />
<ProjectReference Include="..\..\..\abp\src\Volo.Abp.EntityFrameworkCore\Volo.Abp.EntityFrameworkCore.csproj" />
</ItemGroup>
</Project>

@ -0,0 +1,2 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:String x:Key="/Default/CodeInspection/CSharpLanguageProject/LanguageLevel/@EntryValue">CSharp71</s:String></wpf:ResourceDictionary>

@ -0,0 +1,42 @@
using JetBrains.Annotations;
using Microsoft.EntityFrameworkCore;
namespace Volo.Abp.TenantManagement.EntityFrameworkCore
{
public static class AbpTenantManagementDbContextModelCreatingExtensions
{
public static void ConfigureTenantManagement(
this ModelBuilder builder,
[CanBeNull] string tablePrefix = AbpTenantManagementConsts.DefaultDbTablePrefix,
[CanBeNull] string schema = AbpTenantManagementConsts.DefaultDbSchema)
{
Check.NotNull(builder, nameof(builder));
if (tablePrefix == null)
{
tablePrefix = "";
}
builder.Entity<Tenant>(b =>
{
b.ToTable(tablePrefix + "Tenants", schema);
b.Property(t => t.Name).IsRequired().HasMaxLength(TenantConsts.MaxNameLength);
b.HasMany(u => u.ConnectionStrings).WithOne().HasForeignKey(uc => uc.TenantId).IsRequired();
b.HasIndex(u => u.Name).IsUnique();
});
builder.Entity<TenantConnectionString>(b =>
{
b.ToTable(tablePrefix + "TenantConnectionStrings", schema);
b.HasKey(x => new { x.TenantId, x.Name });
b.Property(cs => cs.Name).IsRequired().HasMaxLength(TenantConnectionStringConsts.MaxNameLength);
b.Property(cs => cs.Value).IsRequired().HasMaxLength(TenantConnectionStringConsts.MaxValueLength);
});
}
}
}

@ -0,0 +1,21 @@
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.EntityFrameworkCore;
using Volo.Abp.Modularity;
namespace Volo.Abp.TenantManagement.EntityFrameworkCore
{
[DependsOn(typeof(AbpTenantManagementDomainModule))]
[DependsOn(typeof(AbpEntityFrameworkCoreModule))]
public class AbpTenantManagementEntityFrameworkCoreModule : AbpModule
{
public override void ConfigureServices(IServiceCollection services)
{
services.AddAbpDbContext<TenantManagementDbContext>(options =>
{
options.AddDefaultRepositories<ITenantManagementDbContext>();
});
services.AddAssemblyOf<AbpTenantManagementEntityFrameworkCoreModule>();
}
}
}

@ -0,0 +1,61 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Dynamic.Core;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using Volo.Abp.Domain.Repositories.EntityFrameworkCore;
using Volo.Abp.EntityFrameworkCore;
namespace Volo.Abp.TenantManagement.EntityFrameworkCore
{
public class EfCoreTenantRepository : EfCoreRepository<ITenantManagementDbContext, Tenant, Guid>, ITenantRepository
{
public EfCoreTenantRepository(IDbContextProvider<ITenantManagementDbContext> dbContextProvider)
: base(dbContextProvider)
{
}
public virtual async Task<Tenant> FindByNameAsync(
string name,
bool includeDetails = true,
CancellationToken cancellationToken = default)
{
return await DbSet
.IncludeDetails(includeDetails)
.FirstOrDefaultAsync(t => t.Name == name, cancellationToken);
}
public virtual async Task<List<Tenant>> GetListAsync(
string sorting = null,
int maxResultCount = int.MaxValue,
int skipCount = 0,
string filter = null,
bool includeDetails = false,
CancellationToken cancellationToken = default)
{
return await DbSet
.IncludeDetails(includeDetails)
.WhereIf(
!filter.IsNullOrWhiteSpace(),
u =>
u.Name.Contains(filter)
)
.OrderBy(sorting ?? nameof(Tenant.Name))
.PageBy(skipCount, maxResultCount)
.ToListAsync(cancellationToken);
}
public virtual async Task<long> GetCountAsync(CancellationToken cancellationToken = default)
{
return await DbSet.LongCountAsync(cancellationToken);
}
public override IQueryable<Tenant> WithDetails()
{
return GetQueryable().IncludeDetails();
}
}
}

@ -0,0 +1,14 @@
using Microsoft.EntityFrameworkCore;
using Volo.Abp.Data;
using Volo.Abp.EntityFrameworkCore;
namespace Volo.Abp.TenantManagement.EntityFrameworkCore
{
[ConnectionStringName("AbpTenantManagement")]
public interface ITenantManagementDbContext : IEfCoreDbContext
{
DbSet<Tenant> Tenants { get; set; }
DbSet<TenantConnectionString> TenantConnectionStrings { get; set; }
}
}

@ -0,0 +1,30 @@
using Microsoft.EntityFrameworkCore;
using Volo.Abp.Data;
using Volo.Abp.EntityFrameworkCore;
namespace Volo.Abp.TenantManagement.EntityFrameworkCore
{
[ConnectionStringName("AbpTenantManagement")]
public class TenantManagementDbContext : AbpDbContext<TenantManagementDbContext>, ITenantManagementDbContext
{
public static string TablePrefix { get; set; } = AbpTenantManagementConsts.DefaultDbTablePrefix;
public static string Schema { get; set; } = AbpTenantManagementConsts.DefaultDbSchema;
public DbSet<Tenant> Tenants { get; set; }
public DbSet<TenantConnectionString> TenantConnectionStrings { get; set; }
public TenantManagementDbContext(DbContextOptions<TenantManagementDbContext> options)
: base(options)
{
}
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
builder.ConfigureTenantManagement(TablePrefix, Schema);
}
}
}

@ -0,0 +1,19 @@
using System.Linq;
using Microsoft.EntityFrameworkCore;
namespace Volo.Abp.TenantManagement.EntityFrameworkCore
{
public static class TenantManagementEfCoreQueryableExtensions
{
public static IQueryable<Tenant> IncludeDetails(this IQueryable<Tenant> queryable, bool include = true)
{
if (!include)
{
return queryable;
}
return queryable
.Include(x => x.ConnectionStrings);
}
}
}

@ -0,0 +1,22 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\common.props" />
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<AssemblyName>Volo.Abp.TenantManagement.HttpApi.Client</AssemblyName>
<PackageId>Volo.Abp.TenantManagement.HttpApi.Client</PackageId>
<AssetTargetFallback>$(AssetTargetFallback);portable-net45+win8+wp8+wpa81;</AssetTargetFallback>
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute>
<GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute>
<GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute>
<RootNamespace />
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Volo.Abp.TenantManagement.Application.Contracts\Volo.Abp.TenantManagement.Application.Contracts.csproj" />
<ProjectReference Include="..\..\..\abp\src\Volo.Abp.Http.Client\Volo.Abp.Http.Client.csproj" />
</ItemGroup>
</Project>

@ -0,0 +1,24 @@
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.Http.Client;
using Volo.Abp.Modularity;
namespace Volo.Abp.TenantManagement
{
[DependsOn(
typeof(AbpTenantManagementApplicationContractsModule),
typeof(AbpHttpClientModule))]
public class AbpTenantManagementHttpApiClientModule : AbpModule
{
public const string RemoteServiceName = "AbpTenantManagement";
public override void ConfigureServices(IServiceCollection services)
{
services.AddHttpClientProxies(
typeof(AbpTenantManagementApplicationContractsModule).Assembly,
RemoteServiceName
);
services.AddAssemblyOf<AbpTenantManagementHttpApiClientModule>();
}
}
}

@ -0,0 +1,22 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\common.props" />
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<AssemblyName>Volo.Abp.TenantManagement.HttpApi</AssemblyName>
<PackageId>Volo.Abp.TenantManagement.HttpApi</PackageId>
<AssetTargetFallback>$(AssetTargetFallback);portable-net45+win8+wp8+wpa81;</AssetTargetFallback>
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute>
<GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute>
<GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute>
<RootNamespace />
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Volo.Abp.TenantManagement.Application.Contracts\Volo.Abp.TenantManagement.Application.Contracts.csproj" />
<ProjectReference Include="..\..\..\abp\src\Volo.Abp.AspNetCore.Mvc\Volo.Abp.AspNetCore.Mvc.csproj" />
</ItemGroup>
</Project>

@ -0,0 +1,18 @@
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.AspNetCore.Mvc;
using Volo.Abp.Modularity;
namespace Volo.Abp.TenantManagement
{
[DependsOn(
typeof(AbpTenantManagementApplicationContractsModule),
typeof(AbpAspNetCoreMvcModule)
)]
public class AbpTenantManagementHttpApiModule : AbpModule
{
public override void ConfigureServices(IServiceCollection services)
{
services.AddAssemblyOf<AbpTenantManagementHttpApiModule>();
}
}
}

@ -0,0 +1,47 @@
using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services;
using Volo.Abp.DependencyInjection;
namespace Volo.Abp.TenantManagement
{
[Controller]
[RemoteService]
[Area("multi-tenancy")]
public class TenantController : ITenantAppService, ITransientDependency //TODO: Throws exception on validation if we inherit from Controller
{
private readonly ITenantAppService _service;
public TenantController(ITenantAppService service)
{
_service = service;
}
public virtual Task<TenantDto> GetAsync(Guid id)
{
return _service.GetAsync(id);
}
public virtual Task<PagedResultDto<TenantDto>> GetListAsync(GetTenantsInput input)
{
return _service.GetListAsync(input);
}
public virtual Task<TenantDto> CreateAsync(TenantCreateDto input)
{
return _service.CreateAsync(input);
}
public virtual Task<TenantDto> UpdateAsync(Guid id, TenantUpdateDto input)
{
return _service.UpdateAsync(id, input);
}
public virtual Task DeleteAsync(Guid id)
{
return _service.DeleteAsync(id);
}
}
}

@ -0,0 +1,22 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\common.props" />
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<AssemblyName>Volo.Abp.TenantManagement.MongoDB</AssemblyName>
<PackageId>Volo.Abp.TenantManagement.MongoDB</PackageId>
<AssetTargetFallback>$(AssetTargetFallback);portable-net45+win8+wp8+wpa81;</AssetTargetFallback>
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute>
<GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute>
<GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute>
<RootNamespace />
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Volo.Abp.TenantManagement.Domain\Volo.Abp.TenantManagement.Domain.csproj" />
<ProjectReference Include="..\..\..\abp\src\Volo.Abp.MongoDB\Volo.Abp.MongoDB.csproj" />
</ItemGroup>
</Project>

@ -0,0 +1,2 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:String x:Key="/Default/CodeInspection/CSharpLanguageProject/LanguageLevel/@EntryValue">CSharp71</s:String></wpf:ResourceDictionary>

@ -0,0 +1,23 @@
using MongoDB.Bson.Serialization;
using Volo.Abp.MongoDB;
using Volo.Abp.Threading;
namespace Volo.Abp.TenantManagement.MongoDb
{
public static class AbpTenantManagementBsonClassMap
{
private static readonly OneTimeRunner OneTimeRunner = new OneTimeRunner();
public static void Configure()
{
OneTimeRunner.Run(() =>
{
BsonClassMap.RegisterClassMap<Tenant>(map =>
{
map.AutoMap();
map.ConfigureExtraProperties();
});
});
}
}
}

@ -0,0 +1,24 @@
using System;
using Volo.Abp.MongoDB;
namespace Volo.Abp.TenantManagement.MongoDb
{
public static class AbpTenantManagementMongoDbContextExtensions
{
public static void ConfigureTenantManagement(
this IMongoModelBuilder builder,
Action<MongoModelBuilderConfigurationOptions> optionsAction = null)
{
Check.NotNull(builder, nameof(builder));
var options = new TenantManagementMongoModelBuilderConfigurationOptions();
optionsAction?.Invoke(options);
builder.Entity<Tenant>(b =>
{
b.CollectionName = options.CollectionPrefix + "Tenants";
});
}
}
}

@ -0,0 +1,27 @@
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.Modularity;
using Volo.Abp.MongoDB;
namespace Volo.Abp.TenantManagement.MongoDb
{
[DependsOn(
typeof(AbpTenantManagementDomainModule),
typeof(AbpMongoDbModule)
)]
public class AbpTenantManagementMongoDbModule : AbpModule
{
public override void ConfigureServices(IServiceCollection services)
{
AbpTenantManagementBsonClassMap.Configure();
services.AddMongoDbContext<TenantManagementMongoDbContext>(options =>
{
options.AddDefaultRepositories<ITenantManagementMongoDbContext>();
options.AddRepository<Tenant, MongoTenantRepository>();
});
services.AddAssemblyOf<AbpTenantManagementMongoDbModule>();
}
}
}

@ -0,0 +1,12 @@
using MongoDB.Driver;
using Volo.Abp.Data;
using Volo.Abp.MongoDB;
namespace Volo.Abp.TenantManagement.MongoDb
{
[ConnectionStringName("AbpTenantManagement")]
public interface ITenantManagementMongoDbContext : IAbpMongoDbContext
{
IMongoCollection<Tenant> Tenants { get; }
}
}

@ -0,0 +1,56 @@
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using MongoDB.Driver.Linq;
using System.Linq;
using System.Linq.Dynamic.Core;
using MongoDB.Driver;
using Volo.Abp.Domain.Repositories.MongoDB;
using Volo.Abp.MongoDB;
namespace Volo.Abp.TenantManagement.MongoDb
{
public class MongoTenantRepository : MongoDbRepository<ITenantManagementMongoDbContext, Tenant, Guid>, ITenantRepository
{
public MongoTenantRepository(IMongoDbContextProvider<ITenantManagementMongoDbContext> dbContextProvider)
: base(dbContextProvider)
{
}
public virtual async Task<Tenant> FindByNameAsync(
string name,
bool includeDetails = true,
CancellationToken cancellationToken = default)
{
return await GetMongoQueryable()
.FirstOrDefaultAsync(t => t.Name == name, cancellationToken);
}
public virtual async Task<long> GetCountAsync(CancellationToken cancellationToken = default)
{
return await GetMongoQueryable().LongCountAsync(cancellationToken);
}
public virtual async Task<List<Tenant>> GetListAsync(
string sorting = null,
int maxResultCount = int.MaxValue,
int skipCount = 0,
string filter = null,
bool includeDetails = false,
CancellationToken cancellationToken = default)
{
return await GetMongoQueryable()
.WhereIf<Tenant, IMongoQueryable<Tenant>>(
!filter.IsNullOrWhiteSpace(),
u =>
u.Name.Contains(filter)
)
.OrderBy(sorting ?? nameof(Tenant.Name))
.As<IMongoQueryable<Tenant>>()
.PageBy<Tenant, IMongoQueryable<Tenant>>(skipCount, maxResultCount)
.ToListAsync(cancellationToken);
}
}
}

@ -0,0 +1,24 @@
using MongoDB.Driver;
using Volo.Abp.Data;
using Volo.Abp.MongoDB;
namespace Volo.Abp.TenantManagement.MongoDb
{
[ConnectionStringName("AbpTenantManagement")]
public class TenantManagementMongoDbContext : AbpMongoDbContext, ITenantManagementMongoDbContext
{
public static string CollectionPrefix { get; set; } = AbpTenantManagementConsts.DefaultDbTablePrefix;
public IMongoCollection<Tenant> Tenants => Collection<Tenant>();
protected override void CreateModel(IMongoModelBuilder modelBuilder)
{
base.CreateModel(modelBuilder);
modelBuilder.ConfigureTenantManagement(options =>
{
options.CollectionPrefix = CollectionPrefix;
});
}
}
}

@ -0,0 +1,13 @@
using JetBrains.Annotations;
using Volo.Abp.MongoDB;
namespace Volo.Abp.TenantManagement.MongoDb
{
public class TenantManagementMongoModelBuilderConfigurationOptions : MongoModelBuilderConfigurationOptions
{
public TenantManagementMongoModelBuilderConfigurationOptions([NotNull] string tablePrefix = AbpTenantManagementConsts.DefaultDbTablePrefix)
: base(tablePrefix)
{
}
}
}

@ -0,0 +1,25 @@
using AutoMapper;
using Volo.Abp.TenantManagement.Web.Pages.TenantManagement.Tenants;
namespace Volo.Abp.TenantManagement.Web
{
public class AbpTenantManagementWebAutoMapperProfile : Profile
{
public AbpTenantManagementWebAutoMapperProfile()
{
CreateRoleMappings();
}
private void CreateRoleMappings()
{
//List
CreateMap<TenantDto, EditModalModel.TenantInfoModel>();
//CreateModal
CreateMap<CreateModalModel.TenantInfoModel, TenantCreateDto>();
//EditModal
CreateMap<EditModalModel.TenantInfoModel, TenantUpdateDto>();
}
}
}

@ -0,0 +1,67 @@
using Localization.Resources.AbpUi;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.AspNetCore.Mvc.Localization;
using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap;
using Volo.Abp.AutoMapper;
using Volo.Abp.Localization;
using Volo.Abp.Localization.Resources.AbpValidation;
using Volo.Abp.Modularity;
using Volo.Abp.TenantManagement.Localization;
using Volo.Abp.TenantManagement.Web.Navigation;
using Volo.Abp.UI.Navigation;
using Volo.Abp.VirtualFileSystem;
namespace Volo.Abp.TenantManagement.Web
{
[DependsOn(typeof(AbpTenantManagementHttpApiModule))]
[DependsOn(typeof(AbpAspNetCoreMvcUiBootstrapModule))]
[DependsOn(typeof(AbpAutoMapperModule))]
public class AbpTenantManagementWebModule : AbpModule
{
public override void PreConfigureServices(IServiceCollection services)
{
services.PreConfigure<AbpMvcDataAnnotationsLocalizationOptions>(options =>
{
options.AddAssemblyResource(typeof(AbpTenantManagementResource), typeof(AbpTenantManagementWebModule).Assembly);
});
}
public override void ConfigureServices(IServiceCollection services)
{
services.Configure<NavigationOptions>(options =>
{
options.MenuContributors.Add(new AbpTenantManagementWebMainMenuContributor());
});
services.Configure<VirtualFileSystemOptions>(options =>
{
options.FileSets.AddEmbedded<AbpTenantManagementWebModule>("Volo.Abp.TenantManagement.Web");
});
services.Configure<AbpLocalizationOptions>(options =>
{
options.Resources
.Get<AbpTenantManagementResource>()
.AddBaseTypes(
typeof(AbpValidationResource),
typeof(AbpUiResource)
).AddVirtualJson("/Localization/Resources/AbpTenantManagement/Web");
});
services.Configure<AbpAutoMapperOptions>(options =>
{
options.AddProfile<AbpTenantManagementWebAutoMapperProfile>(validate: true);
});
services.Configure<RazorPagesOptions>(options =>
{
options.Conventions.AuthorizePage("/TenantManagement/Tenants/Index", TenantManagementPermissions.Tenants.Default);
options.Conventions.AuthorizePage("/TenantManagement/Tenants/CreateModal", TenantManagementPermissions.Tenants.Create);
options.Conventions.AuthorizePage("/TenantManagement/Tenants/EditModal", TenantManagementPermissions.Tenants.Update);
});
services.AddAssemblyOf<AbpTenantManagementWebModule>();
}
}
}

@ -0,0 +1,10 @@
{
"culture": "en",
"texts": {
"Menu:TenantManagement": "Tenant management",
"Tenants": "Tenants",
"NewTenant": "New tenant",
"TenantName": "Tenant name",
"TenantDeletionConfirmationMessage": "Tenant '{0}' will be deleted. Do you confirm that?"
}
}

@ -0,0 +1,10 @@
{
"culture": "tr",
"texts": {
"Menu:TenantManagement": "Müşteri yönetimi",
"Tenants": "Müşteriler",
"NewTenant": "Yeni müşteri",
"TenantName": "Müşteri adı",
"TenantDeletionConfirmationMessage": "'{0}' isimli müşteri silinecektir. Onaylıyor musunuz?"
}
}

@ -0,0 +1,31 @@
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Localization;
using Volo.Abp.TenantManagement.Localization;
using Volo.Abp.UI.Navigation;
namespace Volo.Abp.TenantManagement.Web.Navigation
{
public class AbpTenantManagementWebMainMenuContributor : IMenuContributor
{
public async Task ConfigureMenuAsync(MenuConfigurationContext context)
{
if (context.Menu.Name != StandardMenus.Main)
{
return;
}
var authorizationService = context.ServiceProvider.GetRequiredService<IAuthorizationService>();
var l = context.ServiceProvider.GetRequiredService<IStringLocalizer<AbpTenantManagementResource>>();
var tenantManagementMenuItem = new ApplicationMenuItem("TenantManagement", l["Menu:TenantManagement"]);
context.Menu.AddItem(tenantManagementMenuItem);
if (await authorizationService.IsGrantedAsync(TenantManagementPermissions.Tenants.Default))
{
tenantManagementMenuItem.AddItem(new ApplicationMenuItem("Tenants", l["Tenants"], url: "/TenantManagement/Tenants"));
}
}
}
}

@ -0,0 +1,18 @@
@page
@using Microsoft.Extensions.Localization
@using Volo.Abp.TenantManagement.Localization
@using Volo.Abp.TenantManagement.Web.Pages.TenantManagement.Tenants
@model CreateModalModel
@inject IStringLocalizer<AbpTenantManagementResource> L
@{
Layout = null;
}
<form method="post" asp-page="/TenantManagement/Tenants/CreateModal">
<abp-modal>
<abp-modal-header title="@L["NewTenant"]"></abp-modal-header>
<abp-modal-body>
<abp-input asp-for="Tenant.Name" label="@L["TenantName"].Value" />
</abp-modal-body>
<abp-modal-footer></abp-modal-footer>
</abp-modal>
</form>

@ -0,0 +1,38 @@
using System.ComponentModel.DataAnnotations;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Volo.Abp.AspNetCore.Mvc.UI.RazorPages;
namespace Volo.Abp.TenantManagement.Web.Pages.TenantManagement.Tenants
{
public class CreateModalModel : AbpPageModel
{
[BindProperty]
public TenantInfoModel Tenant { get; set; }
private readonly ITenantAppService _tenantAppService;
public CreateModalModel(ITenantAppService tenantAppService)
{
_tenantAppService = tenantAppService;
}
public async Task<IActionResult> OnPostAsync()
{
ValidateModel();
var input = ObjectMapper.Map<TenantInfoModel, TenantCreateDto>(Tenant);
await _tenantAppService.CreateAsync(input);
return NoContent();
}
public class TenantInfoModel
{
[Required]
[StringLength(TenantConsts.MaxNameLength)]
[Display(Name = "TenantName")]
public string Name { get; set; }
}
}
}

@ -0,0 +1,19 @@
@page
@using Microsoft.AspNetCore.Mvc.Localization
@using Volo.Abp.TenantManagement.Localization
@using Volo.Abp.TenantManagement.Web.Pages.TenantManagement.Tenants
@model EditModalModel
@inject IHtmlLocalizer<AbpTenantManagementResource> L
@{
Layout = null;
}
<form method="post" asp-page="/TenantManagement/Tenants/EditModal" autocomplete="off">
<abp-modal>
<abp-modal-header title="@L["Edit"].Value"></abp-modal-header>
<abp-modal-body>
<input asp-for="Tenant.Id" />
<abp-input asp-for="Tenant.Name" label="@L["TenantName"].Value" />
</abp-modal-body>
<abp-modal-footer></abp-modal-footer>
</abp-modal>
</form>

@ -0,0 +1,49 @@
using System;
using System.ComponentModel.DataAnnotations;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Volo.Abp.AspNetCore.Mvc.UI.RazorPages;
namespace Volo.Abp.TenantManagement.Web.Pages.TenantManagement.Tenants
{
public class EditModalModel : AbpPageModel
{
[BindProperty]
public TenantInfoModel Tenant { get; set; }
private readonly ITenantAppService _tenantAppService;
public EditModalModel(ITenantAppService tenantAppService)
{
_tenantAppService = tenantAppService;
}
public async Task OnGetAsync(Guid id)
{
Tenant = ObjectMapper.Map<TenantDto, TenantInfoModel>(
await _tenantAppService.GetAsync(id)
);
}
public async Task<IActionResult> OnPostAsync()
{
ValidateModel();
var input = ObjectMapper.Map<TenantInfoModel, TenantUpdateDto>(Tenant);
await _tenantAppService.UpdateAsync(Tenant.Id, input);
return NoContent();
}
public class TenantInfoModel
{
[HiddenInput]
public Guid Id { get; set; }
[Required]
[StringLength(TenantConsts.MaxNameLength)]
[Display(Name = "TenantName")]
public string Name { get; set; }
}
}
}

@ -0,0 +1,34 @@
@page
@using Microsoft.AspNetCore.Mvc.Localization
@using Volo.Abp.TenantManagement.Localization
@using Volo.Abp.TenantManagement.Web.Pages.TenantManagement.Tenants
@model IndexModel
@inject IHtmlLocalizer<AbpTenantManagementResource> L
@section styles {
<link rel="stylesheet" type="text/css" href="~/modules/multi-tenancy/views/tenants/index.css" />
}
@section scripts {
<script type="text/javascript" src="~/modules/multi-tenancy/views/tenants/index.js"></script>
}
<abp-card id="TenantsWrapper">
<abp-card-header>
<abp-row>
<abp-column size-md="_6">
<h2>@L["Tenants"]</h2>
</abp-column>
<abp-column size-md="_6" class="text-right">
<abp-button button-type="Primary" name="CreateTenant" icon="plus" text="@L["NewTenant"].Value" />
</abp-column>
</abp-row>
</abp-card-header>
<abp-card-body>
<table class="table table-striped nowrap">
<thead>
<tr>
<th>@L["Actions"]</th>
<th>@L["TenantName"]</th>
</tr>
</thead>
</table>
</abp-card-body>
</abp-card>

@ -0,0 +1,12 @@
using Microsoft.AspNetCore.Mvc.RazorPages;
namespace Volo.Abp.TenantManagement.Web.Pages.TenantManagement.Tenants
{
public class IndexModel : PageModel
{
public void OnGet()
{
}
}
}

@ -0,0 +1,2 @@
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@addTagHelper *, Volo.Abp.AspNetCore.Mvc.UI.Bootstrap

@ -0,0 +1,27 @@
{
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:55673/",
"sslPort": 0
}
},
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"Volo.Abp.TenantManagement.Web": {
"commandName": "Project",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"applicationUrl": "http://localhost:55676/"
}
}
}

@ -0,0 +1,27 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<Import Project="..\..\common.props" />
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<AssemblyName>Volo.Abp.TenantManagement.Web</AssemblyName>
<PackageId>Volo.Abp.TenantManagement.Web</PackageId>
<IsPackable>true</IsPackable>
<AssetTargetFallback>$(AssetTargetFallback);portable-net45+win8+wp8+wpa81;</AssetTargetFallback>
<OutputType>Library</OutputType>
</PropertyGroup>
<ItemGroup>
<EmbeddedResource Include="wwwroot\**\*.*" />
<EmbeddedResource Include="Pages\**\*.cshtml" />
<EmbeddedResource Include="Localization\Resources\AbpTenantManagement\Web\*.json" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Volo.Abp.TenantManagement.HttpApi\Volo.Abp.TenantManagement.HttpApi.csproj" />
<ProjectReference Include="..\..\..\abp\src\Volo.Abp.AspNetCore.Mvc.UI.Bootstrap\Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.csproj" />
<ProjectReference Include="..\..\..\abp\src\Volo.Abp.AutoMapper\Volo.Abp.AutoMapper.csproj" />
</ItemGroup>
</Project>

@ -0,0 +1,6 @@
[
{
"outputFile": "wwwroot/modules/multi-tenancy/views/tenants/index.css",
"inputFile": "wwwroot/modules/multi-tenancy/views/tenants/index.less"
}
]

@ -0,0 +1,49 @@
{
"compilers": {
"less": {
"autoPrefix": "",
"cssComb": "none",
"ieCompat": true,
"strictMath": false,
"strictUnits": false,
"relativeUrls": true,
"rootPath": "",
"sourceMapRoot": "",
"sourceMapBasePath": "",
"sourceMap": false
},
"sass": {
"includePath": "",
"indentType": "space",
"indentWidth": 2,
"outputStyle": "nested",
"Precision": 5,
"relativeUrls": true,
"sourceMapRoot": "",
"sourceMap": false
},
"stylus": {
"sourceMap": false
},
"babel": {
"sourceMap": false
},
"coffeescript": {
"bare": false,
"runtimeMode": "node",
"sourceMap": false
}
},
"minifiers": {
"css": {
"enabled": true,
"termSemicolons": true,
"gzip": false
},
"javascript": {
"enabled": true,
"termSemicolons": true,
"gzip": false
}
}
}

@ -0,0 +1,21 @@
.dataTable {
width: 100% !important;
border-spacing: 0 !important;
}
.table td,
.table th {
padding: 8px 10px;
}
.dataTable tbody tr td button {
cursor: pointer;
}
.dataTable tbody tr td div.dropdown ul.dropdown-menu li {
cursor: pointer;
padding: 5px;
}
.dataTable tbody tr td div.dropdown ul.dropdown-menu li a {
display: block;
}
.dataTable tbody tr td div.dropdown ul.dropdown-menu li:hover {
background: #f4f5f8;
}

@ -0,0 +1,6 @@
'use strict';
$(function () {
$('#IdentityUsersTable').DataTable();
});

@ -0,0 +1 @@
"use strict";$(function(){$("#IdentityUsersTable").DataTable()});

@ -0,0 +1,79 @@
(function () {
var l = abp.localization.getResource('AbpTenantManagement');
var _tenantAppService = volo.abp.tenantManagement.tenant;
var _editModal = new abp.ModalManager(abp.appPath + 'TenantManagement/Tenants/EditModal');
var _createModal = new abp.ModalManager(abp.appPath + 'TenantManagement/Tenants/CreateModal');
$(function () {
var _$wrapper = $('#TenantsWrapper');
var _$table = _$wrapper.find('table');
var _dataTable = _$table.DataTable({
order: [[1, "asc"]],
ajax: abp.libs.datatables.createAjax(_tenantAppService.getList),
columnDefs: [
{
//TODO: Can we eleminate targets, data, orderable, autoWidth, defaultContent fields or make these values default
targets: 0,
data: null,
orderable: false,
autoWidth: false,
defaultContent: '',
rowAction: {
text: '<i class="fa fa-cog"></i> ' + l('Actions') + ' <span class="caret"></span>', //TODO: Add icon option and set text as only l('Actions')
items:
[
{
//TODO: Allow to add icon
text: l('Edit'),
visible: function () { //TODO: Allow visible to be a boolean for simple cases
return true;
},
action: function (data) {
_editModal.open({
id: data.record.id
});
}
},
{
text: l('Delete'),
visible: function () {
return true;
},
confirmMessage: function (data) { return l('TenantDeletionConfirmationMessage', data.record.name)},
action: function (data) {
_tenantAppService
.delete(data.record.id)
.then(function () {
_dataTable.ajax.reload();
});
}
}
]
}
},
{
targets: 1,
data: "name"
}
]
});
_createModal.onResult(function () {
_dataTable.ajax.reload();
});
_editModal.onResult(function () {
_dataTable.ajax.reload();
});
_$wrapper.find('button[name=CreateTenant]').click(function (e) {
e.preventDefault();
_createModal.open();
});
});
})();

@ -0,0 +1,39 @@
//TODO: This code is duplicated for other pages too. Unify them.
.dataTable {
width: 100% !important;
border-spacing: 0 !important;
}
.table td, .table th {
padding: 8px 10px;
}
.dataTable {
tbody {
tr {
td {
button {
cursor: pointer;
}
div.dropdown {
ul.dropdown-menu {
li {
cursor: pointer;
padding: 5px;
a {
display: block;
}
}
li:hover {
background: #f4f5f8;
}
}
}
}
}
}
}

@ -0,0 +1 @@
.dataTable{width:100% !important;border-spacing:0 !important;}.table td,.table th{padding:8px 10px;}.dataTable tbody tr td button{cursor:pointer;}.dataTable tbody tr td div.dropdown ul.dropdown-menu li{cursor:pointer;padding:5px;}.dataTable tbody tr td div.dropdown ul.dropdown-menu li a{display:block;}.dataTable tbody tr td div.dropdown ul.dropdown-menu li:hover{background:#f4f5f8;}

@ -0,0 +1,23 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp2.0</TargetFramework>
<AssemblyName>Volo.Abp.TenantManagement.Application.Tests</AssemblyName>
<PackageId>Volo.Abp.TenantManagement.Application.Tests</PackageId>
<GenerateRuntimeConfigurationFiles>true</GenerateRuntimeConfigurationFiles>
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute>
<GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute>
<GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute>
<RootNamespace />
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\Volo.Abp.TenantManagement.Application\Volo.Abp.TenantManagement.Application.csproj" />
<ProjectReference Include="..\Volo.Abp.TenantManagement.EntityFrameworkCore.Tests\Volo.Abp.TenantManagement.EntityFrameworkCore.Tests.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.7.2" />
</ItemGroup>
</Project>

@ -0,0 +1,24 @@
using System;
using Volo.Abp.TenantManagement.EntityFrameworkCore;
namespace Volo.Abp.TenantManagement
{
public abstract class AbpTenantManagementApplicationTestBase : TenantManagementTestBase<AbpTenantManagementApplicationTestModule>
{
protected virtual void UsingDbContext(Action<ITenantManagementDbContext> action)
{
using (var dbContext = GetRequiredService<ITenantManagementDbContext>())
{
action.Invoke(dbContext);
}
}
protected virtual T UsingDbContext<T>(Func<ITenantManagementDbContext, T> action)
{
using (var dbContext = GetRequiredService<ITenantManagementDbContext>())
{
return action.Invoke(dbContext);
}
}
}
}

@ -0,0 +1,19 @@
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.Modularity;
using Volo.Abp.TenantManagement.EntityFrameworkCore;
namespace Volo.Abp.TenantManagement
{
[DependsOn(
typeof(AbpTenantManagementApplicationModule),
typeof(AbpTenantManagementEntityFrameworkCoreTestModule))]
public class AbpTenantManagementApplicationTestModule : AbpModule
{
public override void ConfigureServices(IServiceCollection services)
{
services.AddAlwaysAllowPermissionChecker();
services.AddAssemblyOf<AbpTenantManagementApplicationTestModule>();
}
}
}

@ -0,0 +1,113 @@
using System;
using System.Linq;
using System.Threading.Tasks;
using Shouldly;
using Volo.Abp.UI;
using Xunit;
namespace Volo.Abp.TenantManagement
{
public class TenantAppService_Tests : AbpTenantManagementApplicationTestBase
{
private readonly ITenantAppService _tenantAppService;
public TenantAppService_Tests()
{
_tenantAppService = GetRequiredService<ITenantAppService>();
}
[Fact]
public async Task GetAsync()
{
var tenantInDb = UsingDbContext(dbContext => dbContext.Tenants.First());
var tenant = await _tenantAppService.GetAsync(tenantInDb.Id);
tenant.Name.ShouldBe(tenantInDb.Name);
}
[Fact]
public async Task GetListAsync()
{
var result = await _tenantAppService.GetListAsync(new GetTenantsInput());
result.TotalCount.ShouldBeGreaterThan(0);
result.Items.ShouldContain(t => t.Name == "acme");
result.Items.ShouldContain(t => t.Name == "volosoft");
}
[Fact]
public async Task GetListAsync_Filtered()
{
var result = await _tenantAppService.GetListAsync(new GetTenantsInput { Filter = "volo" });
result.TotalCount.ShouldBeGreaterThan(0);
result.Items.ShouldNotContain(t => t.Name == "acme");
result.Items.ShouldContain(t => t.Name == "volosoft");
}
[Fact]
public async Task GetListAsync_Sorted_Descending_By_Name()
{
var result = await _tenantAppService.GetListAsync(new GetTenantsInput { Sorting = "Name DESC" });
result.TotalCount.ShouldBeGreaterThan(0);
var tenants = result.Items.ToList();
tenants.ShouldContain(t => t.Name == "acme");
tenants.ShouldContain(t => t.Name == "volosoft");
tenants.FindIndex(t => t.Name == "acme").ShouldBeGreaterThan(tenants.FindIndex(t => t.Name == "volosoft"));
}
[Fact]
public async Task CreateAsync()
{
var tenancyName = Guid.NewGuid().ToString("N").ToLowerInvariant();
var tenant = await _tenantAppService.CreateAsync(new TenantCreateDto { Name = tenancyName });
tenant.Name.ShouldBe(tenancyName);
tenant.Id.ShouldNotBe(default(Guid));
}
[Fact]
public async Task CreateAsync_Should_Not_Allow_Duplicate_Names()
{
await Assert.ThrowsAsync<UserFriendlyException>(async () =>
{
await _tenantAppService.CreateAsync(new TenantCreateDto { Name = "acme" });
});
}
[Fact]
public async Task UpdateAsync()
{
var acme = UsingDbContext(dbContext => dbContext.Tenants.Single(t => t.Name == "acme"));
var result = await _tenantAppService.UpdateAsync(acme.Id, new TenantUpdateDto { Name = "acme-renamed" });
result.Id.ShouldBe(acme.Id);
result.Name.ShouldBe("acme-renamed");
var acmeUpdated = UsingDbContext(dbContext => dbContext.Tenants.Single(t => t.Id == acme.Id));
acmeUpdated.Name.ShouldBe("acme-renamed");
}
[Fact]
public async Task UpdateAsync_Should_Not_Allow_Duplicate_Names()
{
var acme = UsingDbContext(dbContext => dbContext.Tenants.Single(t => t.Name == "acme"));
await Assert.ThrowsAsync<UserFriendlyException>(async () =>
{
await _tenantAppService.UpdateAsync(acme.Id, new TenantUpdateDto { Name = "volosoft" });
});
}
[Fact]
public async Task DeleteAsync()
{
var acme = UsingDbContext(dbContext => dbContext.Tenants.Single(t => t.Name == "acme"));
await _tenantAppService.DeleteAsync(acme.Id);
UsingDbContext(dbContext =>
{
dbContext.Tenants.Any(t => t.Id == acme.Id).ShouldBeFalse();
});
}
}
}

@ -0,0 +1,25 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp2.0</TargetFramework>
<AssemblyName>Volo.Abp.TenantManagement.EntityFrameworkCore.Tests</AssemblyName>
<PackageId>Volo.Abp.TenantManagement.EntityFrameworkCore.Tests</PackageId>
<GenerateRuntimeConfigurationFiles>true</GenerateRuntimeConfigurationFiles>
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute>
<GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute>
<GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute>
<RootNamespace />
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Volo.Abp.TenantManagement.TestBase\Volo.Abp.TenantManagement.TestBase.csproj" />
<ProjectReference Include="..\..\src\Volo.Abp.TenantManagement.EntityFrameworkCore\Volo.Abp.TenantManagement.EntityFrameworkCore.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.7.2" />
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="2.1.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Proxies" Version="2.1.0" />
</ItemGroup>
</Project>

@ -0,0 +1,38 @@
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.EntityFrameworkCore;
using Volo.Abp.Modularity;
using Volo.Abp.Uow;
namespace Volo.Abp.TenantManagement.EntityFrameworkCore
{
[DependsOn(
typeof(AbpTenantManagementEntityFrameworkCoreModule),
typeof(AbpTenantManagementTestBaseModule)
)]
public class AbpTenantManagementEntityFrameworkCoreTestModule : AbpModule
{
public override void ConfigureServices(IServiceCollection services)
{
services.AddEntityFrameworkInMemoryDatabase();
var databaseName = Guid.NewGuid().ToString();
services.Configure<AbpDbContextOptions>(options =>
{
options.Configure(context =>
{
context.DbContextOptions.UseInMemoryDatabase(databaseName);
});
});
services.Configure<UnitOfWorkDefaultOptions>(options =>
{
options.TransactionBehavior = UnitOfWorkTransactionBehavior.Disabled; //EF in-memory database does not support transactions
});
services.AddAssemblyOf<AbpTenantManagementEntityFrameworkCoreTestModule>();
}
}
}

@ -0,0 +1,20 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.EntityFrameworkCore;
namespace Volo.Abp.TenantManagement.EntityFrameworkCore
{
public class LazyLoad_Tests : LazyLoad_Tests<AbpTenantManagementEntityFrameworkCoreTestModule>
{
protected override void BeforeAddApplication(IServiceCollection services)
{
services.Configure<AbpDbContextOptions>(options =>
{
options.PreConfigure<TenantManagementDbContext>(context =>
{
context.DbContextOptions.UseLazyLoadingProxies();
});
});
}
}
}

@ -0,0 +1,7 @@
namespace Volo.Abp.TenantManagement.EntityFrameworkCore
{
public class TenantRepository_Tests : TenantRepository_Tests<AbpTenantManagementEntityFrameworkCoreTestModule>
{
}
}

@ -0,0 +1,24 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp2.0</TargetFramework>
<AssemblyName>Volo.Abp.TenantManagement.MongoDB.Tests</AssemblyName>
<PackageId>Volo.Abp.TenantManagement.MongoDB.Tests</PackageId>
<GenerateRuntimeConfigurationFiles>true</GenerateRuntimeConfigurationFiles>
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute>
<GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute>
<GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute>
<RootNamespace />
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Volo.Abp.TenantManagement.TestBase\Volo.Abp.TenantManagement.TestBase.csproj" />
<ProjectReference Include="..\..\src\Volo.Abp.TenantManagement.MongoDB\Volo.Abp.TenantManagement.MongoDB.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.7.2" />
<PackageReference Include="Mongo2Go" Version="2.2.1" />
</ItemGroup>
</Project>

@ -0,0 +1,33 @@
using Microsoft.Extensions.DependencyInjection;
using Mongo2Go;
using Volo.Abp.Data;
using Volo.Abp.Modularity;
namespace Volo.Abp.TenantManagement.MongoDb
{
[DependsOn(
typeof(AbpTenantManagementMongoDbModule),
typeof(AbpTenantManagementTestBaseModule)
)]
public class AbpTenantManagementMongoDbTestModule : AbpModule
{
private MongoDbRunner _mongoDbRunner;
public override void ConfigureServices(IServiceCollection services)
{
_mongoDbRunner = MongoDbRunner.Start();
services.Configure<DbConnectionOptions>(options =>
{
options.ConnectionStrings.Default = _mongoDbRunner.ConnectionString;
});
services.AddAssemblyOf<AbpTenantManagementMongoDbTestModule>();
}
public override void OnApplicationShutdown(ApplicationShutdownContext context)
{
_mongoDbRunner.Dispose();
}
}
}

@ -0,0 +1,7 @@
namespace Volo.Abp.TenantManagement.MongoDb
{
public class TenantRepository_Tests : TenantRepository_Tests<AbpTenantManagementMongoDbTestModule>
{
}
}

@ -0,0 +1,29 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp2.0</TargetFramework>
<AssemblyName>Volo.Abp.TenantManagement.TestBase</AssemblyName>
<PackageId>Volo.Abp.TenantManagement.TestBase</PackageId>
<GenerateRuntimeConfigurationFiles>true</GenerateRuntimeConfigurationFiles>
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute>
<GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute>
<GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute>
<RootNamespace />
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\abp\src\Volo.Abp.Autofac\Volo.Abp.Autofac.csproj" />
<ProjectReference Include="..\..\..\abp\src\Volo.Abp.TestBase\Volo.Abp.TestBase.csproj" />
<ProjectReference Include="..\..\src\Volo.Abp.TenantManagement.Domain\Volo.Abp.TenantManagement.Domain.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.7.2" />
<PackageReference Include="NSubstitute" Version="3.1.0" />
<PackageReference Include="Shouldly" Version="3.0.0" />
<PackageReference Include="xunit" Version="2.3.1" />
<PackageReference Include="xunit.extensibility.execution" Version="2.3.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.3.1" />
</ItemGroup>
</Project>

@ -0,0 +1,34 @@
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.Autofac;
using Volo.Abp.Modularity;
namespace Volo.Abp.TenantManagement
{
[DependsOn(
typeof(AbpTenantManagementDomainModule),
typeof(AbpAutofacModule),
typeof(AbpTestBaseModule)
)]
public class AbpTenantManagementTestBaseModule : AbpModule
{
public override void ConfigureServices(IServiceCollection services)
{
services.AddAssemblyOf<AbpTenantManagementTestBaseModule>();
}
public override void OnApplicationInitialization(ApplicationInitializationContext context)
{
SeedTestData(context);
}
private static void SeedTestData(ApplicationInitializationContext context)
{
using (var scope = context.ServiceProvider.CreateScope())
{
scope.ServiceProvider
.GetRequiredService<AbpTenantManagementTestDataBuilder>()
.Build();
}
}
}
}

@ -0,0 +1,37 @@
using System.Threading.Tasks;
using Volo.Abp.Data;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Threading;
namespace Volo.Abp.TenantManagement
{
public class AbpTenantManagementTestDataBuilder : ITransientDependency
{
private readonly ITenantRepository _tenantRepository;
private readonly ITenantManager _tenantManager;
public AbpTenantManagementTestDataBuilder(
ITenantRepository tenantRepository,
ITenantManager tenantManager)
{
_tenantRepository = tenantRepository;
_tenantManager = tenantManager;
}
public void Build()
{
AsyncHelper.RunSync(AddTenantsAsync);
}
private async Task AddTenantsAsync()
{
var acme = await _tenantManager.CreateAsync("acme");
acme.ConnectionStrings.Add(new TenantConnectionString(acme.Id, ConnectionStrings.DefaultConnectionStringName, "DefaultConnString-Value"));
acme.ConnectionStrings.Add(new TenantConnectionString(acme.Id, "MyConnString", "MyConnString-Value"));
await _tenantRepository.InsertAsync(acme);
var volosoft = await _tenantManager.CreateAsync("volosoft");
await _tenantRepository.InsertAsync(volosoft);
}
}
}

@ -0,0 +1,33 @@
using System.Linq;
using System.Threading.Tasks;
using Shouldly;
using Volo.Abp.Modularity;
using Volo.Abp.Uow;
using Xunit;
namespace Volo.Abp.TenantManagement
{
public abstract class LazyLoad_Tests<TStartupModule> : TenantManagementTestBase<TStartupModule>
where TStartupModule : IAbpModule
{
public ITenantRepository TenantRepository { get; }
protected LazyLoad_Tests()
{
TenantRepository = GetRequiredService<ITenantRepository>();
}
[Fact]
public async Task Should_Lazy_Load_Tenant_Collections()
{
using (var uow = GetRequiredService<IUnitOfWorkManager>().Begin())
{
var role = await TenantRepository.FindByNameAsync("acme", includeDetails: false);
role.ConnectionStrings.ShouldNotBeNull();
role.ConnectionStrings.Any().ShouldBeTrue();
await uow.CompleteAsync();
}
}
}
}

@ -0,0 +1,13 @@
using Volo.Abp.Modularity;
namespace Volo.Abp.TenantManagement
{
public abstract class TenantManagementTestBase<TStartupModule> : AbpIntegratedTest<TStartupModule>
where TStartupModule : IAbpModule
{
protected override void SetAbpApplicationCreationOptions(AbpApplicationCreationOptions options)
{
options.UseAutofac();
}
}
}

@ -0,0 +1,73 @@
using System;
using System.Linq;
using System.Threading.Tasks;
using Shouldly;
using Volo.Abp.Modularity;
using Volo.Abp.Uow;
using Xunit;
namespace Volo.Abp.TenantManagement
{
public abstract class TenantRepository_Tests<TStartupModule> : TenantManagementTestBase<TStartupModule>
where TStartupModule : IAbpModule
{
public ITenantRepository TenantRepository { get; }
protected TenantRepository_Tests()
{
TenantRepository = GetRequiredService<ITenantRepository>();
}
[Fact]
public async Task FindByNameAsync()
{
var tenant = await TenantRepository.FindByNameAsync("acme");
tenant.ShouldNotBeNull();
tenant = await TenantRepository.FindByNameAsync("undefined-tenant");
tenant.ShouldBeNull();
tenant = await TenantRepository.FindByNameAsync("acme", includeDetails: true);
tenant.ShouldNotBeNull();
tenant.ConnectionStrings.Count.ShouldBeGreaterThanOrEqualTo(2);
}
[Fact]
public async Task FindAsync()
{
var tenantId = (await TenantRepository.FindByNameAsync("acme")).Id;
var tenant = await TenantRepository.FindAsync(tenantId);
tenant.ShouldNotBeNull();
tenant = await TenantRepository.FindAsync(Guid.NewGuid());
tenant.ShouldBeNull();
tenant = await TenantRepository.FindAsync(tenantId, includeDetails: true);
tenant.ShouldNotBeNull();
tenant.ConnectionStrings.Count.ShouldBeGreaterThanOrEqualTo(2);
}
[Fact]
public async Task GetCountAsync()
{
(await TenantRepository.GetCountAsync()).ShouldBeGreaterThan(0);
}
[Fact]
public async Task GetListAsync()
{
var tenants = await TenantRepository.GetListAsync();
tenants.ShouldContain(t => t.Name == "acme");
tenants.ShouldContain(t => t.Name == "volosoft");
}
[Fact]
public async Task Should_Eager_Load_Tenant_Collections()
{
var role = await TenantRepository.FindByNameAsync("acme");
role.ConnectionStrings.ShouldNotBeNull();
role.ConnectionStrings.Any().ShouldBeTrue();
}
}
}

@ -0,0 +1,2 @@
# abp-users
Users module for ABP framework.

@ -0,0 +1,60 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.27428.1
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.Users.Domain", "src\Volo.Abp.Users.Domain\Volo.Abp.Users.Domain.csproj", "{C4147378-B0A4-4308-840F-BD75D2EFC808}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.Users.EntityFrameworkCore", "src\Volo.Abp.Users.EntityFrameworkCore\Volo.Abp.Users.EntityFrameworkCore.csproj", "{F7F3F6E3-E564-49C5-8DF7-53FB390730A3}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.Users.Domain.Shared", "src\Volo.Abp.Users.Domain.Shared\Volo.Abp.Users.Domain.Shared.csproj", "{C18FFD6A-0BE2-4FB8-B953-895F7B9CB374}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{6DE713B1-3AD7-4388-8B07-CCBE7158EC6E}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{61BBB58B-4B6E-417D-A768-87B2D00BC7C3}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.Users.Abstractions", "src\Volo.Abp.Users.Abstractions\Volo.Abp.Users.Abstractions.csproj", "{3905D0E9-448D-43DE-8884-C60D0612AA04}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.Users.MongoDB", "src\Volo.Abp.Users.MongoDB\Volo.Abp.Users.MongoDB.csproj", "{70E89492-7D4E-418A-835F-35E70282E808}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{C4147378-B0A4-4308-840F-BD75D2EFC808}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C4147378-B0A4-4308-840F-BD75D2EFC808}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C4147378-B0A4-4308-840F-BD75D2EFC808}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C4147378-B0A4-4308-840F-BD75D2EFC808}.Release|Any CPU.Build.0 = Release|Any CPU
{F7F3F6E3-E564-49C5-8DF7-53FB390730A3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F7F3F6E3-E564-49C5-8DF7-53FB390730A3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F7F3F6E3-E564-49C5-8DF7-53FB390730A3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F7F3F6E3-E564-49C5-8DF7-53FB390730A3}.Release|Any CPU.Build.0 = Release|Any CPU
{C18FFD6A-0BE2-4FB8-B953-895F7B9CB374}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C18FFD6A-0BE2-4FB8-B953-895F7B9CB374}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C18FFD6A-0BE2-4FB8-B953-895F7B9CB374}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C18FFD6A-0BE2-4FB8-B953-895F7B9CB374}.Release|Any CPU.Build.0 = Release|Any CPU
{3905D0E9-448D-43DE-8884-C60D0612AA04}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3905D0E9-448D-43DE-8884-C60D0612AA04}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3905D0E9-448D-43DE-8884-C60D0612AA04}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3905D0E9-448D-43DE-8884-C60D0612AA04}.Release|Any CPU.Build.0 = Release|Any CPU
{70E89492-7D4E-418A-835F-35E70282E808}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{70E89492-7D4E-418A-835F-35E70282E808}.Debug|Any CPU.Build.0 = Debug|Any CPU
{70E89492-7D4E-418A-835F-35E70282E808}.Release|Any CPU.ActiveCfg = Release|Any CPU
{70E89492-7D4E-418A-835F-35E70282E808}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{C4147378-B0A4-4308-840F-BD75D2EFC808} = {6DE713B1-3AD7-4388-8B07-CCBE7158EC6E}
{F7F3F6E3-E564-49C5-8DF7-53FB390730A3} = {6DE713B1-3AD7-4388-8B07-CCBE7158EC6E}
{C18FFD6A-0BE2-4FB8-B953-895F7B9CB374} = {6DE713B1-3AD7-4388-8B07-CCBE7158EC6E}
{3905D0E9-448D-43DE-8884-C60D0612AA04} = {6DE713B1-3AD7-4388-8B07-CCBE7158EC6E}
{70E89492-7D4E-418A-835F-35E70282E808} = {6DE713B1-3AD7-4388-8B07-CCBE7158EC6E}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {E18777C8-72AB-4C08-BA72-885650BE70A9}
EndGlobalSection
EndGlobal

@ -0,0 +1,16 @@
<Project>
<PropertyGroup>
<LangVersion>latest</LangVersion>
<Version>0.3.0</Version>
<NoWarn>$(NoWarn);CS1591</NoWarn>
<PackageIconUrl>http://www.aspnetboilerplate.com/images/abp_nupkg.png</PackageIconUrl>
<PackageProjectUrl>http://abp.io</PackageProjectUrl>
<RepositoryType>git</RepositoryType>
<RepositoryUrl>https://github.com/volosoft/abp/</RepositoryUrl>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="SourceLink.Create.CommandLine" Version="2.8.1" PrivateAssets="All" />
</ItemGroup>
</Project>

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save