24 changed files with 494 additions and 148 deletions
@ -0,0 +1,36 @@ |
|||
@page |
|||
@using Microsoft.AspNetCore.Mvc.Localization |
|||
@using LINGYUN.Abp.MicroService.AuthServer.Pages.Abp.MultiTenancy |
|||
@using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Modal |
|||
@using Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy.Localization |
|||
@using static LINGYUN.Abp.MicroService.AuthServer.Pages.Abp.MultiTenancy.TenantSwitchModalModel |
|||
@model TenantSwitchModalModel |
|||
@inject IHtmlLocalizer<AbpUiMultiTenancyResource> L |
|||
@{ |
|||
Layout = null; |
|||
} |
|||
<abp-modal> |
|||
<abp-modal-header title="@L["SwitchTenant"].Value"></abp-modal-header> |
|||
<abp-modal-body> |
|||
<form method="post" id="tenantSwitchForm" asp-page="/Abp/MultiTenancy/TenantSwitchModal"> |
|||
@if (Model.Input is SelectTenantInfoModel selectModel && selectModel.AvailableTenants.Count > 0) |
|||
{ |
|||
<abp-select asp-for="Input.Name" label="@L["SwitchTenantHint"].Value" asp-items="selectModel.AvailableTenants" /> |
|||
} |
|||
else |
|||
{ |
|||
<abp-input asp-for="Input.Name" label="@L["SwitchTenantHint"].Value" /> |
|||
} |
|||
</form> |
|||
</abp-modal-body> |
|||
<abp-modal-footer buttons="@(AbpModalButtons.Cancel | AbpModalButtons.Save)"></abp-modal-footer> |
|||
</abp-modal> |
|||
|
|||
<script> |
|||
$(function() { |
|||
$('.modal-footer .btn-primary').click(function(e) { |
|||
e.preventDefault(); |
|||
$('#tenantSwitchForm').submit(); |
|||
}); |
|||
}); |
|||
</script> |
|||
@ -0,0 +1,118 @@ |
|||
using LINGYUN.Platform.Portal; |
|||
using Microsoft.AspNetCore.Mvc; |
|||
using Microsoft.AspNetCore.Mvc.Rendering; |
|||
using Microsoft.Extensions.Options; |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp; |
|||
using Volo.Abp.AspNetCore.MultiTenancy; |
|||
using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form; |
|||
using Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy.Localization; |
|||
using Volo.Abp.AspNetCore.Mvc.UI.RazorPages; |
|||
using Volo.Abp.MultiTenancy; |
|||
|
|||
#nullable enable |
|||
namespace LINGYUN.Abp.MicroService.AuthServer.Pages.Abp.MultiTenancy; |
|||
|
|||
public class TenantSwitchModalModel : AbpPageModel |
|||
{ |
|||
[BindProperty] |
|||
public TenantInfoModel Input { get; set; } = default!; |
|||
|
|||
public List<SelectListItem> AvailableTenants { get; set; } = new(); |
|||
|
|||
protected ITenantStore TenantStore { get; } |
|||
protected ITenantNormalizer TenantNormalizer { get; } |
|||
protected AbpAspNetCoreMultiTenancyOptions Options { get; } |
|||
protected IEnterpriseRepository EnterpriseRepository { get; } |
|||
public TenantSwitchModalModel( |
|||
ITenantStore tenantStore, |
|||
ITenantNormalizer tenantNormalizer, |
|||
IOptions<AbpAspNetCoreMultiTenancyOptions> options, |
|||
IEnterpriseRepository enterpriseRepository) |
|||
{ |
|||
TenantStore = tenantStore; |
|||
TenantNormalizer = tenantNormalizer; |
|||
Options = options.Value; |
|||
EnterpriseRepository = enterpriseRepository; |
|||
|
|||
LocalizationResourceType = typeof(AbpUiMultiTenancyResource); |
|||
} |
|||
|
|||
public async virtual Task OnGetAsync() |
|||
{ |
|||
await LoadAvailableTenants(); |
|||
if (AvailableTenants.Count > 0) |
|||
{ |
|||
Input = new SelectTenantInfoModel |
|||
{ |
|||
AvailableTenants = AvailableTenants |
|||
}; |
|||
} |
|||
else |
|||
{ |
|||
Input = new TenantInfoModel(); |
|||
} |
|||
|
|||
if (CurrentTenant.IsAvailable) |
|||
{ |
|||
var tenant = await TenantStore.FindAsync(CurrentTenant.GetId()); |
|||
Input.Name = tenant?.Name; |
|||
} |
|||
} |
|||
|
|||
public virtual async Task OnPostAsync() |
|||
{ |
|||
Guid? tenantId = null; |
|||
if (!Input.Name.IsNullOrEmpty()) |
|||
{ |
|||
var tenant = await TenantStore.FindAsync(TenantNormalizer.NormalizeName(Input.Name!)!); |
|||
if (tenant == null && Guid.TryParse(Input.Name, out var id)) |
|||
{ |
|||
tenant = await TenantStore.FindAsync(id); |
|||
} |
|||
if (tenant == null) |
|||
{ |
|||
throw new UserFriendlyException(L["GivenTenantIsNotExist", Input.Name!]); |
|||
} |
|||
|
|||
if (!tenant.IsActive) |
|||
{ |
|||
throw new UserFriendlyException(L["GivenTenantIsNotAvailable", Input.Name!]); |
|||
} |
|||
|
|||
tenantId = tenant.Id; |
|||
} |
|||
|
|||
AbpMultiTenancyCookieHelper.SetTenantCookie(HttpContext, tenantId, Options.TenantKey); |
|||
} |
|||
private async Task LoadAvailableTenants() |
|||
{ |
|||
var enterprises = await EnterpriseRepository.GetEnterprisesInTenantListAsync(maxResultCount: 25); |
|||
if (enterprises.Count > 0) |
|||
{ |
|||
AvailableTenants = enterprises |
|||
.Select(enterprise => |
|||
new SelectListItem( |
|||
enterprise.Name, enterprise.TenantId?.ToString())) |
|||
.Union([new SelectListItem("Default", "")]) |
|||
.ToList(); |
|||
} |
|||
} |
|||
|
|||
public class TenantInfoModel |
|||
{ |
|||
public virtual string? Name { get; set; } |
|||
} |
|||
|
|||
public class SelectTenantInfoModel : TenantInfoModel |
|||
{ |
|||
public List<SelectListItem> AvailableTenants { get; set; } = new(); |
|||
|
|||
[SelectItems(nameof(AvailableTenants))] |
|||
public override string? Name { get; set; } |
|||
} |
|||
} |
|||
#nullable disable |
|||
@ -0,0 +1,3 @@ |
|||
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers |
|||
@addTagHelper *, Volo.Abp.AspNetCore.Mvc.UI.Bootstrap |
|||
@addTagHelper *, Volo.Abp.AspNetCore.Mvc.UI.Bundling |
|||
@ -1,137 +0,0 @@ |
|||
using System; |
|||
using System.Diagnostics; |
|||
using System.Net; |
|||
using System.Security.Cryptography; |
|||
using System.Text; |
|||
|
|||
namespace LINGYUN.Abp.Identity.AspNetCore; |
|||
|
|||
/// <summary>
|
|||
/// 参考
|
|||
/// Microsoft: https://github.com/dotnet/dotnet/blob/main/src/aspnetcore/src/Identity/Extensions.Core/src/Rfc6238AuthenticationService.cs
|
|||
/// </summary>
|
|||
#nullable enable |
|||
internal class TotpService |
|||
{ |
|||
private static readonly TimeSpan _timestep = TimeSpan.FromMinutes(3); |
|||
private static readonly Encoding _encoding = new UTF8Encoding(false, true); |
|||
#if NETSTANDARD2_0 || NETFRAMEWORK
|
|||
private static readonly DateTime _unixEpoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); |
|||
#endif
|
|||
|
|||
internal static int ComputeTotp( |
|||
#if NET6_0_OR_GREATER
|
|||
byte[] key, |
|||
#else
|
|||
HashAlgorithm hashAlgorithm, |
|||
#endif
|
|||
ulong timestepNumber, |
|||
byte[]? modifierBytes) |
|||
{ |
|||
// # of 0's = length of pin
|
|||
const int Mod = 1000000; |
|||
|
|||
// See https://tools.ietf.org/html/rfc4226
|
|||
// We can add an optional modifier
|
|||
#if NET6_0_OR_GREATER
|
|||
Span<byte> timestepAsBytes = stackalloc byte[sizeof(long)]; |
|||
var res = BitConverter.TryWriteBytes(timestepAsBytes, IPAddress.HostToNetworkOrder((long)timestepNumber)); |
|||
Debug.Assert(res); |
|||
#else
|
|||
var timestepAsBytes = BitConverter.GetBytes(IPAddress.HostToNetworkOrder((long)timestepNumber)); |
|||
#endif
|
|||
|
|||
#if NET6_0_OR_GREATER
|
|||
Span<byte> modifierCombinedBytes = timestepAsBytes; |
|||
if (modifierBytes is not null) |
|||
{ |
|||
modifierCombinedBytes = ApplyModifier(timestepAsBytes, modifierBytes); |
|||
} |
|||
Span<byte> hash = stackalloc byte[HMACSHA1.HashSizeInBytes]; |
|||
res = HMACSHA1.TryHashData(key, modifierCombinedBytes, hash, out var written); |
|||
Debug.Assert(res); |
|||
Debug.Assert(written == hash.Length); |
|||
#else
|
|||
var hash = hashAlgorithm.ComputeHash(ApplyModifier(timestepAsBytes, modifierBytes)); |
|||
#endif
|
|||
|
|||
// Generate DT string
|
|||
var offset = hash[hash.Length - 1] & 0xf; |
|||
Debug.Assert(offset + 4 < hash.Length); |
|||
var binaryCode = (hash[offset] & 0x7f) << 24 |
|||
| (hash[offset + 1] & 0xff) << 16 |
|||
| (hash[offset + 2] & 0xff) << 8 |
|||
| (hash[offset + 3] & 0xff); |
|||
|
|||
return binaryCode % Mod; |
|||
} |
|||
|
|||
private static byte[] ApplyModifier(Span<byte> input, byte[] modifierBytes) |
|||
{ |
|||
var combined = new byte[checked(input.Length + modifierBytes.Length)]; |
|||
input.CopyTo(combined); |
|||
Buffer.BlockCopy(modifierBytes, 0, combined, input.Length, modifierBytes.Length); |
|||
return combined; |
|||
} |
|||
|
|||
// More info: https://tools.ietf.org/html/rfc6238#section-4
|
|||
private static ulong GetCurrentTimeStepNumber() |
|||
{ |
|||
#if NETSTANDARD2_0 || NETFRAMEWORK
|
|||
var delta = DateTime.UtcNow - _unixEpoch; |
|||
#else
|
|||
var delta = DateTimeOffset.UtcNow - DateTimeOffset.UnixEpoch; |
|||
#endif
|
|||
return (ulong)(delta.Ticks / _timestep.Ticks); |
|||
} |
|||
|
|||
public static int GenerateCode(byte[] securityToken, string? modifier = null) |
|||
{ |
|||
ArgumentNullException.ThrowIfNull(securityToken); |
|||
|
|||
// Allow a variance of no greater than 9 minutes in either direction
|
|||
var currentTimeStep = GetCurrentTimeStepNumber(); |
|||
|
|||
var modifierBytes = modifier is not null ? _encoding.GetBytes(modifier) : null; |
|||
#if NET6_0_OR_GREATER
|
|||
return ComputeTotp(securityToken, currentTimeStep, modifierBytes); |
|||
#else
|
|||
using (var hashAlgorithm = new HMACSHA1(securityToken)) |
|||
{ |
|||
return ComputeTotp(hashAlgorithm, currentTimeStep, modifierBytes); |
|||
} |
|||
#endif
|
|||
} |
|||
|
|||
public static bool ValidateCode(byte[] securityToken, int code, string? modifier = null) |
|||
{ |
|||
ArgumentNullException.ThrowIfNull(securityToken); |
|||
|
|||
// Allow a variance of no greater than 9 minutes in either direction
|
|||
var currentTimeStep = GetCurrentTimeStepNumber(); |
|||
|
|||
#if !NET6_0_OR_GREATER
|
|||
using (var hashAlgorithm = new HMACSHA1(securityToken)) |
|||
#endif
|
|||
{ |
|||
var modifierBytes = modifier is not null ? _encoding.GetBytes(modifier) : null; |
|||
for (var i = -2; i <= 2; i++) |
|||
{ |
|||
#if NET6_0_OR_GREATER
|
|||
var computedTotp = ComputeTotp(securityToken, (ulong)((long)currentTimeStep + i), modifierBytes); |
|||
#else
|
|||
var computedTotp = ComputeTotp(hashAlgorithm, (ulong)((long)currentTimeStep + i), modifierBytes); |
|||
#endif
|
|||
if (computedTotp == code) |
|||
{ |
|||
return true; |
|||
} |
|||
} |
|||
} |
|||
|
|||
// No match
|
|||
return false; |
|||
} |
|||
} |
|||
|
|||
#nullable disable |
|||
@ -0,0 +1,36 @@ |
|||
@page |
|||
@using Microsoft.AspNetCore.Mvc.Localization |
|||
@using LY.MicroService.Applications.Single.Pages.Abp.MultiTenancy |
|||
@using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Modal |
|||
@using Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy.Localization |
|||
@using static LY.MicroService.Applications.Single.Pages.Abp.MultiTenancy.TenantSwitchModalModel |
|||
@model TenantSwitchModalModel |
|||
@inject IHtmlLocalizer<AbpUiMultiTenancyResource> L |
|||
@{ |
|||
Layout = null; |
|||
} |
|||
<abp-modal> |
|||
<abp-modal-header title="@L["SwitchTenant"].Value"></abp-modal-header> |
|||
<abp-modal-body> |
|||
<form method="post" id="tenantSwitchForm" asp-page="/Abp/MultiTenancy/TenantSwitchModal"> |
|||
@if (Model.Input is SelectTenantInfoModel selectModel && selectModel.AvailableTenants.Count > 0) |
|||
{ |
|||
<abp-select asp-for="Input.Name" label="@L["SwitchTenantHint"].Value" asp-items="selectModel.AvailableTenants" /> |
|||
} |
|||
else |
|||
{ |
|||
<abp-input asp-for="Input.Name" label="@L["SwitchTenantHint"].Value" /> |
|||
} |
|||
</form> |
|||
</abp-modal-body> |
|||
<abp-modal-footer buttons="@(AbpModalButtons.Cancel | AbpModalButtons.Save)"></abp-modal-footer> |
|||
</abp-modal> |
|||
|
|||
<script> |
|||
$(function() { |
|||
$('.modal-footer .btn-primary').click(function(e) { |
|||
e.preventDefault(); |
|||
$('#tenantSwitchForm').submit(); |
|||
}); |
|||
}); |
|||
</script> |
|||
@ -0,0 +1,112 @@ |
|||
using LINGYUN.Platform.Portal; |
|||
using Microsoft.AspNetCore.Mvc; |
|||
using Microsoft.AspNetCore.Mvc.Rendering; |
|||
using Microsoft.Extensions.Options; |
|||
using Volo.Abp.AspNetCore.MultiTenancy; |
|||
using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form; |
|||
using Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy.Localization; |
|||
using Volo.Abp.AspNetCore.Mvc.UI.RazorPages; |
|||
|
|||
#nullable enable |
|||
namespace LY.MicroService.Applications.Single.Pages.Abp.MultiTenancy; |
|||
|
|||
public class TenantSwitchModalModel : AbpPageModel |
|||
{ |
|||
[BindProperty] |
|||
public TenantInfoModel Input { get; set; } = default!; |
|||
|
|||
public List<SelectListItem> AvailableTenants { get; set; } = new(); |
|||
|
|||
protected ITenantStore TenantStore { get; } |
|||
protected ITenantNormalizer TenantNormalizer { get; } |
|||
protected AbpAspNetCoreMultiTenancyOptions Options { get; } |
|||
protected IEnterpriseRepository EnterpriseRepository { get; } |
|||
public TenantSwitchModalModel( |
|||
ITenantStore tenantStore, |
|||
ITenantNormalizer tenantNormalizer, |
|||
IOptions<AbpAspNetCoreMultiTenancyOptions> options, |
|||
IEnterpriseRepository enterpriseRepository) |
|||
{ |
|||
TenantStore = tenantStore; |
|||
TenantNormalizer = tenantNormalizer; |
|||
Options = options.Value; |
|||
EnterpriseRepository = enterpriseRepository; |
|||
|
|||
LocalizationResourceType = typeof(AbpUiMultiTenancyResource); |
|||
} |
|||
|
|||
public async virtual Task OnGetAsync() |
|||
{ |
|||
await LoadAvailableTenants(); |
|||
if (AvailableTenants.Count > 0) |
|||
{ |
|||
Input = new SelectTenantInfoModel |
|||
{ |
|||
AvailableTenants = AvailableTenants |
|||
}; |
|||
} |
|||
else |
|||
{ |
|||
Input = new TenantInfoModel(); |
|||
} |
|||
|
|||
if (CurrentTenant.IsAvailable) |
|||
{ |
|||
var tenant = await TenantStore.FindAsync(CurrentTenant.GetId()); |
|||
Input.Name = tenant?.Name; |
|||
} |
|||
} |
|||
|
|||
public virtual async Task OnPostAsync() |
|||
{ |
|||
Guid? tenantId = null; |
|||
if (!Input.Name.IsNullOrEmpty()) |
|||
{ |
|||
var tenant = await TenantStore.FindAsync(TenantNormalizer.NormalizeName(Input.Name!)!); |
|||
if (tenant == null && Guid.TryParse(Input.Name, out var id)) |
|||
{ |
|||
tenant = await TenantStore.FindAsync(id); |
|||
} |
|||
if (tenant == null) |
|||
{ |
|||
throw new UserFriendlyException(L["GivenTenantIsNotExist", Input.Name!]); |
|||
} |
|||
|
|||
if (!tenant.IsActive) |
|||
{ |
|||
throw new UserFriendlyException(L["GivenTenantIsNotAvailable", Input.Name!]); |
|||
} |
|||
|
|||
tenantId = tenant.Id; |
|||
} |
|||
|
|||
AbpMultiTenancyCookieHelper.SetTenantCookie(HttpContext, tenantId, Options.TenantKey); |
|||
} |
|||
private async Task LoadAvailableTenants() |
|||
{ |
|||
var enterprises = await EnterpriseRepository.GetEnterprisesInTenantListAsync(maxResultCount: 25); |
|||
if (enterprises.Count > 0) |
|||
{ |
|||
AvailableTenants = enterprises |
|||
.Select(enterprise => |
|||
new SelectListItem( |
|||
enterprise.Name, enterprise.TenantId?.ToString())) |
|||
.Union([new SelectListItem("Default", "")]) |
|||
.ToList(); |
|||
} |
|||
} |
|||
|
|||
public class TenantInfoModel |
|||
{ |
|||
public virtual string? Name { get; set; } |
|||
} |
|||
|
|||
public class SelectTenantInfoModel : TenantInfoModel |
|||
{ |
|||
public List<SelectListItem> AvailableTenants { get; set; } = new(); |
|||
|
|||
[SelectItems(nameof(AvailableTenants))] |
|||
public override string? Name { get; set; } |
|||
} |
|||
} |
|||
#nullable disable |
|||
@ -0,0 +1,3 @@ |
|||
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers |
|||
@addTagHelper *, Volo.Abp.AspNetCore.Mvc.UI.Bootstrap |
|||
@addTagHelper *, Volo.Abp.AspNetCore.Mvc.UI.Bundling |
|||
@ -0,0 +1,36 @@ |
|||
@page |
|||
@using Microsoft.AspNetCore.Mvc.Localization |
|||
@using LY.MicroService.AuthServer.Pages.Abp.MultiTenancy |
|||
@using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Modal |
|||
@using Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy.Localization |
|||
@using static LY.MicroService.AuthServer.Pages.Abp.MultiTenancy.TenantSwitchModalModel |
|||
@model TenantSwitchModalModel |
|||
@inject IHtmlLocalizer<AbpUiMultiTenancyResource> L |
|||
@{ |
|||
Layout = null; |
|||
} |
|||
<abp-modal> |
|||
<abp-modal-header title="@L["SwitchTenant"].Value"></abp-modal-header> |
|||
<abp-modal-body> |
|||
<form method="post" id="tenantSwitchForm" asp-page="/Abp/MultiTenancy/TenantSwitchModal"> |
|||
@if (Model.Input is SelectTenantInfoModel selectModel && selectModel.AvailableTenants.Count > 0) |
|||
{ |
|||
<abp-select asp-for="Input.Name" label="@L["SwitchTenantHint"].Value" asp-items="selectModel.AvailableTenants" /> |
|||
} |
|||
else |
|||
{ |
|||
<abp-input asp-for="Input.Name" label="@L["SwitchTenantHint"].Value" /> |
|||
} |
|||
</form> |
|||
</abp-modal-body> |
|||
<abp-modal-footer buttons="@(AbpModalButtons.Cancel | AbpModalButtons.Save)"></abp-modal-footer> |
|||
</abp-modal> |
|||
|
|||
<script> |
|||
$(function() { |
|||
$('.modal-footer .btn-primary').click(function(e) { |
|||
e.preventDefault(); |
|||
$('#tenantSwitchForm').submit(); |
|||
}); |
|||
}); |
|||
</script> |
|||
@ -0,0 +1,118 @@ |
|||
using LINGYUN.Platform.Portal; |
|||
using Microsoft.AspNetCore.Mvc; |
|||
using Microsoft.AspNetCore.Mvc.Rendering; |
|||
using Microsoft.Extensions.Options; |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp; |
|||
using Volo.Abp.AspNetCore.MultiTenancy; |
|||
using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form; |
|||
using Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy.Localization; |
|||
using Volo.Abp.AspNetCore.Mvc.UI.RazorPages; |
|||
using Volo.Abp.MultiTenancy; |
|||
|
|||
#nullable enable |
|||
namespace LY.MicroService.AuthServer.Pages.Abp.MultiTenancy; |
|||
|
|||
public class TenantSwitchModalModel : AbpPageModel |
|||
{ |
|||
[BindProperty] |
|||
public TenantInfoModel Input { get; set; } = default!; |
|||
|
|||
public List<SelectListItem> AvailableTenants { get; set; } = new(); |
|||
|
|||
protected ITenantStore TenantStore { get; } |
|||
protected ITenantNormalizer TenantNormalizer { get; } |
|||
protected AbpAspNetCoreMultiTenancyOptions Options { get; } |
|||
protected IEnterpriseRepository EnterpriseRepository { get; } |
|||
public TenantSwitchModalModel( |
|||
ITenantStore tenantStore, |
|||
ITenantNormalizer tenantNormalizer, |
|||
IOptions<AbpAspNetCoreMultiTenancyOptions> options, |
|||
IEnterpriseRepository enterpriseRepository) |
|||
{ |
|||
TenantStore = tenantStore; |
|||
TenantNormalizer = tenantNormalizer; |
|||
Options = options.Value; |
|||
EnterpriseRepository = enterpriseRepository; |
|||
|
|||
LocalizationResourceType = typeof(AbpUiMultiTenancyResource); |
|||
} |
|||
|
|||
public async virtual Task OnGetAsync() |
|||
{ |
|||
await LoadAvailableTenants(); |
|||
if (AvailableTenants.Count > 0) |
|||
{ |
|||
Input = new SelectTenantInfoModel |
|||
{ |
|||
AvailableTenants = AvailableTenants |
|||
}; |
|||
} |
|||
else |
|||
{ |
|||
Input = new TenantInfoModel(); |
|||
} |
|||
|
|||
if (CurrentTenant.IsAvailable) |
|||
{ |
|||
var tenant = await TenantStore.FindAsync(CurrentTenant.GetId()); |
|||
Input.Name = tenant?.Name; |
|||
} |
|||
} |
|||
|
|||
public virtual async Task OnPostAsync() |
|||
{ |
|||
Guid? tenantId = null; |
|||
if (!Input.Name.IsNullOrEmpty()) |
|||
{ |
|||
var tenant = await TenantStore.FindAsync(TenantNormalizer.NormalizeName(Input.Name!)!); |
|||
if (tenant == null && Guid.TryParse(Input.Name, out var id)) |
|||
{ |
|||
tenant = await TenantStore.FindAsync(id); |
|||
} |
|||
if (tenant == null) |
|||
{ |
|||
throw new UserFriendlyException(L["GivenTenantIsNotExist", Input.Name!]); |
|||
} |
|||
|
|||
if (!tenant.IsActive) |
|||
{ |
|||
throw new UserFriendlyException(L["GivenTenantIsNotAvailable", Input.Name!]); |
|||
} |
|||
|
|||
tenantId = tenant.Id; |
|||
} |
|||
|
|||
AbpMultiTenancyCookieHelper.SetTenantCookie(HttpContext, tenantId, Options.TenantKey); |
|||
} |
|||
private async Task LoadAvailableTenants() |
|||
{ |
|||
var enterprises = await EnterpriseRepository.GetEnterprisesInTenantListAsync(maxResultCount: 25); |
|||
if (enterprises.Count > 0) |
|||
{ |
|||
AvailableTenants = enterprises |
|||
.Select(enterprise => |
|||
new SelectListItem( |
|||
enterprise.Name, enterprise.TenantId?.ToString())) |
|||
.Union([new SelectListItem("Default", "")]) |
|||
.ToList(); |
|||
} |
|||
} |
|||
|
|||
public class TenantInfoModel |
|||
{ |
|||
public virtual string? Name { get; set; } |
|||
} |
|||
|
|||
public class SelectTenantInfoModel : TenantInfoModel |
|||
{ |
|||
public List<SelectListItem> AvailableTenants { get; set; } = new(); |
|||
|
|||
[SelectItems(nameof(AvailableTenants))] |
|||
public override string? Name { get; set; } |
|||
} |
|||
} |
|||
#nullable disable |
|||
@ -0,0 +1,3 @@ |
|||
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers |
|||
@addTagHelper *, Volo.Abp.AspNetCore.Mvc.UI.Bootstrap |
|||
@addTagHelper *, Volo.Abp.AspNetCore.Mvc.UI.Bundling |
|||
Loading…
Reference in new issue