467 changed files with 34239 additions and 32737 deletions
@ -0,0 +1,28 @@ |
|||
using Microsoft.Extensions.DependencyInjection; |
|||
using Volo.Abp.Modularity; |
|||
using Volo.Abp.VirtualFileSystem; |
|||
using VoloAbpAccountWebIdentityServerModule = Volo.Abp.Account.Web.AbpAccountWebIdentityServerModule; |
|||
|
|||
namespace LINGYUN.Abp.Account.Web.IdentityServer; |
|||
|
|||
[DependsOn( |
|||
typeof(AbpAccountWebModule), |
|||
typeof(VoloAbpAccountWebIdentityServerModule))] |
|||
public class AbpAccountWebIdentityServerModule : AbpModule |
|||
{ |
|||
public override void PreConfigureServices(ServiceConfigurationContext context) |
|||
{ |
|||
PreConfigure<IMvcBuilder>(mvcBuilder => |
|||
{ |
|||
mvcBuilder.AddApplicationPartIfNotExists(typeof(AbpAccountWebIdentityServerModule).Assembly); |
|||
}); |
|||
} |
|||
|
|||
public override void ConfigureServices(ServiceConfigurationContext context) |
|||
{ |
|||
Configure<AbpVirtualFileSystemOptions>(options => |
|||
{ |
|||
options.FileSets.AddEmbedded<AbpAccountWebIdentityServerModule>(); |
|||
}); |
|||
} |
|||
} |
|||
@ -0,0 +1,3 @@ |
|||
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd"> |
|||
<ConfigureAwait ContinueOnCapturedContext="false" /> |
|||
</Weavers> |
|||
@ -0,0 +1,30 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> |
|||
<!-- This file was generated by Fody. Manual changes to this file will be lost when your project is rebuilt. --> |
|||
<xs:element name="Weavers"> |
|||
<xs:complexType> |
|||
<xs:all> |
|||
<xs:element name="ConfigureAwait" minOccurs="0" maxOccurs="1"> |
|||
<xs:complexType> |
|||
<xs:attribute name="ContinueOnCapturedContext" type="xs:boolean" /> |
|||
</xs:complexType> |
|||
</xs:element> |
|||
</xs:all> |
|||
<xs:attribute name="VerifyAssembly" type="xs:boolean"> |
|||
<xs:annotation> |
|||
<xs:documentation>'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.</xs:documentation> |
|||
</xs:annotation> |
|||
</xs:attribute> |
|||
<xs:attribute name="VerifyIgnoreCodes" type="xs:string"> |
|||
<xs:annotation> |
|||
<xs:documentation>A comma-separated list of error codes that can be safely ignored in assembly verification.</xs:documentation> |
|||
</xs:annotation> |
|||
</xs:attribute> |
|||
<xs:attribute name="GenerateXsd" type="xs:boolean"> |
|||
<xs:annotation> |
|||
<xs:documentation>'false' to turn off automatic generation of the XML Schema file.</xs:documentation> |
|||
</xs:annotation> |
|||
</xs:attribute> |
|||
</xs:complexType> |
|||
</xs:element> |
|||
</xs:schema> |
|||
@ -0,0 +1,26 @@ |
|||
<Project Sdk="Microsoft.NET.Sdk.Web"> |
|||
|
|||
<Import Project="..\..\..\..\configureawait.props" /> |
|||
<Import Project="..\..\..\..\common.props" /> |
|||
|
|||
<PropertyGroup> |
|||
<TargetFramework>net9.0</TargetFramework> |
|||
<AssemblyName>LINGYUN.Abp.Account.Web.IdentityServer</AssemblyName> |
|||
<PackageId>LINGYUN.Abp.Account.Web.IdentityServer</PackageId> |
|||
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute> |
|||
<GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute> |
|||
<GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute> |
|||
<RootNamespace>LINGYUN.Abp.Account.Web.IdentityServer</RootNamespace> |
|||
<OutputType>Library</OutputType> |
|||
</PropertyGroup> |
|||
|
|||
<ItemGroup> |
|||
<PackageReference Include="Volo.Abp.Account.Web.IdentityServer" /> |
|||
<PackageReference Include="Microsoft.Extensions.FileProviders.Embedded" /> |
|||
</ItemGroup> |
|||
|
|||
<ItemGroup> |
|||
<ProjectReference Include="..\LINGYUN.Abp.Account.Web\LINGYUN.Abp.Account.Web.csproj" /> |
|||
</ItemGroup> |
|||
|
|||
</Project> |
|||
@ -1,68 +1,68 @@ |
|||
using IdentityServer4.Services; |
|||
using IdentityServer4.Stores; |
|||
using Microsoft.AspNetCore.Authentication; |
|||
using Microsoft.AspNetCore.Mvc; |
|||
using Microsoft.Extensions.Options; |
|||
using System.Collections.Generic; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.Account.Web; |
|||
using Volo.Abp.Account.Web.Pages.Account; |
|||
using Volo.Abp.DependencyInjection; |
|||
using Volo.Abp.Identity; |
|||
using IdentityOptions = Microsoft.AspNetCore.Identity.IdentityOptions; |
|||
|
|||
namespace LY.MicroService.IdentityServer.Pages.Account |
|||
{ |
|||
/// <summary>
|
|||
/// 重写登录模型,实现双因素登录
|
|||
/// </summary>
|
|||
[Dependency(ReplaceServices = true)] |
|||
[ExposeServices(typeof(LoginModel), typeof(IdentityServerSupportedLoginModel))] |
|||
public class TwoFactorSupportedLoginModel : IdentityServerSupportedLoginModel |
|||
{ |
|||
public TwoFactorSupportedLoginModel( |
|||
IAuthenticationSchemeProvider schemeProvider, |
|||
IOptions<AbpAccountOptions> accountOptions, |
|||
IOptions<IdentityOptions> identityOptions, |
|||
IIdentityServerInteractionService interaction, |
|||
IdentityDynamicClaimsPrincipalContributorCache identityDynamicClaimsPrincipalContributorCache, |
|||
IClientStore clientStore, |
|||
IEventService identityServerEvents) |
|||
: base(schemeProvider, accountOptions, identityOptions, identityDynamicClaimsPrincipalContributorCache, interaction, clientStore, identityServerEvents) |
|||
{ |
|||
|
|||
} |
|||
|
|||
protected async override Task<List<ExternalProviderModel>> GetExternalProviders() |
|||
{ |
|||
var providers = await base.GetExternalProviders(); |
|||
|
|||
foreach (var provider in providers) |
|||
{ |
|||
var localizedDisplayName = L[provider.DisplayName]; |
|||
if (localizedDisplayName.ResourceNotFound) |
|||
{ |
|||
localizedDisplayName = L["AuthenticationScheme:" + provider.DisplayName]; |
|||
} |
|||
|
|||
if (!localizedDisplayName.ResourceNotFound) |
|||
{ |
|||
provider.DisplayName = localizedDisplayName.Value; |
|||
} |
|||
} |
|||
|
|||
return providers; |
|||
} |
|||
|
|||
protected override Task<IActionResult> TwoFactorLoginResultAsync() |
|||
{ |
|||
// 重定向双因素认证页面
|
|||
return Task.FromResult<IActionResult>(RedirectToPage("SendCode", new |
|||
{ |
|||
returnUrl = ReturnUrl, |
|||
returnUrlHash = ReturnUrlHash, |
|||
rememberMe = LoginInput.RememberMe |
|||
})); |
|||
} |
|||
} |
|||
} |
|||
using IdentityServer4.Services; |
|||
using IdentityServer4.Stores; |
|||
using Microsoft.AspNetCore.Authentication; |
|||
using Microsoft.AspNetCore.Mvc; |
|||
using Microsoft.Extensions.Options; |
|||
using System.Collections.Generic; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.Account.Web; |
|||
using Volo.Abp.Account.Web.Pages.Account; |
|||
using Volo.Abp.DependencyInjection; |
|||
using Volo.Abp.Identity; |
|||
using IdentityOptions = Microsoft.AspNetCore.Identity.IdentityOptions; |
|||
|
|||
namespace LINGYUN.Abp.Account.Web.IdentityServer.Pages.Account |
|||
{ |
|||
/// <summary>
|
|||
/// 重写登录模型,实现双因素登录
|
|||
/// </summary>
|
|||
[Dependency(ReplaceServices = true)] |
|||
[ExposeServices(typeof(LoginModel), typeof(IdentityServerSupportedLoginModel))] |
|||
public class TwoFactorSupportedLoginModel : IdentityServerSupportedLoginModel |
|||
{ |
|||
public TwoFactorSupportedLoginModel( |
|||
IAuthenticationSchemeProvider schemeProvider, |
|||
IOptions<AbpAccountOptions> accountOptions, |
|||
IOptions<IdentityOptions> identityOptions, |
|||
IIdentityServerInteractionService interaction, |
|||
IdentityDynamicClaimsPrincipalContributorCache identityDynamicClaimsPrincipalContributorCache, |
|||
IClientStore clientStore, |
|||
IEventService identityServerEvents) |
|||
: base(schemeProvider, accountOptions, identityOptions, identityDynamicClaimsPrincipalContributorCache, interaction, clientStore, identityServerEvents) |
|||
{ |
|||
|
|||
} |
|||
|
|||
protected async override Task<List<ExternalProviderModel>> GetExternalProviders() |
|||
{ |
|||
var providers = await base.GetExternalProviders(); |
|||
|
|||
foreach (var provider in providers) |
|||
{ |
|||
var localizedDisplayName = L[provider.DisplayName]; |
|||
if (localizedDisplayName.ResourceNotFound) |
|||
{ |
|||
localizedDisplayName = L["AuthenticationScheme:" + provider.DisplayName]; |
|||
} |
|||
|
|||
if (!localizedDisplayName.ResourceNotFound) |
|||
{ |
|||
provider.DisplayName = localizedDisplayName.Value; |
|||
} |
|||
} |
|||
|
|||
return providers; |
|||
} |
|||
|
|||
protected override Task<IActionResult> TwoFactorLoginResultAsync() |
|||
{ |
|||
// 重定向双因素认证页面
|
|||
return Task.FromResult<IActionResult>(RedirectToPage("SendCode", new |
|||
{ |
|||
returnUrl = ReturnUrl, |
|||
returnUrlHash = ReturnUrlHash, |
|||
rememberMe = LoginInput.RememberMe |
|||
})); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,4 @@ |
|||
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers |
|||
@addTagHelper *, Volo.Abp.AspNetCore.Mvc.UI |
|||
@addTagHelper *, Volo.Abp.AspNetCore.Mvc.UI.Bootstrap |
|||
@addTagHelper *, Volo.Abp.AspNetCore.Mvc.UI.Bundling |
|||
@ -0,0 +1,12 @@ |
|||
{ |
|||
"profiles": { |
|||
"LINGYUN.Abp.Account.Web.IdentityServer": { |
|||
"commandName": "Project", |
|||
"launchBrowser": true, |
|||
"environmentVariables": { |
|||
"ASPNETCORE_ENVIRONMENT": "Development" |
|||
}, |
|||
"applicationUrl": "https://localhost:56712;http://localhost:56713" |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,28 @@ |
|||
using Microsoft.Extensions.DependencyInjection; |
|||
using Volo.Abp.Modularity; |
|||
using Volo.Abp.VirtualFileSystem; |
|||
using VoloAbpAccountWebOpenIddictModule = Volo.Abp.Account.Web.AbpAccountWebOpenIddictModule; |
|||
|
|||
namespace LINGYUN.Abp.Account.Web.OpenIddict; |
|||
|
|||
[DependsOn( |
|||
typeof(AbpAccountWebModule), |
|||
typeof(VoloAbpAccountWebOpenIddictModule))] |
|||
public class AbpAccountWebOpenIddictModule : AbpModule |
|||
{ |
|||
public override void PreConfigureServices(ServiceConfigurationContext context) |
|||
{ |
|||
PreConfigure<IMvcBuilder>(mvcBuilder => |
|||
{ |
|||
mvcBuilder.AddApplicationPartIfNotExists(typeof(AbpAccountWebOpenIddictModule).Assembly); |
|||
}); |
|||
} |
|||
|
|||
public override void ConfigureServices(ServiceConfigurationContext context) |
|||
{ |
|||
Configure<AbpVirtualFileSystemOptions>(options => |
|||
{ |
|||
options.FileSets.AddEmbedded<AbpAccountWebOpenIddictModule>(); |
|||
}); |
|||
} |
|||
} |
|||
@ -0,0 +1,3 @@ |
|||
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd"> |
|||
<ConfigureAwait ContinueOnCapturedContext="false" /> |
|||
</Weavers> |
|||
@ -0,0 +1,30 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> |
|||
<!-- This file was generated by Fody. Manual changes to this file will be lost when your project is rebuilt. --> |
|||
<xs:element name="Weavers"> |
|||
<xs:complexType> |
|||
<xs:all> |
|||
<xs:element name="ConfigureAwait" minOccurs="0" maxOccurs="1"> |
|||
<xs:complexType> |
|||
<xs:attribute name="ContinueOnCapturedContext" type="xs:boolean" /> |
|||
</xs:complexType> |
|||
</xs:element> |
|||
</xs:all> |
|||
<xs:attribute name="VerifyAssembly" type="xs:boolean"> |
|||
<xs:annotation> |
|||
<xs:documentation>'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.</xs:documentation> |
|||
</xs:annotation> |
|||
</xs:attribute> |
|||
<xs:attribute name="VerifyIgnoreCodes" type="xs:string"> |
|||
<xs:annotation> |
|||
<xs:documentation>A comma-separated list of error codes that can be safely ignored in assembly verification.</xs:documentation> |
|||
</xs:annotation> |
|||
</xs:attribute> |
|||
<xs:attribute name="GenerateXsd" type="xs:boolean"> |
|||
<xs:annotation> |
|||
<xs:documentation>'false' to turn off automatic generation of the XML Schema file.</xs:documentation> |
|||
</xs:annotation> |
|||
</xs:attribute> |
|||
</xs:complexType> |
|||
</xs:element> |
|||
</xs:schema> |
|||
@ -0,0 +1,26 @@ |
|||
<Project Sdk="Microsoft.NET.Sdk.Web"> |
|||
|
|||
<Import Project="..\..\..\..\configureawait.props" /> |
|||
<Import Project="..\..\..\..\common.props" /> |
|||
|
|||
<PropertyGroup> |
|||
<TargetFramework>net9.0</TargetFramework> |
|||
<AssemblyName>LINGYUN.Abp.Account.Web.OpenIddict</AssemblyName> |
|||
<PackageId>LINGYUN.Abp.Account.Web.OpenIddict</PackageId> |
|||
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute> |
|||
<GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute> |
|||
<GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute> |
|||
<RootNamespace>LINGYUN.Abp.Account.Web.OpenIddict</RootNamespace> |
|||
<OutputType>Library</OutputType> |
|||
</PropertyGroup> |
|||
|
|||
<ItemGroup> |
|||
<PackageReference Include="Volo.Abp.Account.Web.OpenIddict" /> |
|||
<PackageReference Include="Microsoft.Extensions.FileProviders.Embedded" /> |
|||
</ItemGroup> |
|||
|
|||
<ItemGroup> |
|||
<ProjectReference Include="..\LINGYUN.Abp.Account.Web\LINGYUN.Abp.Account.Web.csproj" /> |
|||
</ItemGroup> |
|||
|
|||
</Project> |
|||
@ -1,70 +1,64 @@ |
|||
using Microsoft.AspNetCore.Authentication; |
|||
using Microsoft.AspNetCore.Mvc; |
|||
using Microsoft.Extensions.Options; |
|||
using OpenIddict.Server.AspNetCore; |
|||
using OpenIddict.Server; |
|||
using System.Collections.Generic; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.Account.Web; |
|||
using Volo.Abp.Account.Web.Pages.Account; |
|||
using Volo.Abp.DependencyInjection; |
|||
using Volo.Abp.Identity; |
|||
using Volo.Abp.OpenIddict; |
|||
using IdentityOptions = Microsoft.AspNetCore.Identity.IdentityOptions; |
|||
using System.Diagnostics; |
|||
using Volo.Abp.Account.Settings; |
|||
using Volo.Abp.Settings; |
|||
using LINGYUN.Abp.Identity.Session; |
|||
|
|||
namespace LY.MicroService.AuthServer.Pages.Account |
|||
{ |
|||
/// <summary>
|
|||
/// 重写登录模型,实现双因素登录
|
|||
/// </summary>
|
|||
[Dependency(ReplaceServices = true)] |
|||
[ExposeServices(typeof(LoginModel), typeof(OpenIddictSupportedLoginModel))] |
|||
public class TwoFactorSupportedLoginModel : OpenIddictSupportedLoginModel |
|||
{ |
|||
public TwoFactorSupportedLoginModel( |
|||
IAuthenticationSchemeProvider schemeProvider, |
|||
IOptions<AbpAccountOptions> accountOptions, |
|||
IOptions<IdentityOptions> identityOptions, |
|||
IdentityDynamicClaimsPrincipalContributorCache identityDynamicClaimsPrincipalContributorCache, |
|||
AbpOpenIddictRequestHelper openIddictRequestHelper) |
|||
: base(schemeProvider, accountOptions, identityOptions, identityDynamicClaimsPrincipalContributorCache, openIddictRequestHelper) |
|||
{ |
|||
} |
|||
|
|||
protected async override Task<List<ExternalProviderModel>> GetExternalProviders() |
|||
{ |
|||
var providers = await base.GetExternalProviders(); |
|||
|
|||
foreach (var provider in providers) |
|||
{ |
|||
var localizedDisplayName = L[provider.DisplayName]; |
|||
if (localizedDisplayName.ResourceNotFound) |
|||
{ |
|||
localizedDisplayName = L["AuthenticationScheme:" + provider.DisplayName]; |
|||
} |
|||
|
|||
if (!localizedDisplayName.ResourceNotFound) |
|||
{ |
|||
provider.DisplayName = localizedDisplayName.Value; |
|||
} |
|||
} |
|||
|
|||
return providers; |
|||
} |
|||
|
|||
protected override Task<IActionResult> TwoFactorLoginResultAsync() |
|||
{ |
|||
// 重定向双因素认证页面
|
|||
return Task.FromResult<IActionResult>(RedirectToPage("SendCode", new |
|||
{ |
|||
returnUrl = ReturnUrl, |
|||
returnUrlHash = ReturnUrlHash, |
|||
rememberMe = LoginInput.RememberMe |
|||
})); |
|||
} |
|||
} |
|||
} |
|||
using Microsoft.AspNetCore.Authentication; |
|||
using Microsoft.AspNetCore.Mvc; |
|||
using Microsoft.Extensions.Options; |
|||
using System.Collections.Generic; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.Account.Web; |
|||
using Volo.Abp.Account.Web.Pages.Account; |
|||
using Volo.Abp.DependencyInjection; |
|||
using Volo.Abp.Identity; |
|||
using Volo.Abp.OpenIddict; |
|||
using IdentityOptions = Microsoft.AspNetCore.Identity.IdentityOptions; |
|||
|
|||
namespace LINGYUN.Abp.Account.Web.OpenIddict.Pages.Account |
|||
{ |
|||
/// <summary>
|
|||
/// 重写登录模型,实现双因素登录
|
|||
/// </summary>
|
|||
[Dependency(ReplaceServices = true)] |
|||
[ExposeServices(typeof(LoginModel), typeof(OpenIddictSupportedLoginModel))] |
|||
public class TwoFactorSupportedLoginModel : OpenIddictSupportedLoginModel |
|||
{ |
|||
public TwoFactorSupportedLoginModel( |
|||
IAuthenticationSchemeProvider schemeProvider, |
|||
IOptions<AbpAccountOptions> accountOptions, |
|||
IOptions<IdentityOptions> identityOptions, |
|||
IdentityDynamicClaimsPrincipalContributorCache identityDynamicClaimsPrincipalContributorCache, |
|||
AbpOpenIddictRequestHelper openIddictRequestHelper) |
|||
: base(schemeProvider, accountOptions, identityOptions, identityDynamicClaimsPrincipalContributorCache, openIddictRequestHelper) |
|||
{ |
|||
} |
|||
|
|||
protected async override Task<List<ExternalProviderModel>> GetExternalProviders() |
|||
{ |
|||
var providers = await base.GetExternalProviders(); |
|||
|
|||
foreach (var provider in providers) |
|||
{ |
|||
var localizedDisplayName = L[provider.DisplayName]; |
|||
if (localizedDisplayName.ResourceNotFound) |
|||
{ |
|||
localizedDisplayName = L["AuthenticationScheme:" + provider.DisplayName]; |
|||
} |
|||
|
|||
if (!localizedDisplayName.ResourceNotFound) |
|||
{ |
|||
provider.DisplayName = localizedDisplayName.Value; |
|||
} |
|||
} |
|||
|
|||
return providers; |
|||
} |
|||
|
|||
protected override Task<IActionResult> TwoFactorLoginResultAsync() |
|||
{ |
|||
// 重定向双因素认证页面
|
|||
return Task.FromResult<IActionResult>(RedirectToPage("SendCode", new |
|||
{ |
|||
returnUrl = ReturnUrl, |
|||
returnUrlHash = ReturnUrlHash, |
|||
rememberMe = LoginInput.RememberMe |
|||
})); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,4 @@ |
|||
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers |
|||
@addTagHelper *, Volo.Abp.AspNetCore.Mvc.UI |
|||
@addTagHelper *, Volo.Abp.AspNetCore.Mvc.UI.Bootstrap |
|||
@addTagHelper *, Volo.Abp.AspNetCore.Mvc.UI.Bundling |
|||
@ -0,0 +1,12 @@ |
|||
{ |
|||
"profiles": { |
|||
"LINGYUN.Abp.Account.Web.OpenIddict": { |
|||
"commandName": "Project", |
|||
"launchBrowser": true, |
|||
"environmentVariables": { |
|||
"ASPNETCORE_ENVIRONMENT": "Development" |
|||
}, |
|||
"applicationUrl": "https://localhost:65279;http://localhost:65280" |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,89 @@ |
|||
using LINGYUN.Abp.Account.Emailing; |
|||
using LINGYUN.Abp.Account.Web.ProfileManagement; |
|||
using LINGYUN.Abp.Identity; |
|||
using Microsoft.Extensions.DependencyInjection; |
|||
using Volo.Abp.Account.Localization; |
|||
using Volo.Abp.Account.Web.Pages.Account; |
|||
using Volo.Abp.Account.Web.ProfileManagement; |
|||
using Volo.Abp.AspNetCore.Mvc.Localization; |
|||
using Volo.Abp.AspNetCore.Mvc.UI.Bundling; |
|||
using Volo.Abp.AspNetCore.Mvc.UI.Packages.QRCode; |
|||
using Volo.Abp.AutoMapper; |
|||
using Volo.Abp.Modularity; |
|||
using Volo.Abp.Sms; |
|||
using Volo.Abp.VirtualFileSystem; |
|||
using VoloAbpAccountWebModule = Volo.Abp.Account.Web.AbpAccountWebModule; |
|||
|
|||
namespace LINGYUN.Abp.Account.Web; |
|||
|
|||
[DependsOn( |
|||
typeof(AbpSmsModule), |
|||
typeof(VoloAbpAccountWebModule), |
|||
typeof(AbpIdentityDomainModule), |
|||
typeof(AbpAccountEmailingModule), |
|||
typeof(AbpAccountApplicationContractsModule))] |
|||
public class AbpAccountWebModule : AbpModule |
|||
{ |
|||
public override void PreConfigureServices(ServiceConfigurationContext context) |
|||
{ |
|||
context.Services.PreConfigure<AbpMvcDataAnnotationsLocalizationOptions>(options => |
|||
{ |
|||
options.AddAssemblyResource(typeof(AccountResource), typeof(AbpAccountWebModule).Assembly); |
|||
}); |
|||
|
|||
PreConfigure<IMvcBuilder>(mvcBuilder => |
|||
{ |
|||
mvcBuilder.AddApplicationPartIfNotExists(typeof(AbpAccountWebModule).Assembly); |
|||
}); |
|||
} |
|||
|
|||
public override void ConfigureServices(ServiceConfigurationContext context) |
|||
{ |
|||
Configure<AbpVirtualFileSystemOptions>(options => |
|||
{ |
|||
options.FileSets.AddEmbedded<AbpAccountWebModule>(); |
|||
}); |
|||
|
|||
ConfigureProfileManagementPage(); |
|||
|
|||
context.Services.AddAutoMapperObjectMapper<AbpAccountWebModule>(); |
|||
Configure<AbpAutoMapperOptions>(options => |
|||
{ |
|||
options.AddMaps<AbpAccountWebModule>(validate: true); |
|||
}); |
|||
} |
|||
|
|||
private void ConfigureProfileManagementPage() |
|||
{ |
|||
Configure<ProfileManagementPageOptions>(options => |
|||
{ |
|||
options.Contributors.Add(new SessionManagementPageContributor()); |
|||
}); |
|||
|
|||
Configure<AbpBundlingOptions>(options => |
|||
{ |
|||
options.ScriptBundles |
|||
.Configure(typeof(ManageModel).FullName, |
|||
configuration => |
|||
{ |
|||
// Client Proxies
|
|||
configuration.AddFiles("/client-proxies/account-proxy.js"); |
|||
|
|||
// Session
|
|||
configuration.AddFiles("/Pages/Account/Components/ProfileManagementGroup/Session/Index.js"); |
|||
|
|||
// Authenticator
|
|||
configuration.AddFiles("/Pages/Account/Components/ProfileManagementGroup/Authenticator/Index.js"); |
|||
|
|||
// SecurityLog
|
|||
configuration.AddFiles("/Pages/Account/Components/ProfileManagementGroup/SecurityLog/Index.js"); |
|||
|
|||
// TwoFactor
|
|||
configuration.AddFiles("/Pages/Account/Components/ProfileManagementGroup/TwoFactor/Default.js"); |
|||
|
|||
// QrCode
|
|||
configuration.AddContributors(typeof(QRCodeScriptContributor)); |
|||
}); |
|||
}); |
|||
} |
|||
} |
|||
@ -0,0 +1,3 @@ |
|||
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd"> |
|||
<ConfigureAwait ContinueOnCapturedContext="false" /> |
|||
</Weavers> |
|||
@ -0,0 +1,30 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> |
|||
<!-- This file was generated by Fody. Manual changes to this file will be lost when your project is rebuilt. --> |
|||
<xs:element name="Weavers"> |
|||
<xs:complexType> |
|||
<xs:all> |
|||
<xs:element name="ConfigureAwait" minOccurs="0" maxOccurs="1"> |
|||
<xs:complexType> |
|||
<xs:attribute name="ContinueOnCapturedContext" type="xs:boolean" /> |
|||
</xs:complexType> |
|||
</xs:element> |
|||
</xs:all> |
|||
<xs:attribute name="VerifyAssembly" type="xs:boolean"> |
|||
<xs:annotation> |
|||
<xs:documentation>'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.</xs:documentation> |
|||
</xs:annotation> |
|||
</xs:attribute> |
|||
<xs:attribute name="VerifyIgnoreCodes" type="xs:string"> |
|||
<xs:annotation> |
|||
<xs:documentation>A comma-separated list of error codes that can be safely ignored in assembly verification.</xs:documentation> |
|||
</xs:annotation> |
|||
</xs:attribute> |
|||
<xs:attribute name="GenerateXsd" type="xs:boolean"> |
|||
<xs:annotation> |
|||
<xs:documentation>'false' to turn off automatic generation of the XML Schema file.</xs:documentation> |
|||
</xs:annotation> |
|||
</xs:attribute> |
|||
</xs:complexType> |
|||
</xs:element> |
|||
</xs:schema> |
|||
@ -0,0 +1,50 @@ |
|||
<Project Sdk="Microsoft.NET.Sdk.Web"> |
|||
|
|||
<Import Project="..\..\..\..\configureawait.props" /> |
|||
<Import Project="..\..\..\..\common.props" /> |
|||
|
|||
<PropertyGroup> |
|||
<TargetFramework>net9.0</TargetFramework> |
|||
<AssemblyName>LINGYUN.Abp.Account.Web</AssemblyName> |
|||
<PackageId>LINGYUN.Abp.Account.Web</PackageId> |
|||
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute> |
|||
<GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute> |
|||
<GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute> |
|||
<GenerateEmbeddedFilesManifest>true</GenerateEmbeddedFilesManifest> |
|||
<RootNamespace>LINGYUN.Abp.Account.Web</RootNamespace> |
|||
<IsPackable>true</IsPackable> |
|||
<OutputType>Library</OutputType> |
|||
</PropertyGroup> |
|||
|
|||
<ItemGroup> |
|||
<EmbeddedResource Include="Modules\**\*.js" /> |
|||
<EmbeddedResource Include="Modules\**\*.css" /> |
|||
<EmbeddedResource Include="Pages\**\*.js" /> |
|||
<EmbeddedResource Include="Pages\**\*.css" /> |
|||
<EmbeddedResource Include="Components\**\*.js" /> |
|||
<EmbeddedResource Include="Components\**\*.css" /> |
|||
<EmbeddedResource Include="wwwroot\**\*.js" /> |
|||
<EmbeddedResource Include="wwwroot\**\*.css" /> |
|||
<Content Remove="Modules\**\*.js" /> |
|||
<Content Remove="Modules\**\*.css" /> |
|||
<Content Remove="Pages\**\*.js" /> |
|||
<Content Remove="Pages\**\*.css" /> |
|||
<Content Remove="Components\**\*.js" /> |
|||
<Content Remove="Components\**\*.css" /> |
|||
<Content Remove="wwwroot\**\*.js" /> |
|||
<Content Remove="wwwroot\**\*.css" /> |
|||
</ItemGroup> |
|||
|
|||
<ItemGroup> |
|||
<PackageReference Include="Volo.Abp.Sms" /> |
|||
<PackageReference Include="Volo.Abp.Account.Web" /> |
|||
<PackageReference Include="Microsoft.Extensions.FileProviders.Embedded" /> |
|||
</ItemGroup> |
|||
|
|||
<ItemGroup> |
|||
<ProjectReference Include="..\..\identity\LINGYUN.Abp.Identity.Domain\LINGYUN.Abp.Identity.Domain.csproj" /> |
|||
<ProjectReference Include="..\LINGYUN.Abp.Account.Application.Contracts\LINGYUN.Abp.Account.Application.Contracts.csproj" /> |
|||
<ProjectReference Include="..\LINGYUN.Abp.Account.Emailing\LINGYUN.Abp.Account.Emailing.csproj" /> |
|||
</ItemGroup> |
|||
|
|||
</Project> |
|||
@ -0,0 +1,44 @@ |
|||
using Microsoft.AspNetCore.Mvc; |
|||
using System.ComponentModel.DataAnnotations; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.AspNetCore.Mvc; |
|||
|
|||
namespace LINGYUN.Abp.Account.Web.Pages.Account.Components.ProfileManagementGroup.Authenticator; |
|||
|
|||
public class AccountProfileAuthenticatorManagementGroupViewComponent : AbpViewComponent |
|||
{ |
|||
protected IMyProfileAppService ProfileAppService { get; } |
|||
|
|||
public AccountProfileAuthenticatorManagementGroupViewComponent( |
|||
IMyProfileAppService profileAppService) |
|||
{ |
|||
ProfileAppService = profileAppService; |
|||
} |
|||
|
|||
public async virtual Task<IViewComponentResult> InvokeAsync() |
|||
{ |
|||
var authenticatorDto = await ProfileAppService.GetAuthenticatorAsync(); |
|||
|
|||
var model = new AuthenticatorModel |
|||
{ |
|||
AuthenticatorUri = authenticatorDto.AuthenticatorUri, |
|||
IsAuthenticated = authenticatorDto.IsAuthenticated, |
|||
SharedKey = authenticatorDto.SharedKey, |
|||
}; |
|||
|
|||
return View("~/Pages/Account/Components/ProfileManagementGroup/Authenticator/Index.cshtml", model); |
|||
} |
|||
|
|||
public class AuthenticatorModel |
|||
{ |
|||
public bool IsAuthenticated { get; set; } |
|||
|
|||
public string SharedKey { get; set; } |
|||
|
|||
public string AuthenticatorUri { get; set; } |
|||
|
|||
[Required] |
|||
[StringLength(6)] |
|||
public string AuthenticatorCode { get; set; } |
|||
} |
|||
} |
|||
@ -0,0 +1,17 @@ |
|||
@using Microsoft.AspNetCore.Mvc.Localization |
|||
@using Volo.Abp.Account.Localization |
|||
@using Volo.Abp.Localization |
|||
|
|||
@inject IHtmlLocalizer<AccountResource> L |
|||
|
|||
@model LINGYUN.Abp.Account.Web.Pages.Account.Components.ProfileManagementGroup.Authenticator.AccountProfileAuthenticatorManagementGroupViewComponent.AuthenticatorModel |
|||
|
|||
<abp-card> |
|||
<abp-card-header> |
|||
<abp-row> |
|||
<abp-column size-md="_6"> |
|||
<abp-card-title>@L["Authenticator"]</abp-card-title> |
|||
</abp-column> |
|||
</abp-row> |
|||
</abp-card-header> |
|||
</abp-card> |
|||
@ -0,0 +1,5 @@ |
|||
$(function () { |
|||
var ul = abp.localization.getResource('AbpUi'); |
|||
|
|||
abp.log.warn('Please implement your own authentication procedure!'); |
|||
}); |
|||
@ -0,0 +1,19 @@ |
|||
using Microsoft.AspNetCore.Mvc; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.AspNetCore.Mvc; |
|||
|
|||
namespace LINGYUN.Abp.Account.Web.Pages.Account.Components.ProfileManagementGroup.SecurityLog; |
|||
|
|||
public class AccountProfileSecurityLogManagementGroupViewComponent : AbpViewComponent |
|||
{ |
|||
public AccountProfileSecurityLogManagementGroupViewComponent() |
|||
{ |
|||
} |
|||
|
|||
public async virtual Task<IViewComponentResult> InvokeAsync() |
|||
{ |
|||
await Task.CompletedTask; |
|||
|
|||
return View("~/Pages/Account/Components/ProfileManagementGroup/SecurityLog/Index.cshtml"); |
|||
} |
|||
} |
|||
@ -0,0 +1,22 @@ |
|||
@using Microsoft.AspNetCore.Mvc.Localization |
|||
@using Volo.Abp.Account.Localization |
|||
@using Volo.Abp.Localization |
|||
|
|||
@inject IHtmlLocalizer<AccountResource> L |
|||
|
|||
@section scripts { |
|||
<abp-script src="/Pages/Account/Components/ProfileManagementGroup/SecurityLog/Index.js" /> |
|||
} |
|||
|
|||
<abp-card> |
|||
<abp-card-header> |
|||
<abp-row> |
|||
<abp-column size-md="_6"> |
|||
<abp-card-title>@L["SecurityLog"]</abp-card-title> |
|||
</abp-column> |
|||
</abp-row> |
|||
</abp-card-header> |
|||
<abp-card-body> |
|||
<abp-table striped-rows="true" id="SecurityLogTable"></abp-table> |
|||
</abp-card-body> |
|||
</abp-card> |
|||
@ -0,0 +1,73 @@ |
|||
$(function () { |
|||
var ul = abp.localization.getResource('AbpUi'); |
|||
var l = abp.localization.getResource('AbpAuditLogging'); |
|||
var dataTable = $('#SecurityLogTable').DataTable( |
|||
abp.libs.datatables.normalizeConfiguration({ |
|||
serverSide: true, |
|||
paging: true, |
|||
searching: false, |
|||
scrollX: true, |
|||
ajax: abp.libs.datatables.createAjax(labp.account.mySecurityLog.getList), |
|||
columnDefs: [ |
|||
{ |
|||
title: ul('Actions'), |
|||
rowAction: { |
|||
items: |
|||
[ |
|||
{ |
|||
text: ul('Delete'), |
|||
confirmMessage: function () { |
|||
return ul('ItemWillBeDeletedMessage'); |
|||
}, |
|||
action: function (data) { |
|||
labp.account.mySecurityLog |
|||
.delete(data.record.id) |
|||
.then(function () { |
|||
abp.notify.info( |
|||
ul('DeletedSuccessfully') |
|||
); |
|||
dataTable.ajax.reload(); |
|||
}); |
|||
} |
|||
} |
|||
] |
|||
} |
|||
}, |
|||
{ |
|||
title: l('DisplayName:CreationTime'), |
|||
data: "creationTime", |
|||
render: function (data) { |
|||
return luxon |
|||
.DateTime |
|||
.fromISO(data, { |
|||
locale: abp.localization.currentCulture.name |
|||
}).toLocaleString(luxon.DateTime.DATETIME_FULL_WITH_SECONDS); |
|||
} |
|||
}, |
|||
{ |
|||
title: l('DisplayName:Identity'), |
|||
data: "identity" |
|||
}, |
|||
{ |
|||
title: l('DisplayName:ClientId'), |
|||
data: "clientId" |
|||
}, |
|||
{ |
|||
title: l('DisplayName:ClientIpAddress'), |
|||
data: "clientIpAddress" |
|||
}, |
|||
{ |
|||
title: l('DisplayName:ApplicationName'), |
|||
data: "applicationName" |
|||
}, |
|||
{ |
|||
title: l('DisplayName:Actions'), |
|||
data: "action" |
|||
}, |
|||
{ |
|||
title: l('DisplayName:BrowserInfo'), |
|||
data: "browserInfo" |
|||
}] |
|||
}) |
|||
); |
|||
}); |
|||
@ -0,0 +1,19 @@ |
|||
using Microsoft.AspNetCore.Mvc; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.AspNetCore.Mvc; |
|||
|
|||
namespace LINGYUN.Abp.Account.Web.Pages.Account.Components.ProfileManagementGroup.Session; |
|||
|
|||
public class AccountProfileSessionManagementGroupViewComponent : AbpViewComponent |
|||
{ |
|||
public AccountProfileSessionManagementGroupViewComponent() |
|||
{ |
|||
} |
|||
|
|||
public async virtual Task<IViewComponentResult> InvokeAsync() |
|||
{ |
|||
await Task.CompletedTask; |
|||
|
|||
return View("~/Pages/Account/Components/ProfileManagementGroup/Session/Index.cshtml"); |
|||
} |
|||
} |
|||
@ -0,0 +1,22 @@ |
|||
@using Microsoft.AspNetCore.Mvc.Localization |
|||
@using Volo.Abp.Account.Localization |
|||
@using Volo.Abp.Localization |
|||
|
|||
@inject IHtmlLocalizer<AccountResource> L |
|||
|
|||
@section scripts { |
|||
<abp-script src="/Pages/Account/Components/ProfileManagementGroup/Session/Index.js" /> |
|||
} |
|||
|
|||
<abp-card> |
|||
<abp-card-header> |
|||
<abp-row> |
|||
<abp-column size-md="_6"> |
|||
<abp-card-title>@L["PersonalSessions"]</abp-card-title> |
|||
</abp-column> |
|||
</abp-row> |
|||
</abp-card-header> |
|||
<abp-card-body> |
|||
<abp-table striped-rows="true" id="SessionsTable"></abp-table> |
|||
</abp-card-body> |
|||
</abp-card> |
|||
@ -0,0 +1,60 @@ |
|||
$(function () { |
|||
var ul = abp.localization.getResource('AbpUi'); |
|||
var il = abp.localization.getResource('AbpIdentity'); |
|||
var dataTable = $('#SessionsTable').DataTable( |
|||
abp.libs.datatables.normalizeConfiguration({ |
|||
serverSide: true, |
|||
paging: true, |
|||
searching: false, |
|||
scrollX: true, |
|||
ajax: abp.libs.datatables.createAjax(labp.account.myProfile.getSessions), |
|||
columnDefs: [ |
|||
{ |
|||
title: ul('Actions'), |
|||
rowAction: { |
|||
items: |
|||
[ |
|||
{ |
|||
text: il('RevokeSession'), |
|||
confirmMessage: function () { |
|||
return il('SessionWillBeRevokedMessage'); |
|||
}, |
|||
visible: function (data) { |
|||
return data.sessionId !== abp.currentUser?.sessionId; |
|||
}, |
|||
action: function (data) { |
|||
labp.account.myProfile |
|||
.revokeSession(data.record.sessionId) |
|||
.then(function () { |
|||
abp.notify.info( |
|||
il('SuccessfullyRevoked') |
|||
); |
|||
dataTable.ajax.reload(); |
|||
}); |
|||
} |
|||
} |
|||
] |
|||
} |
|||
}, |
|||
{ |
|||
title: il('DisplayName:Device'), |
|||
data: "device" |
|||
}, |
|||
{ |
|||
title: il('DisplayName:IpAddresses'), |
|||
data: "ipAddresses" |
|||
}, |
|||
{ |
|||
title: il('DisplayName:SignedIn'), |
|||
data: "signedIn", |
|||
render: function (data) { |
|||
return luxon |
|||
.DateTime |
|||
.fromISO(data, { |
|||
locale: abp.localization.currentCulture.name |
|||
}).toLocaleString(luxon.DateTime.DATETIME_FULL_WITH_SECONDS); |
|||
} |
|||
}] |
|||
}) |
|||
); |
|||
}); |
|||
@ -0,0 +1,33 @@ |
|||
using Microsoft.AspNetCore.Mvc; |
|||
using System.ComponentModel; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.AspNetCore.Mvc; |
|||
|
|||
namespace LINGYUN.Abp.Account.Web.Pages.Account.Components.ProfileManagementGroup.TwoFactor; |
|||
|
|||
public class AccountProfileTwoFactorManagementGroupViewComponent : AbpViewComponent |
|||
{ |
|||
protected IMyProfileAppService ProfileAppService { get; } |
|||
|
|||
public AccountProfileTwoFactorManagementGroupViewComponent(IMyProfileAppService profileAppService) |
|||
{ |
|||
ProfileAppService = profileAppService; |
|||
} |
|||
|
|||
public async virtual Task<IViewComponentResult> InvokeAsync() |
|||
{ |
|||
var dto = await ProfileAppService.GetTwoFactorEnabledAsync(); |
|||
var model = new ChangeTwoFactorModel |
|||
{ |
|||
TwoFactorEnabled = dto.Enabled |
|||
}; |
|||
|
|||
return View("~/Pages/Account/Components/ProfileManagementGroup/TwoFactor/Default.cshtml", model); |
|||
} |
|||
|
|||
public class ChangeTwoFactorModel |
|||
{ |
|||
[DisplayName("TwoFactor:Enabled")] |
|||
public bool TwoFactorEnabled { get; set; } |
|||
} |
|||
} |
|||
@ -0,0 +1,17 @@ |
|||
@using Volo.Abp.Account.Localization |
|||
@using Microsoft.AspNetCore.Mvc.Localization |
|||
@inject IHtmlLocalizer<AccountResource> L |
|||
@model LINGYUN.Abp.Account.Web.Pages.Account.Components.ProfileManagementGroup.TwoFactor.AccountProfileTwoFactorManagementGroupViewComponent.ChangeTwoFactorModel |
|||
|
|||
@section scripts { |
|||
<abp-script src="/Pages/Account/Components/ProfileManagementGroup/TwoFactor/Default.js" /> |
|||
} |
|||
|
|||
<abp-card> |
|||
<abp-card-header> |
|||
<abp-card-title>@L["TwoFactor"]</abp-card-title> |
|||
</abp-card-header> |
|||
<abp-card-body> |
|||
<abp-input id="TwoFactorEnabled" asp-for="TwoFactorEnabled" /> |
|||
</abp-card-body> |
|||
</abp-card> |
|||
@ -0,0 +1,17 @@ |
|||
$(function () { |
|||
var ul = abp.localization.getResource("AbpUi"); |
|||
$("#TwoFactorEnabled").change(function () { |
|||
var isChecked = $(this).is(':checked'); |
|||
abp.ui.setBusy({ busy: true }); |
|||
labp.account.myProfile |
|||
.changeTwoFactorEnabled({ |
|||
enabled: isChecked |
|||
}) |
|||
.then(function () { |
|||
abp.notify.success(ul("SavedSuccessfully")); |
|||
}) |
|||
.done(function () { |
|||
abp.ui.clearBusy(); |
|||
}); |
|||
}); |
|||
}); |
|||
@ -1,74 +1,74 @@ |
|||
using LINGYUN.Abp.Account; |
|||
using Microsoft.AspNetCore.Mvc; |
|||
using System; |
|||
using System.ComponentModel.DataAnnotations; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.Account.Localization; |
|||
using Volo.Abp.Account.Web.Pages.Account; |
|||
using Volo.Abp.Identity; |
|||
using Volo.Abp.Validation; |
|||
|
|||
namespace LY.MicroService.AuthServer.Pages.Account |
|||
{ |
|||
public class EmailConfirmModel : AccountPageModel |
|||
{ |
|||
[Required] |
|||
[HiddenInput] |
|||
[BindProperty(SupportsGet = true)] |
|||
public Guid UserId { get; set; } |
|||
|
|||
[Required] |
|||
[HiddenInput] |
|||
[BindProperty(SupportsGet = true)] |
|||
public string ConfirmToken { get; set; } |
|||
|
|||
[HiddenInput] |
|||
[BindProperty(SupportsGet = true)] |
|||
public string ReturnUrl { get; set; } |
|||
|
|||
[HiddenInput] |
|||
[BindProperty(SupportsGet = true)] |
|||
public string ReturnUrlHash { get; set; } |
|||
|
|||
public IMyProfileAppService MyProfileAppService { get; set; } |
|||
|
|||
public EmailConfirmModel() |
|||
{ |
|||
LocalizationResourceType = typeof(AccountResource); |
|||
} |
|||
|
|||
public async virtual Task<IActionResult> OnPostAsync() |
|||
{ |
|||
try |
|||
{ |
|||
ValidateModel(); |
|||
|
|||
await MyProfileAppService.ConfirmEmailAsync( |
|||
new ConfirmEmailInput |
|||
{ |
|||
ConfirmToken = ConfirmToken, |
|||
}); |
|||
} |
|||
catch (AbpIdentityResultException e) |
|||
{ |
|||
if (!string.IsNullOrWhiteSpace(e.Message)) |
|||
{ |
|||
Alerts.Warning(GetLocalizeExceptionMessage(e)); |
|||
return Page(); |
|||
} |
|||
|
|||
throw; |
|||
} |
|||
catch (AbpValidationException) |
|||
{ |
|||
return Page(); |
|||
} |
|||
|
|||
return RedirectToPage("./ConfirmEmailConfirmation", new |
|||
{ |
|||
returnUrl = ReturnUrl, |
|||
returnUrlHash = ReturnUrlHash |
|||
}); |
|||
} |
|||
} |
|||
} |
|||
using LINGYUN.Abp.Account; |
|||
using Microsoft.AspNetCore.Mvc; |
|||
using System; |
|||
using System.ComponentModel.DataAnnotations; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.Account.Localization; |
|||
using Volo.Abp.Account.Web.Pages.Account; |
|||
using Volo.Abp.Identity; |
|||
using Volo.Abp.Validation; |
|||
|
|||
namespace LINGYUN.Abp.Account.Web.Pages.Account |
|||
{ |
|||
public class EmailConfirmModel : AccountPageModel |
|||
{ |
|||
[Required] |
|||
[HiddenInput] |
|||
[BindProperty(SupportsGet = true)] |
|||
public Guid UserId { get; set; } |
|||
|
|||
[Required] |
|||
[HiddenInput] |
|||
[BindProperty(SupportsGet = true)] |
|||
public string ConfirmToken { get; set; } |
|||
|
|||
[HiddenInput] |
|||
[BindProperty(SupportsGet = true)] |
|||
public string ReturnUrl { get; set; } |
|||
|
|||
[HiddenInput] |
|||
[BindProperty(SupportsGet = true)] |
|||
public string ReturnUrlHash { get; set; } |
|||
|
|||
public IMyProfileAppService MyProfileAppService { get; set; } |
|||
|
|||
public EmailConfirmModel() |
|||
{ |
|||
LocalizationResourceType = typeof(AccountResource); |
|||
} |
|||
|
|||
public async virtual Task<IActionResult> OnPostAsync() |
|||
{ |
|||
try |
|||
{ |
|||
ValidateModel(); |
|||
|
|||
await MyProfileAppService.ConfirmEmailAsync( |
|||
new ConfirmEmailInput |
|||
{ |
|||
ConfirmToken = ConfirmToken, |
|||
}); |
|||
} |
|||
catch (AbpIdentityResultException e) |
|||
{ |
|||
if (!string.IsNullOrWhiteSpace(e.Message)) |
|||
{ |
|||
Alerts.Warning(GetLocalizeExceptionMessage(e)); |
|||
return Page(); |
|||
} |
|||
|
|||
throw; |
|||
} |
|||
catch (AbpValidationException) |
|||
{ |
|||
return Page(); |
|||
} |
|||
|
|||
return RedirectToPage("./ConfirmEmailConfirmation", new |
|||
{ |
|||
returnUrl = ReturnUrl, |
|||
returnUrlHash = ReturnUrlHash |
|||
}); |
|||
} |
|||
} |
|||
} |
|||
@ -1,13 +1,13 @@ |
|||
@page |
|||
@model LY.MicroService.AuthServer.Pages.Account.EmailConfirmConfirmationModel |
|||
@inject Volo.Abp.AspNetCore.Mvc.UI.Layout.IPageLayout PageLayout |
|||
@using Microsoft.AspNetCore.Mvc.Localization |
|||
@using Volo.Abp.Account.Localization |
|||
@inject IHtmlLocalizer<AccountResource> L |
|||
<div class="card mt-3 shadow-sm rounded"> |
|||
<div class="card-body p-5"> |
|||
<h4>@L["EmailConfirm"]</h4> |
|||
<p>@L["YourEmailIsSuccessfullyConfirm"]</p> |
|||
<a abp-button="Primary" href="@Url.Content(Model.ReturnUrl)">@L["GoToTheApplication"]</a> |
|||
</div> |
|||
</div> |
|||
@page |
|||
@model LINGYUN.Abp.Account.Web.Pages.Account.EmailConfirmConfirmationModel |
|||
@inject Volo.Abp.AspNetCore.Mvc.UI.Layout.IPageLayout PageLayout |
|||
@using Microsoft.AspNetCore.Mvc.Localization |
|||
@using Volo.Abp.Account.Localization |
|||
@inject IHtmlLocalizer<AccountResource> L |
|||
<div class="card mt-3 shadow-sm rounded"> |
|||
<div class="card-body p-5"> |
|||
<h4>@L["EmailConfirm"]</h4> |
|||
<p>@L["YourEmailIsSuccessfullyConfirm"]</p> |
|||
<a abp-button="Primary" href="@Url.Content(Model.ReturnUrl)">@L["GoToTheApplication"]</a> |
|||
</div> |
|||
</div> |
|||
@ -1,23 +1,23 @@ |
|||
using Microsoft.AspNetCore.Authorization; |
|||
using Microsoft.AspNetCore.Mvc; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.Account.Web.Pages.Account; |
|||
|
|||
namespace LY.MicroService.AuthServer.Pages.Account; |
|||
|
|||
[AllowAnonymous] |
|||
public class EmailConfirmConfirmationModel : AccountPageModel |
|||
{ |
|||
[BindProperty(SupportsGet = true)] |
|||
public string ReturnUrl { get; set; } |
|||
|
|||
[BindProperty(SupportsGet = true)] |
|||
public string ReturnUrlHash { get; set; } |
|||
|
|||
public async virtual Task<IActionResult> OnGetAsync() |
|||
{ |
|||
ReturnUrl = await GetRedirectUrlAsync(ReturnUrl, ReturnUrlHash); |
|||
|
|||
return Page(); |
|||
} |
|||
} |
|||
using Microsoft.AspNetCore.Authorization; |
|||
using Microsoft.AspNetCore.Mvc; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.Account.Web.Pages.Account; |
|||
|
|||
namespace LINGYUN.Abp.Account.Web.Pages.Account; |
|||
|
|||
[AllowAnonymous] |
|||
public class EmailConfirmConfirmationModel : AccountPageModel |
|||
{ |
|||
[BindProperty(SupportsGet = true)] |
|||
public string ReturnUrl { get; set; } |
|||
|
|||
[BindProperty(SupportsGet = true)] |
|||
public string ReturnUrlHash { get; set; } |
|||
|
|||
public async virtual Task<IActionResult> OnGetAsync() |
|||
{ |
|||
ReturnUrl = await GetRedirectUrlAsync(ReturnUrl, ReturnUrlHash); |
|||
|
|||
return Page(); |
|||
} |
|||
} |
|||
@ -1,7 +1,7 @@ |
|||
@page |
|||
@using Microsoft.AspNetCore.Mvc.Localization |
|||
@using Volo.Abp.Account.Localization |
|||
@model LY.MicroService.AuthServer.Pages.Account.SendCodeModel |
|||
@model LINGYUN.Abp.Account.Web.Pages.Account.SendCodeModel |
|||
@inject IHtmlLocalizer<AccountResource> L |
|||
|
|||
<div class="card mt-3 shadow-sm rounded"> |
|||
@ -1,128 +1,128 @@ |
|||
using LINGYUN.Abp.Account.Emailing; |
|||
using LINGYUN.Abp.Identity.Settings; |
|||
using Microsoft.AspNetCore.Mvc; |
|||
using Microsoft.AspNetCore.Mvc.Rendering; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp; |
|||
using Volo.Abp.Account.Localization; |
|||
using Volo.Abp.Account.Web.Pages.Account; |
|||
using Volo.Abp.Sms; |
|||
|
|||
namespace LY.MicroService.AuthServer.Pages.Account |
|||
{ |
|||
public class SendCodeModel : AccountPageModel |
|||
{ |
|||
[BindProperty] |
|||
public SendCodeInputModel Input { get; set; } |
|||
|
|||
[HiddenInput] |
|||
[BindProperty(SupportsGet = true)] |
|||
public string ReturnUrl { get; set; } |
|||
|
|||
[HiddenInput] |
|||
[BindProperty(SupportsGet = true)] |
|||
public string ReturnUrlHash { get; set; } |
|||
|
|||
[HiddenInput] |
|||
[BindProperty(SupportsGet = true)] |
|||
public bool RememberMe { get; set; } |
|||
|
|||
public IEnumerable<SelectListItem> Providers { get; set; } |
|||
|
|||
protected ISmsSender SmsSender { get; } |
|||
|
|||
protected IAccountEmailVerifySender AccountEmailVerifySender { get; } |
|||
|
|||
public SendCodeModel( |
|||
ISmsSender smsSender, |
|||
IAccountEmailVerifySender accountEmailVerifySender) |
|||
{ |
|||
SmsSender = smsSender; |
|||
AccountEmailVerifySender = accountEmailVerifySender; |
|||
|
|||
LocalizationResourceType = typeof(AccountResource); |
|||
} |
|||
|
|||
public virtual async Task<IActionResult> OnGetAsync() |
|||
{ |
|||
Input = new SendCodeInputModel(); |
|||
|
|||
var user = await SignInManager.GetTwoFactorAuthenticationUserAsync(); |
|||
if (user == null) |
|||
{ |
|||
// 双因素信息验证失败,一般都是超时了或者用户信息变更
|
|||
Alerts.Warning(L["TwoFactorAuthenticationInvaidUser"]); |
|||
return Page(); |
|||
} |
|||
var userFactors = await UserManager.GetValidTwoFactorProvidersAsync(user); |
|||
Providers = userFactors.Select(purpose => new SelectListItem { Text = purpose, Value = purpose }).ToList(); |
|||
|
|||
return Page(); |
|||
} |
|||
|
|||
public virtual async Task<IActionResult> OnPostAsync() |
|||
{ |
|||
var user = await SignInManager.GetTwoFactorAuthenticationUserAsync(); |
|||
if (user == null) |
|||
{ |
|||
Alerts.Warning(L["TwoFactorAuthenticationInvaidUser"]); |
|||
return Page(); |
|||
} |
|||
|
|||
if (Input.SelectedProvider == "Authenticator") |
|||
{ |
|||
// 用户通过邮件/短信链接进入授权页面
|
|||
return RedirectToPage("VerifyAuthenticatorCode", new |
|||
{ |
|||
returnUrl = ReturnUrl, |
|||
returnUrlHash = ReturnUrlHash, |
|||
rememberMe = RememberMe |
|||
}); |
|||
} |
|||
// 生成验证码
|
|||
var code = await UserManager.GenerateTwoFactorTokenAsync(user, Input.SelectedProvider); |
|||
if (string.IsNullOrWhiteSpace(code)) |
|||
{ |
|||
Alerts.Warning(L["InvaidGenerateTwoFactorToken"]); |
|||
return Page(); |
|||
} |
|||
|
|||
if (Input.SelectedProvider == "Email") |
|||
{ |
|||
await AccountEmailVerifySender |
|||
.SendMailLoginVerifyCodeAsync( |
|||
code, |
|||
user.UserName, |
|||
user.Email); |
|||
} |
|||
else if (Input.SelectedProvider == "Phone") |
|||
{ |
|||
var phoneNumber = await UserManager.GetPhoneNumberAsync(user); |
|||
var templateCode = await SettingProvider.GetOrNullAsync(IdentitySettingNames.User.SmsUserSignin); |
|||
Check.NotNullOrWhiteSpace(templateCode, nameof(IdentitySettingNames.User.SmsUserSignin)); |
|||
|
|||
// TODO: 以后扩展短信模板发送
|
|||
var smsMessage = new SmsMessage(phoneNumber, code); |
|||
smsMessage.Properties.Add("code", code); |
|||
smsMessage.Properties.Add("TemplateCode", templateCode); |
|||
|
|||
await SmsSender.SendAsync(smsMessage); |
|||
} |
|||
|
|||
return RedirectToPage("VerifyCode", new |
|||
{ |
|||
provider = Input.SelectedProvider, |
|||
returnUrl = ReturnUrl, |
|||
returnUrlHash = ReturnUrlHash, |
|||
rememberMe = RememberMe |
|||
}); |
|||
} |
|||
} |
|||
|
|||
public class SendCodeInputModel |
|||
{ |
|||
public string SelectedProvider { get; set; } |
|||
} |
|||
} |
|||
using LINGYUN.Abp.Account.Emailing; |
|||
using LINGYUN.Abp.Identity.Settings; |
|||
using Microsoft.AspNetCore.Mvc; |
|||
using Microsoft.AspNetCore.Mvc.Rendering; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp; |
|||
using Volo.Abp.Account.Localization; |
|||
using Volo.Abp.Account.Web.Pages.Account; |
|||
using Volo.Abp.Sms; |
|||
|
|||
namespace LINGYUN.Abp.Account.Web.Pages.Account |
|||
{ |
|||
public class SendCodeModel : AccountPageModel |
|||
{ |
|||
[BindProperty] |
|||
public SendCodeInputModel Input { get; set; } |
|||
|
|||
[HiddenInput] |
|||
[BindProperty(SupportsGet = true)] |
|||
public string ReturnUrl { get; set; } |
|||
|
|||
[HiddenInput] |
|||
[BindProperty(SupportsGet = true)] |
|||
public string ReturnUrlHash { get; set; } |
|||
|
|||
[HiddenInput] |
|||
[BindProperty(SupportsGet = true)] |
|||
public bool RememberMe { get; set; } |
|||
|
|||
public IEnumerable<SelectListItem> Providers { get; set; } |
|||
|
|||
protected ISmsSender SmsSender { get; } |
|||
|
|||
protected IAccountEmailVerifySender AccountEmailVerifySender { get; } |
|||
|
|||
public SendCodeModel( |
|||
ISmsSender smsSender, |
|||
IAccountEmailVerifySender accountEmailVerifySender) |
|||
{ |
|||
SmsSender = smsSender; |
|||
AccountEmailVerifySender = accountEmailVerifySender; |
|||
|
|||
LocalizationResourceType = typeof(AccountResource); |
|||
} |
|||
|
|||
public virtual async Task<IActionResult> OnGetAsync() |
|||
{ |
|||
Input = new SendCodeInputModel(); |
|||
|
|||
var user = await SignInManager.GetTwoFactorAuthenticationUserAsync(); |
|||
if (user == null) |
|||
{ |
|||
// 双因素信息验证失败,一般都是超时了或者用户信息变更
|
|||
Alerts.Warning(L["TwoFactorAuthenticationInvaidUser"]); |
|||
return Page(); |
|||
} |
|||
var userFactors = await UserManager.GetValidTwoFactorProvidersAsync(user); |
|||
Providers = userFactors.Select(purpose => new SelectListItem { Text = purpose, Value = purpose }).ToList(); |
|||
|
|||
return Page(); |
|||
} |
|||
|
|||
public virtual async Task<IActionResult> OnPostAsync() |
|||
{ |
|||
var user = await SignInManager.GetTwoFactorAuthenticationUserAsync(); |
|||
if (user == null) |
|||
{ |
|||
Alerts.Warning(L["TwoFactorAuthenticationInvaidUser"]); |
|||
return Page(); |
|||
} |
|||
|
|||
if (Input.SelectedProvider == "Authenticator") |
|||
{ |
|||
// 用户通过邮件/短信链接进入授权页面
|
|||
return RedirectToPage("VerifyAuthenticatorCode", new |
|||
{ |
|||
returnUrl = ReturnUrl, |
|||
returnUrlHash = ReturnUrlHash, |
|||
rememberMe = RememberMe |
|||
}); |
|||
} |
|||
// 生成验证码
|
|||
var code = await UserManager.GenerateTwoFactorTokenAsync(user, Input.SelectedProvider); |
|||
if (string.IsNullOrWhiteSpace(code)) |
|||
{ |
|||
Alerts.Warning(L["InvaidGenerateTwoFactorToken"]); |
|||
return Page(); |
|||
} |
|||
|
|||
if (Input.SelectedProvider == "Email") |
|||
{ |
|||
await AccountEmailVerifySender |
|||
.SendMailLoginVerifyCodeAsync( |
|||
code, |
|||
user.UserName, |
|||
user.Email); |
|||
} |
|||
else if (Input.SelectedProvider == "Phone") |
|||
{ |
|||
var phoneNumber = await UserManager.GetPhoneNumberAsync(user); |
|||
var templateCode = await SettingProvider.GetOrNullAsync(IdentitySettingNames.User.SmsUserSignin); |
|||
Check.NotNullOrWhiteSpace(templateCode, nameof(IdentitySettingNames.User.SmsUserSignin)); |
|||
|
|||
// TODO: 以后扩展短信模板发送
|
|||
var smsMessage = new SmsMessage(phoneNumber, code); |
|||
smsMessage.Properties.Add("code", code); |
|||
smsMessage.Properties.Add("TemplateCode", templateCode); |
|||
|
|||
await SmsSender.SendAsync(smsMessage); |
|||
} |
|||
|
|||
return RedirectToPage("VerifyCode", new |
|||
{ |
|||
provider = Input.SelectedProvider, |
|||
returnUrl = ReturnUrl, |
|||
returnUrlHash = ReturnUrlHash, |
|||
rememberMe = RememberMe |
|||
}); |
|||
} |
|||
} |
|||
|
|||
public class SendCodeInputModel |
|||
{ |
|||
public string SelectedProvider { get; set; } |
|||
} |
|||
} |
|||
@ -1,75 +1,73 @@ |
|||
using LINGYUN.Abp.Account; |
|||
using Microsoft.AspNetCore.Mvc; |
|||
using System.ComponentModel.DataAnnotations; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.Account.Localization; |
|||
using Volo.Abp.Account.Web.Pages.Account; |
|||
using Volo.Abp.Identity; |
|||
using Volo.Abp.Validation; |
|||
|
|||
namespace LY.MicroService.AuthServer.Pages.Account |
|||
{ |
|||
public class SendEmailConfirmModel : AccountPageModel |
|||
{ |
|||
[BindProperty(SupportsGet = true)] |
|||
public string Email { get; set; } |
|||
|
|||
[HiddenInput] |
|||
[BindProperty(SupportsGet = true)] |
|||
public string ReturnUrl { get; set; } |
|||
|
|||
[HiddenInput] |
|||
[BindProperty(SupportsGet = true)] |
|||
public string ReturnUrlHash { get; set; } |
|||
|
|||
public IMyProfileAppService MyProfileAppService { get; set; } |
|||
|
|||
public SendEmailConfirmModel() |
|||
{ |
|||
LocalizationResourceType = typeof(AccountResource); |
|||
} |
|||
|
|||
public virtual Task<IActionResult> OnGetAsync() |
|||
{ |
|||
Email = CurrentUser.Email; |
|||
|
|||
return Task.FromResult<IActionResult>(Page()); |
|||
} |
|||
|
|||
public async virtual Task<IActionResult> OnPostAsync() |
|||
{ |
|||
try |
|||
{ |
|||
ValidateModel(); |
|||
|
|||
await MyProfileAppService.SendEmailConfirmLinkAsync( |
|||
new SendEmailConfirmCodeDto |
|||
{ |
|||
Email = Email, |
|||
AppName = "MVC", |
|||
ReturnUrl = ReturnUrl, |
|||
ReturnUrlHash = ReturnUrlHash |
|||
}); |
|||
} |
|||
catch (AbpIdentityResultException e) |
|||
{ |
|||
if (!string.IsNullOrWhiteSpace(e.Message)) |
|||
{ |
|||
Alerts.Warning(GetLocalizeExceptionMessage(e)); |
|||
return Page(); |
|||
} |
|||
|
|||
throw; |
|||
} |
|||
catch (AbpValidationException) |
|||
{ |
|||
return Page(); |
|||
} |
|||
|
|||
return RedirectToPage("~/Account/Manage", new |
|||
{ |
|||
returnUrl = ReturnUrl |
|||
}); |
|||
} |
|||
} |
|||
} |
|||
using Microsoft.AspNetCore.Mvc; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.Account.Localization; |
|||
using Volo.Abp.Account.Web.Pages.Account; |
|||
using Volo.Abp.Identity; |
|||
using Volo.Abp.Validation; |
|||
|
|||
namespace LINGYUN.Abp.Account.Web.Pages.Account |
|||
{ |
|||
public class SendEmailConfirmModel : AccountPageModel |
|||
{ |
|||
[BindProperty(SupportsGet = true)] |
|||
public string Email { get; set; } |
|||
|
|||
[HiddenInput] |
|||
[BindProperty(SupportsGet = true)] |
|||
public string ReturnUrl { get; set; } |
|||
|
|||
[HiddenInput] |
|||
[BindProperty(SupportsGet = true)] |
|||
public string ReturnUrlHash { get; set; } |
|||
|
|||
public IMyProfileAppService MyProfileAppService { get; set; } |
|||
|
|||
public SendEmailConfirmModel() |
|||
{ |
|||
LocalizationResourceType = typeof(AccountResource); |
|||
} |
|||
|
|||
public virtual Task<IActionResult> OnGetAsync() |
|||
{ |
|||
Email = CurrentUser.Email; |
|||
|
|||
return Task.FromResult<IActionResult>(Page()); |
|||
} |
|||
|
|||
public async virtual Task<IActionResult> OnPostAsync() |
|||
{ |
|||
try |
|||
{ |
|||
ValidateModel(); |
|||
|
|||
await MyProfileAppService.SendEmailConfirmLinkAsync( |
|||
new SendEmailConfirmCodeDto |
|||
{ |
|||
Email = Email, |
|||
AppName = "MVC", |
|||
ReturnUrl = ReturnUrl, |
|||
ReturnUrlHash = ReturnUrlHash |
|||
}); |
|||
} |
|||
catch (AbpIdentityResultException e) |
|||
{ |
|||
if (!string.IsNullOrWhiteSpace(e.Message)) |
|||
{ |
|||
Alerts.Warning(GetLocalizeExceptionMessage(e)); |
|||
return Page(); |
|||
} |
|||
|
|||
throw; |
|||
} |
|||
catch (AbpValidationException) |
|||
{ |
|||
return Page(); |
|||
} |
|||
|
|||
return RedirectToPage("~/Account/Manage", new |
|||
{ |
|||
returnUrl = ReturnUrl |
|||
}); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,4 @@ |
|||
@page |
|||
@model LINGYUN.Abp.Account.Web.Pages.Account.UseRecoveryCodeModel |
|||
@{ |
|||
} |
|||
@ -0,0 +1,11 @@ |
|||
using Microsoft.AspNetCore.Mvc.RazorPages; |
|||
|
|||
namespace LINGYUN.Abp.Account.Web.Pages.Account |
|||
{ |
|||
public class UseRecoveryCodeModel : PageModel |
|||
{ |
|||
public void OnGet() |
|||
{ |
|||
} |
|||
} |
|||
} |
|||
@ -1,7 +1,7 @@ |
|||
@page |
|||
@using Microsoft.AspNetCore.Mvc.Localization |
|||
@using Volo.Abp.Account.Localization |
|||
@model LY.MicroService.AuthServer.Pages.Account.VerifyAuthenticatorCodeModel |
|||
@model LINGYUN.Abp.Account.Web.Pages.Account.VerifyAuthenticatorCodeModel |
|||
@inject IHtmlLocalizer<AccountResource> L |
|||
<div class="card mt-3 shadow-sm rounded"> |
|||
<div class="card-body p-5"> |
|||
@ -0,0 +1,4 @@ |
|||
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers |
|||
@addTagHelper *, Volo.Abp.AspNetCore.Mvc.UI |
|||
@addTagHelper *, Volo.Abp.AspNetCore.Mvc.UI.Bootstrap |
|||
@addTagHelper *, Volo.Abp.AspNetCore.Mvc.UI.Bundling |
|||
@ -0,0 +1,53 @@ |
|||
using LINGYUN.Abp.Account.Web.Pages.Account.Components.ProfileManagementGroup.Authenticator; |
|||
using LINGYUN.Abp.Account.Web.Pages.Account.Components.ProfileManagementGroup.SecurityLog; |
|||
using LINGYUN.Abp.Account.Web.Pages.Account.Components.ProfileManagementGroup.Session; |
|||
using LINGYUN.Abp.Account.Web.Pages.Account.Components.ProfileManagementGroup.TwoFactor; |
|||
using Microsoft.Extensions.DependencyInjection; |
|||
using Microsoft.Extensions.Localization; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.Account.Localization; |
|||
using Volo.Abp.Account.Web.ProfileManagement; |
|||
|
|||
namespace LINGYUN.Abp.Account.Web.ProfileManagement; |
|||
|
|||
public class SessionManagementPageContributor : IProfileManagementPageContributor |
|||
{ |
|||
public virtual Task ConfigureAsync(ProfileManagementPageCreationContext context) |
|||
{ |
|||
var l = context.ServiceProvider.GetRequiredService<IStringLocalizer<AccountResource>>(); |
|||
|
|||
context.Groups.Add( |
|||
new ProfileManagementPageGroup( |
|||
"LINGYUN.Abp.Account.Session", |
|||
l["ProfileTab:Session"], |
|||
typeof(AccountProfileSessionManagementGroupViewComponent) |
|||
) |
|||
); |
|||
|
|||
context.Groups.Add( |
|||
new ProfileManagementPageGroup( |
|||
"LINGYUN.Abp.Account.TwoFactor", |
|||
l["ProfileTab:TwoFactor"], |
|||
typeof(AccountProfileTwoFactorManagementGroupViewComponent) |
|||
) |
|||
); |
|||
|
|||
context.Groups.Add( |
|||
new ProfileManagementPageGroup( |
|||
"LINGYUN.Abp.Account.SecurityLog", |
|||
l["ProfileTab:SecurityLog"], |
|||
typeof(AccountProfileSecurityLogManagementGroupViewComponent) |
|||
) |
|||
); |
|||
|
|||
context.Groups.Add( |
|||
new ProfileManagementPageGroup( |
|||
"LINGYUN.Abp.Account.Authenticator", |
|||
l["ProfileTab:Authenticator"], |
|||
typeof(AccountProfileAuthenticatorManagementGroupViewComponent) |
|||
) |
|||
); |
|||
|
|||
return Task.CompletedTask; |
|||
} |
|||
} |
|||
@ -0,0 +1,12 @@ |
|||
{ |
|||
"profiles": { |
|||
"LINGYUN.Abp.Account.Web": { |
|||
"commandName": "Project", |
|||
"launchBrowser": true, |
|||
"environmentVariables": { |
|||
"ASPNETCORE_ENVIRONMENT": "Development" |
|||
}, |
|||
"applicationUrl": "https://localhost:51246;http://localhost:51247" |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,329 @@ |
|||
/* This file is automatically generated by ABP framework to use MVC Controllers from javascript. */ |
|||
|
|||
|
|||
// module account
|
|||
|
|||
(function(){ |
|||
|
|||
// controller labp.account.account
|
|||
|
|||
(function(){ |
|||
|
|||
abp.utils.createNamespace(window, 'labp.account.account'); |
|||
|
|||
labp.account.account.register = function(input, ajaxParams) { |
|||
return abp.ajax($.extend(true, { |
|||
url: abp.appPath + 'api/account/wechat/register', |
|||
type: 'POST', |
|||
dataType: null, |
|||
data: JSON.stringify(input) |
|||
}, ajaxParams)); |
|||
}; |
|||
|
|||
labp.account.account.resetPassword = function(input, ajaxParams) { |
|||
return abp.ajax($.extend(true, { |
|||
url: abp.appPath + 'api/account/phone/reset-password', |
|||
type: 'PUT', |
|||
dataType: null, |
|||
data: JSON.stringify(input) |
|||
}, ajaxParams)); |
|||
}; |
|||
|
|||
labp.account.account.sendPhoneSigninCode = function(input, ajaxParams) { |
|||
return abp.ajax($.extend(true, { |
|||
url: abp.appPath + 'api/account/phone/send-signin-code', |
|||
type: 'POST', |
|||
dataType: null, |
|||
data: JSON.stringify(input) |
|||
}, ajaxParams)); |
|||
}; |
|||
|
|||
labp.account.account.sendEmailSigninCode = function(input, ajaxParams) { |
|||
return abp.ajax($.extend(true, { |
|||
url: abp.appPath + 'api/account/email/send-signin-code', |
|||
type: 'POST', |
|||
dataType: null, |
|||
data: JSON.stringify(input) |
|||
}, ajaxParams)); |
|||
}; |
|||
|
|||
labp.account.account.sendPhoneRegisterCode = function(input, ajaxParams) { |
|||
return abp.ajax($.extend(true, { |
|||
url: abp.appPath + 'api/account/phone/send-register-code', |
|||
type: 'POST', |
|||
dataType: null, |
|||
data: JSON.stringify(input) |
|||
}, ajaxParams)); |
|||
}; |
|||
|
|||
labp.account.account.sendPhoneResetPasswordCode = function(input, ajaxParams) { |
|||
return abp.ajax($.extend(true, { |
|||
url: abp.appPath + 'api/account/phone/send-password-reset-code', |
|||
type: 'POST', |
|||
dataType: null, |
|||
data: JSON.stringify(input) |
|||
}, ajaxParams)); |
|||
}; |
|||
|
|||
labp.account.account.getTwoFactorProviders = function(input, ajaxParams) { |
|||
return abp.ajax($.extend(true, { |
|||
url: abp.appPath + 'api/account/two-factor-providers' + abp.utils.buildQueryString([{ name: 'userId', value: input.userId }]) + '', |
|||
type: 'GET' |
|||
}, ajaxParams)); |
|||
}; |
|||
|
|||
})(); |
|||
|
|||
// controller labp.account.myClaim
|
|||
|
|||
(function(){ |
|||
|
|||
abp.utils.createNamespace(window, 'labp.account.myClaim'); |
|||
|
|||
labp.account.myClaim.changeAvatar = function(input, ajaxParams) { |
|||
return abp.ajax($.extend(true, { |
|||
url: abp.appPath + 'api/account/my-claim/change-avatar', |
|||
type: 'POST', |
|||
dataType: null, |
|||
data: JSON.stringify(input) |
|||
}, ajaxParams)); |
|||
}; |
|||
|
|||
labp.account.myClaim.getState = function(claimType, ajaxParams) { |
|||
return abp.ajax($.extend(true, { |
|||
url: abp.appPath + 'api/account/my-claim/state/' + claimType + '', |
|||
type: 'GET' |
|||
}, ajaxParams)); |
|||
}; |
|||
|
|||
labp.account.myClaim.reset = function(claimType, ajaxParams) { |
|||
return abp.ajax($.extend(true, { |
|||
url: abp.appPath + 'api/account/my-claim/reset/' + claimType + '', |
|||
type: 'DELETE', |
|||
dataType: null |
|||
}, ajaxParams)); |
|||
}; |
|||
|
|||
})(); |
|||
|
|||
// controller labp.account.myProfile
|
|||
|
|||
(function(){ |
|||
|
|||
abp.utils.createNamespace(window, 'labp.account.myProfile'); |
|||
|
|||
labp.account.myProfile.getSessions = function(input, ajaxParams) { |
|||
return abp.ajax($.extend(true, { |
|||
url: abp.appPath + 'api/account/my-profile/sessions' + abp.utils.buildQueryString([{ name: 'device', value: input.device }, { name: 'clientId', value: input.clientId }, { name: 'sorting', value: input.sorting }, { name: 'skipCount', value: input.skipCount }, { name: 'maxResultCount', value: input.maxResultCount }]) + '', |
|||
type: 'GET' |
|||
}, ajaxParams)); |
|||
}; |
|||
|
|||
labp.account.myProfile.revokeSession = function(sessionId, ajaxParams) { |
|||
return abp.ajax($.extend(true, { |
|||
url: abp.appPath + 'api/account/my-profile/sessions/' + sessionId + '/revoke', |
|||
type: 'DELETE', |
|||
dataType: null |
|||
}, ajaxParams)); |
|||
}; |
|||
|
|||
labp.account.myProfile.getTwoFactorEnabled = function(ajaxParams) { |
|||
return abp.ajax($.extend(true, { |
|||
url: abp.appPath + 'api/account/my-profile/two-factor', |
|||
type: 'GET' |
|||
}, ajaxParams)); |
|||
}; |
|||
|
|||
labp.account.myProfile.changeTwoFactorEnabled = function(input, ajaxParams) { |
|||
return abp.ajax($.extend(true, { |
|||
url: abp.appPath + 'api/account/my-profile/change-two-factor', |
|||
type: 'PUT', |
|||
dataType: null, |
|||
data: JSON.stringify(input) |
|||
}, ajaxParams)); |
|||
}; |
|||
|
|||
labp.account.myProfile.sendChangePhoneNumberCode = function(input, ajaxParams) { |
|||
return abp.ajax($.extend(true, { |
|||
url: abp.appPath + 'api/account/my-profile/send-phone-number-change-code', |
|||
type: 'POST', |
|||
dataType: null, |
|||
data: JSON.stringify(input) |
|||
}, ajaxParams)); |
|||
}; |
|||
|
|||
labp.account.myProfile.changePhoneNumber = function(input, ajaxParams) { |
|||
return abp.ajax($.extend(true, { |
|||
url: abp.appPath + 'api/account/my-profile/change-phone-number', |
|||
type: 'PUT', |
|||
dataType: null, |
|||
data: JSON.stringify(input) |
|||
}, ajaxParams)); |
|||
}; |
|||
|
|||
labp.account.myProfile.sendEmailConfirmLink = function(input, ajaxParams) { |
|||
return abp.ajax($.extend(true, { |
|||
url: abp.appPath + 'api/account/my-profile/send-email-confirm-link', |
|||
type: 'POST', |
|||
dataType: null, |
|||
data: JSON.stringify(input) |
|||
}, ajaxParams)); |
|||
}; |
|||
|
|||
labp.account.myProfile.confirmEmail = function(input, ajaxParams) { |
|||
return abp.ajax($.extend(true, { |
|||
url: abp.appPath + 'api/account/my-profile/confirm-email', |
|||
type: 'PUT', |
|||
dataType: null, |
|||
data: JSON.stringify(input) |
|||
}, ajaxParams)); |
|||
}; |
|||
|
|||
labp.account.myProfile.getAuthenticator = function(ajaxParams) { |
|||
return abp.ajax($.extend(true, { |
|||
url: abp.appPath + 'api/account/my-profile/authenticator', |
|||
type: 'GET' |
|||
}, ajaxParams)); |
|||
}; |
|||
|
|||
labp.account.myProfile.verifyAuthenticatorCode = function(input, ajaxParams) { |
|||
return abp.ajax($.extend(true, { |
|||
url: abp.appPath + 'api/account/my-profile/verify-authenticator-code', |
|||
type: 'POST', |
|||
data: JSON.stringify(input) |
|||
}, ajaxParams)); |
|||
}; |
|||
|
|||
labp.account.myProfile.resetAuthenticator = function(ajaxParams) { |
|||
return abp.ajax($.extend(true, { |
|||
url: abp.appPath + 'api/account/my-profile/reset-authenticator', |
|||
type: 'POST', |
|||
dataType: null |
|||
}, ajaxParams)); |
|||
}; |
|||
|
|||
})(); |
|||
|
|||
// controller labp.account.mySecurityLog
|
|||
|
|||
(function(){ |
|||
|
|||
abp.utils.createNamespace(window, 'labp.account.mySecurityLog'); |
|||
|
|||
labp.account.mySecurityLog['delete'] = function(id, ajaxParams) { |
|||
return abp.ajax($.extend(true, { |
|||
url: abp.appPath + 'api/account/security-logs/' + id + '', |
|||
type: 'DELETE', |
|||
dataType: null |
|||
}, ajaxParams)); |
|||
}; |
|||
|
|||
labp.account.mySecurityLog.get = function(id, ajaxParams) { |
|||
return abp.ajax($.extend(true, { |
|||
url: abp.appPath + 'api/account/security-logs/' + id + '', |
|||
type: 'GET' |
|||
}, ajaxParams)); |
|||
}; |
|||
|
|||
labp.account.mySecurityLog.getList = function(input, ajaxParams) { |
|||
return abp.ajax($.extend(true, { |
|||
url: abp.appPath + 'api/account/security-logs' + abp.utils.buildQueryString([{ name: 'startTime', value: input.startTime }, { name: 'endTime', value: input.endTime }, { name: 'applicationName', value: input.applicationName }, { name: 'identity', value: input.identity }, { name: 'actionName', value: input.actionName }, { name: 'clientId', value: input.clientId }, { name: 'correlationId', value: input.correlationId }, { name: 'sorting', value: input.sorting }, { name: 'skipCount', value: input.skipCount }, { name: 'maxResultCount', value: input.maxResultCount }]) + '', |
|||
type: 'GET' |
|||
}, ajaxParams)); |
|||
}; |
|||
|
|||
})(); |
|||
|
|||
// controller volo.abp.account.account
|
|||
|
|||
(function(){ |
|||
|
|||
abp.utils.createNamespace(window, 'volo.abp.account.account'); |
|||
|
|||
volo.abp.account.account.register = function(input, ajaxParams) { |
|||
return abp.ajax($.extend(true, { |
|||
url: abp.appPath + 'api/account/register', |
|||
type: 'POST', |
|||
data: JSON.stringify(input) |
|||
}, ajaxParams)); |
|||
}; |
|||
|
|||
volo.abp.account.account.sendPasswordResetCode = function(input, ajaxParams) { |
|||
return abp.ajax($.extend(true, { |
|||
url: abp.appPath + 'api/account/send-password-reset-code', |
|||
type: 'POST', |
|||
dataType: null, |
|||
data: JSON.stringify(input) |
|||
}, ajaxParams)); |
|||
}; |
|||
|
|||
volo.abp.account.account.verifyPasswordResetToken = function(input, ajaxParams) { |
|||
return abp.ajax($.extend(true, { |
|||
url: abp.appPath + 'api/account/verify-password-reset-token', |
|||
type: 'POST', |
|||
data: JSON.stringify(input) |
|||
}, ajaxParams)); |
|||
}; |
|||
|
|||
volo.abp.account.account.resetPassword = function(input, ajaxParams) { |
|||
return abp.ajax($.extend(true, { |
|||
url: abp.appPath + 'api/account/reset-password', |
|||
type: 'POST', |
|||
dataType: null, |
|||
data: JSON.stringify(input) |
|||
}, ajaxParams)); |
|||
}; |
|||
|
|||
})(); |
|||
|
|||
// controller volo.abp.account.dynamicClaims
|
|||
|
|||
(function(){ |
|||
|
|||
abp.utils.createNamespace(window, 'volo.abp.account.dynamicClaims'); |
|||
|
|||
volo.abp.account.dynamicClaims.refresh = function(ajaxParams) { |
|||
return abp.ajax($.extend(true, { |
|||
url: abp.appPath + 'api/account/dynamic-claims/refresh', |
|||
type: 'POST', |
|||
dataType: null |
|||
}, ajaxParams)); |
|||
}; |
|||
|
|||
})(); |
|||
|
|||
// controller volo.abp.account.profile
|
|||
|
|||
(function(){ |
|||
|
|||
abp.utils.createNamespace(window, 'volo.abp.account.profile'); |
|||
|
|||
volo.abp.account.profile.get = function(ajaxParams) { |
|||
return abp.ajax($.extend(true, { |
|||
url: abp.appPath + 'api/account/my-profile', |
|||
type: 'GET' |
|||
}, ajaxParams)); |
|||
}; |
|||
|
|||
volo.abp.account.profile.update = function(input, ajaxParams) { |
|||
return abp.ajax($.extend(true, { |
|||
url: abp.appPath + 'api/account/my-profile', |
|||
type: 'PUT', |
|||
data: JSON.stringify(input) |
|||
}, ajaxParams)); |
|||
}; |
|||
|
|||
volo.abp.account.profile.changePassword = function(input, ajaxParams) { |
|||
return abp.ajax($.extend(true, { |
|||
url: abp.appPath + 'api/account/my-profile/change-password', |
|||
type: 'POST', |
|||
dataType: null, |
|||
data: JSON.stringify(input) |
|||
}, ajaxParams)); |
|||
}; |
|||
|
|||
})(); |
|||
|
|||
})(); |
|||
|
|||
|
|||
@ -0,0 +1,29 @@ |
|||
using LINGYUN.Abp.Gdpr.Localization; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.UI.Navigation; |
|||
|
|||
namespace LINGYUN.Abp.Gdpr.Web; |
|||
|
|||
public class AbpGdprUserMenuContributor : IMenuContributor |
|||
{ |
|||
public virtual Task ConfigureMenuAsync(MenuConfigurationContext context) |
|||
{ |
|||
if (context.Menu.Name != StandardMenus.User) |
|||
{ |
|||
return Task.CompletedTask; |
|||
} |
|||
|
|||
|
|||
var gdprResource = context.GetLocalizer<GdprResource>(); |
|||
|
|||
context.Menu.AddItem( |
|||
new ApplicationMenuItem( |
|||
"Account.Delete", |
|||
gdprResource["DeletePersonalAccount"], |
|||
url: "~/Account/Delete", |
|||
icon: "fa fa-remove", |
|||
order: int.MaxValue - 999)); |
|||
|
|||
return Task.CompletedTask; |
|||
} |
|||
} |
|||
@ -0,0 +1,88 @@ |
|||
using LINGYUN.Abp.Gdpr.Localization; |
|||
using LINGYUN.Abp.Gdpr.Web.Pages.Account; |
|||
using LINGYUN.Abp.Gdpr.Web.Pages.Account.Components.ProfileManagementGroup.Gdpr; |
|||
using LINGYUN.Abp.Gdpr.Web.ProfileManagement; |
|||
using Microsoft.Extensions.DependencyInjection; |
|||
using Volo.Abp.Account.Web; |
|||
using Volo.Abp.Account.Web.Pages.Account; |
|||
using Volo.Abp.Account.Web.ProfileManagement; |
|||
using Volo.Abp.AspNetCore.Mvc.Localization; |
|||
using Volo.Abp.AspNetCore.Mvc.UI.Bundling; |
|||
using Volo.Abp.AutoMapper; |
|||
using Volo.Abp.Http.ProxyScripting.Generators.JQuery; |
|||
using Volo.Abp.Modularity; |
|||
using Volo.Abp.UI.Navigation; |
|||
using Volo.Abp.VirtualFileSystem; |
|||
|
|||
namespace LINGYUN.Abp.Gdpr.Web; |
|||
|
|||
[DependsOn( |
|||
typeof(AbpAccountWebModule), |
|||
typeof(AbpGdprApplicationContractsModule))] |
|||
public class AbpGdprWebModule : AbpModule |
|||
{ |
|||
public override void PreConfigureServices(ServiceConfigurationContext context) |
|||
{ |
|||
context.Services.PreConfigure<AbpMvcDataAnnotationsLocalizationOptions>(options => |
|||
{ |
|||
options.AddAssemblyResource(typeof(GdprResource), typeof(AbpGdprWebModule).Assembly); |
|||
}); |
|||
|
|||
PreConfigure<IMvcBuilder>(mvcBuilder => |
|||
{ |
|||
mvcBuilder.AddApplicationPartIfNotExists(typeof(AbpGdprWebModule).Assembly); |
|||
}); |
|||
} |
|||
|
|||
public override void ConfigureServices(ServiceConfigurationContext context) |
|||
{ |
|||
Configure<AbpVirtualFileSystemOptions>(options => |
|||
{ |
|||
options.FileSets.AddEmbedded<AbpGdprWebModule>(); |
|||
}); |
|||
|
|||
Configure<AbpNavigationOptions>(options => |
|||
{ |
|||
options.MenuContributors.Add(new AbpGdprUserMenuContributor()); |
|||
}); |
|||
|
|||
ConfigureProfileManagementPage(); |
|||
|
|||
context.Services.AddAutoMapperObjectMapper<AbpGdprWebModule>(); |
|||
Configure<AbpAutoMapperOptions>(options => |
|||
{ |
|||
options.AddMaps<AbpGdprWebModule>(validate: true); |
|||
}); |
|||
|
|||
Configure<DynamicJavaScriptProxyOptions>(options => |
|||
{ |
|||
options.DisableModule(GdprRemoteServiceConsts.ModuleName); |
|||
}); |
|||
} |
|||
|
|||
private void ConfigureProfileManagementPage() |
|||
{ |
|||
Configure<ProfileManagementPageOptions>(options => |
|||
{ |
|||
options.Contributors.Add(new GdprManagementPageContributor()); |
|||
}); |
|||
|
|||
Configure<AbpBundlingOptions>(options => |
|||
{ |
|||
options.ScriptBundles |
|||
.Configure(typeof(ManageModel).FullName, |
|||
configuration => |
|||
{ |
|||
configuration.AddFiles("/client-proxies/gdpr-proxy.js"); |
|||
configuration.AddFiles("/Pages/Account/Components/ProfileManagementGroup/Gdpr/Index.js"); |
|||
}); |
|||
options.ScriptBundles |
|||
.Configure(typeof(DeleteModel).FullName, |
|||
configuration => |
|||
{ |
|||
configuration.AddFiles("/client-proxies/gdpr-proxy.js"); |
|||
configuration.AddFiles("/Pages/Account/Delete.js"); |
|||
}); |
|||
}); |
|||
} |
|||
} |
|||
@ -0,0 +1,3 @@ |
|||
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd"> |
|||
<ConfigureAwait ContinueOnCapturedContext="false" /> |
|||
</Weavers> |
|||
@ -0,0 +1,30 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> |
|||
<!-- This file was generated by Fody. Manual changes to this file will be lost when your project is rebuilt. --> |
|||
<xs:element name="Weavers"> |
|||
<xs:complexType> |
|||
<xs:all> |
|||
<xs:element name="ConfigureAwait" minOccurs="0" maxOccurs="1"> |
|||
<xs:complexType> |
|||
<xs:attribute name="ContinueOnCapturedContext" type="xs:boolean" /> |
|||
</xs:complexType> |
|||
</xs:element> |
|||
</xs:all> |
|||
<xs:attribute name="VerifyAssembly" type="xs:boolean"> |
|||
<xs:annotation> |
|||
<xs:documentation>'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.</xs:documentation> |
|||
</xs:annotation> |
|||
</xs:attribute> |
|||
<xs:attribute name="VerifyIgnoreCodes" type="xs:string"> |
|||
<xs:annotation> |
|||
<xs:documentation>A comma-separated list of error codes that can be safely ignored in assembly verification.</xs:documentation> |
|||
</xs:annotation> |
|||
</xs:attribute> |
|||
<xs:attribute name="GenerateXsd" type="xs:boolean"> |
|||
<xs:annotation> |
|||
<xs:documentation>'false' to turn off automatic generation of the XML Schema file.</xs:documentation> |
|||
</xs:annotation> |
|||
</xs:attribute> |
|||
</xs:complexType> |
|||
</xs:element> |
|||
</xs:schema> |
|||
@ -0,0 +1,39 @@ |
|||
<Project Sdk="Microsoft.NET.Sdk.Web"> |
|||
|
|||
<Import Project="..\..\..\..\configureawait.props" /> |
|||
<Import Project="..\..\..\..\common.props" /> |
|||
|
|||
<PropertyGroup> |
|||
<TargetFramework>net9.0</TargetFramework> |
|||
<AssemblyName>LINGYUN.Abp.Gdpr.Web</AssemblyName> |
|||
<PackageId>LINGYUN.Abp.Gdpr.Web</PackageId> |
|||
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute> |
|||
<GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute> |
|||
<GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute> |
|||
<GenerateEmbeddedFilesManifest>true</GenerateEmbeddedFilesManifest> |
|||
<RootNamespace>LINGYUN.Abp.Gdpr.Web</RootNamespace> |
|||
<IsPackable>true</IsPackable> |
|||
<OutputType>Library</OutputType> |
|||
</PropertyGroup> |
|||
|
|||
<ItemGroup> |
|||
<EmbeddedResource Include="Modules\**\*.js" /> |
|||
<EmbeddedResource Include="Modules\**\*.css" /> |
|||
<EmbeddedResource Include="Pages\**\*.js" /> |
|||
<EmbeddedResource Include="Pages\**\*.css" /> |
|||
<EmbeddedResource Include="wwwroot\**\*.js" /> |
|||
<EmbeddedResource Include="wwwroot\**\*.css" /> |
|||
<Content Remove="Modules\**\*.js" /> |
|||
<Content Remove="Modules\**\*.css" /> |
|||
</ItemGroup> |
|||
|
|||
<ItemGroup> |
|||
<PackageReference Include="Volo.Abp.Account.Web" /> |
|||
<PackageReference Include="Microsoft.Extensions.FileProviders.Embedded" /> |
|||
</ItemGroup> |
|||
|
|||
<ItemGroup> |
|||
<ProjectReference Include="..\LINGYUN.Abp.Gdpr.Application.Contracts\LINGYUN.Abp.Gdpr.Application.Contracts.csproj" /> |
|||
</ItemGroup> |
|||
|
|||
</Project> |
|||
@ -0,0 +1,19 @@ |
|||
using Microsoft.AspNetCore.Mvc; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.AspNetCore.Mvc; |
|||
|
|||
namespace LINGYUN.Abp.Gdpr.Web.Pages.Account.Components.ProfileManagementGroup.Gdpr; |
|||
|
|||
public class AccountProfileGdprManagementGroupViewComponent : AbpViewComponent |
|||
{ |
|||
public AccountProfileGdprManagementGroupViewComponent() |
|||
{ |
|||
} |
|||
|
|||
public async virtual Task<IViewComponentResult> InvokeAsync() |
|||
{ |
|||
await Task.CompletedTask; |
|||
|
|||
return View("~/Pages/Account/Components/ProfileManagementGroup/Gdpr/Index.cshtml"); |
|||
} |
|||
} |
|||
@ -0,0 +1,31 @@ |
|||
@using LINGYUN.Abp.Gdpr.Web.Pages.Account.Components.ProfileManagementGroup.Gdpr |
|||
@using Microsoft.AspNetCore.Mvc.Localization |
|||
@using LINGYUN.Abp.Gdpr.Localization |
|||
@using Volo.Abp.Localization |
|||
|
|||
@inject IHtmlLocalizer<GdprResource> L |
|||
|
|||
<abp-card> |
|||
<abp-card-header> |
|||
<abp-row> |
|||
<abp-column size-md="_6"> |
|||
<abp-card-title>@L["PersonalData"]</abp-card-title> |
|||
</abp-column> |
|||
<abp-column size-md="_6" class="text-right"> |
|||
<abp-button-group> |
|||
<abp-button id="RequestPersonalDataButton" |
|||
text="@L["RequestPersonalData"].Value" |
|||
icon="id-card" |
|||
button-type="Primary" /> |
|||
<abp-button id="DeletePersonalDataButton" |
|||
text="@L["DeletePersonalData"].Value" |
|||
icon="remove" |
|||
button-type="Outline_Danger" /> |
|||
</abp-button-group> |
|||
</abp-column> |
|||
</abp-row> |
|||
</abp-card-header> |
|||
<abp-card-body> |
|||
<abp-table striped-rows="true" id="PersonalDataTable"></abp-table> |
|||
</abp-card-body> |
|||
</abp-card> |
|||
@ -0,0 +1,108 @@ |
|||
$(function () { |
|||
var ul = abp.localization.getResource('AbpUi'); |
|||
var gl = abp.localization.getResource('AbpGdpr'); |
|||
|
|||
var dataTable = $('#PersonalDataTable').DataTable( |
|||
abp.libs.datatables.normalizeConfiguration({ |
|||
serverSide: true, |
|||
paging: true, |
|||
searching: false, |
|||
scrollX: true, |
|||
ajax: abp.libs.datatables.createAjax(labp.gdpr.gdprRequest.getList), |
|||
columnDefs: [ |
|||
{ |
|||
title: ul('Actions'), |
|||
rowAction: { |
|||
items: |
|||
[ |
|||
{ |
|||
text: gl('Download'), |
|||
visible: function (data) { |
|||
const now = luxon.DateTime.now(); |
|||
const readyTime = luxon.DateTime.fromISO(data.readyTime, { |
|||
locale: abp.localization.currentCulture.name |
|||
}); |
|||
return now >= readyTime; |
|||
}, |
|||
action: function (data) { |
|||
var downloadWindow = window.open( |
|||
abp.appPath + 'api/gdpr/requests/personal-data/download/' + data.record.id + '', |
|||
"_blank" |
|||
); |
|||
downloadWindow.focus(); |
|||
} |
|||
}, |
|||
{ |
|||
text: ul('Delete'), |
|||
confirmMessage: function () { |
|||
return ul('ItemWillBeDeletedMessage'); |
|||
}, |
|||
action: function (data) { |
|||
labp.gdpr.gdprRequest |
|||
.delete(data.record.id) |
|||
.then(function () { |
|||
abp.notify.info( |
|||
ul('DeletedSuccessfully') |
|||
); |
|||
dataTable.ajax.reload(); |
|||
}); |
|||
} |
|||
} |
|||
] |
|||
} |
|||
}, |
|||
{ |
|||
title: gl('DisplayName:ReadyTime'), |
|||
data: "readyTime", |
|||
render: function (data) { |
|||
return luxon |
|||
.DateTime |
|||
.fromISO(data, { |
|||
locale: abp.localization.currentCulture.name |
|||
}).toLocaleString(luxon.DateTime.DATETIME_FULL_WITH_SECONDS); |
|||
} |
|||
}, |
|||
{ |
|||
title: gl('DisplayName:CreationTime'), |
|||
data: "creationTime", |
|||
render: function (data) { |
|||
return luxon |
|||
.DateTime |
|||
.fromISO(data, { |
|||
locale: abp.localization.currentCulture.name |
|||
}).toLocaleString(luxon.DateTime.DATETIME_FULL_WITH_SECONDS); |
|||
} |
|||
}] |
|||
}) |
|||
); |
|||
|
|||
$('#RequestPersonalDataButton').click(function (e) { |
|||
e.preventDefault(); |
|||
labp.gdpr.gdprRequest |
|||
.preparePersonalData() |
|||
.then(function () { |
|||
abp.notify.success( |
|||
gl('PersonalDataPrepareRequestReceived') |
|||
); |
|||
dataTable.ajax.reload(); |
|||
}); |
|||
}); |
|||
$('#DeletePersonalDataButton').click(function (e) { |
|||
e.preventDefault(); |
|||
abp.message.confirm( |
|||
gl('DeletePersonalDataWarning'), |
|||
function (confirm) { |
|||
if (confirm) { |
|||
labp.gdpr.gdprRequest |
|||
.deletePersonalData() |
|||
.then(function () { |
|||
abp.notify.success( |
|||
gl('PersonalDataDeleteRequestReceived') |
|||
); |
|||
dataTable.ajax.reload(); |
|||
}); |
|||
} |
|||
} |
|||
); |
|||
}); |
|||
}); |
|||
@ -0,0 +1,38 @@ |
|||
@page |
|||
@using Microsoft.AspNetCore.Mvc.Localization |
|||
@using Volo.Abp.Account.Localization |
|||
@using LINGYUN.Abp.Gdpr.Localization |
|||
@using LINGYUN.Abp.Gdpr.Web.Pages.Account |
|||
@using Volo.Abp.AspNetCore.Mvc.UI.Theming |
|||
@inject IThemeManager ThemeManager |
|||
@inject IHtmlLocalizer<GdprResource> L |
|||
@inject IHtmlLocalizer<AccountResource> AL |
|||
@model DeleteModel |
|||
@{ |
|||
Layout = ThemeManager.CurrentTheme.GetApplicationLayout(); |
|||
} |
|||
@section scripts { |
|||
<abp-script-bundle name="@typeof(DeleteModel).FullName" /> |
|||
} |
|||
|
|||
@if (!Model.ReturnUrl.IsNullOrWhiteSpace()) |
|||
{ |
|||
<abp-row class="mb-2"> |
|||
<abp-column> |
|||
<a class="btn btn-primary" href="@Model.ReturnUrl"> |
|||
<i class="fa fa-chevron-left me-2"></i>@AL["ReturnToApplication"] |
|||
</a> |
|||
</abp-column> |
|||
</abp-row> |
|||
} |
|||
|
|||
<div id="ProfileManagementWrapper"> |
|||
<abp-card> |
|||
<abp-card-header> |
|||
<abp-button id="DeletePersonalAccountButton" |
|||
text="@L["DeletePersonalAccount"].Value" |
|||
icon="remove" |
|||
button-type="Outline_Danger" /> |
|||
</abp-card-header> |
|||
</abp-card> |
|||
</div> |
|||
@ -0,0 +1,38 @@ |
|||
using Microsoft.AspNetCore.Http.Extensions; |
|||
using Microsoft.AspNetCore.Mvc; |
|||
using System; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.Account.Web.Pages.Account; |
|||
|
|||
namespace LINGYUN.Abp.Gdpr.Web.Pages.Account; |
|||
|
|||
public class DeleteModel : AccountPageModel |
|||
{ |
|||
[HiddenInput] |
|||
[BindProperty(SupportsGet = true)] |
|||
public string ReturnUrl { get; set; } |
|||
|
|||
public DeleteModel() |
|||
{ |
|||
} |
|||
|
|||
public virtual async Task<IActionResult> OnGetAsync() |
|||
{ |
|||
if (ReturnUrl != null) |
|||
{ |
|||
if (!Url.IsLocalUrl(ReturnUrl) && |
|||
!ReturnUrl.StartsWith(UriHelper.BuildAbsolute(Request.Scheme, Request.Host, Request.PathBase).RemovePostFix("/")) && |
|||
!await AppUrlProvider.IsRedirectAllowedUrlAsync(ReturnUrl)) |
|||
{ |
|||
ReturnUrl = null; |
|||
} |
|||
} |
|||
|
|||
return Page(); |
|||
} |
|||
|
|||
public virtual Task<IActionResult> OnPostAsync() |
|||
{ |
|||
return Task.FromResult<IActionResult>(Page()); |
|||
} |
|||
} |
|||
@ -0,0 +1,22 @@ |
|||
$(function () { |
|||
var l = abp.localization.getResource('AbpGdpr'); |
|||
|
|||
$('#DeletePersonalAccountButton').click(function (e) { |
|||
e.preventDefault(); |
|||
abp.message.confirm( |
|||
l('DeletePersonalAccountWarning'), |
|||
function (confirm) { |
|||
if (confirm) { |
|||
labp.gdpr.gdprRequest |
|||
.deletePersonalAccount() |
|||
.then(function () { |
|||
abp.notify.success( |
|||
l('PersonalAccountDeleteRequestReceived') |
|||
); |
|||
$(location).attr('href', '/Account/Login'); |
|||
}); |
|||
} |
|||
} |
|||
); |
|||
}); |
|||
}); |
|||
@ -0,0 +1,4 @@ |
|||
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers |
|||
@addTagHelper *, Volo.Abp.AspNetCore.Mvc.UI |
|||
@addTagHelper *, Volo.Abp.AspNetCore.Mvc.UI.Bootstrap |
|||
@addTagHelper *, Volo.Abp.AspNetCore.Mvc.UI.Bundling |
|||
@ -0,0 +1,26 @@ |
|||
using LINGYUN.Abp.Gdpr.Localization; |
|||
using LINGYUN.Abp.Gdpr.Web.Pages.Account.Components.ProfileManagementGroup.Gdpr; |
|||
using Microsoft.Extensions.DependencyInjection; |
|||
using Microsoft.Extensions.Localization; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.Account.Web.ProfileManagement; |
|||
|
|||
namespace LINGYUN.Abp.Gdpr.Web.ProfileManagement; |
|||
|
|||
public class GdprManagementPageContributor : IProfileManagementPageContributor |
|||
{ |
|||
public virtual Task ConfigureAsync(ProfileManagementPageCreationContext context) |
|||
{ |
|||
var l = context.ServiceProvider.GetRequiredService<IStringLocalizer<GdprResource>>(); |
|||
|
|||
context.Groups.Add( |
|||
new ProfileManagementPageGroup( |
|||
"LINGYUN.Abp.Account.Gdpr", |
|||
l["PersonalData"], |
|||
typeof(AccountProfileGdprManagementGroupViewComponent) |
|||
) |
|||
); |
|||
|
|||
return Task.CompletedTask; |
|||
} |
|||
} |
|||
@ -0,0 +1,12 @@ |
|||
{ |
|||
"profiles": { |
|||
"LINGYUN.Abp.Gdpr.Web": { |
|||
"commandName": "Project", |
|||
"launchBrowser": true, |
|||
"environmentVariables": { |
|||
"ASPNETCORE_ENVIRONMENT": "Development" |
|||
}, |
|||
"applicationUrl": "https://localhost:64471;http://localhost:64472" |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,71 @@ |
|||
/* This file is automatically generated by ABP framework to use MVC Controllers from javascript. */ |
|||
|
|||
|
|||
// module gdpr
|
|||
|
|||
(function(){ |
|||
|
|||
// controller labp.gdpr.gdprRequest
|
|||
|
|||
(function(){ |
|||
|
|||
abp.utils.createNamespace(window, 'labp.gdpr.gdprRequest'); |
|||
|
|||
labp.gdpr.gdprRequest['delete'] = function(id, ajaxParams) { |
|||
return abp.ajax($.extend(true, { |
|||
url: abp.appPath + 'api/gdpr/requests/' + id + '', |
|||
type: 'DELETE', |
|||
dataType: null |
|||
}, ajaxParams)); |
|||
}; |
|||
|
|||
labp.gdpr.gdprRequest.deletePersonalAccount = function(ajaxParams) { |
|||
return abp.ajax($.extend(true, { |
|||
url: abp.appPath + 'api/gdpr/requests/personal-account', |
|||
type: 'DELETE', |
|||
dataType: null |
|||
}, ajaxParams)); |
|||
}; |
|||
|
|||
labp.gdpr.gdprRequest.deletePersonalData = function(ajaxParams) { |
|||
return abp.ajax($.extend(true, { |
|||
url: abp.appPath + 'api/gdpr/requests/personal-data', |
|||
type: 'DELETE', |
|||
dataType: null |
|||
}, ajaxParams)); |
|||
}; |
|||
|
|||
labp.gdpr.gdprRequest.get = function(id, ajaxParams) { |
|||
return abp.ajax($.extend(true, { |
|||
url: abp.appPath + 'api/gdpr/requests/' + id + '', |
|||
type: 'GET' |
|||
}, ajaxParams)); |
|||
}; |
|||
|
|||
labp.gdpr.gdprRequest.getList = function(input, ajaxParams) { |
|||
return abp.ajax($.extend(true, { |
|||
url: abp.appPath + 'api/gdpr/requests' + abp.utils.buildQueryString([{ name: 'creationTime', value: input.creationTime }, { name: 'readyTime', value: input.readyTime }, { name: 'sorting', value: input.sorting }, { name: 'skipCount', value: input.skipCount }, { name: 'maxResultCount', value: input.maxResultCount }]) + '', |
|||
type: 'GET' |
|||
}, ajaxParams)); |
|||
}; |
|||
|
|||
labp.gdpr.gdprRequest.downloadPersonalData = function(requestId, ajaxParams) { |
|||
return abp.ajax($.extend(true, { |
|||
url: abp.appPath + 'api/gdpr/requests/personal-data/download/' + requestId + '', |
|||
type: 'GET' |
|||
}, ajaxParams)); |
|||
}; |
|||
|
|||
labp.gdpr.gdprRequest.preparePersonalData = function(ajaxParams) { |
|||
return abp.ajax($.extend(true, { |
|||
url: abp.appPath + 'api/gdpr/requests/personal-data/prepare', |
|||
type: 'POST', |
|||
dataType: null |
|||
}, ajaxParams)); |
|||
}; |
|||
|
|||
})(); |
|||
|
|||
})(); |
|||
|
|||
|
|||
@ -1,4 +0,0 @@ |
|||
@page |
|||
@model LY.MicroService.AuthServer.Pages.Account.UseRecoveryCodeModel |
|||
@{ |
|||
} |
|||
@ -1,16 +0,0 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Threading.Tasks; |
|||
using Microsoft.AspNetCore.Mvc; |
|||
using Microsoft.AspNetCore.Mvc.RazorPages; |
|||
|
|||
namespace LY.MicroService.AuthServer.Pages.Account |
|||
{ |
|||
public class UseRecoveryCodeModel : PageModel |
|||
{ |
|||
public void OnGet() |
|||
{ |
|||
} |
|||
} |
|||
} |
|||
@ -1,11 +1,10 @@ |
|||
using Volo.Abp.AspNetCore.Mvc.UI.RazorPages; |
|||
|
|||
namespace LY.MicroService.AuthServer.Pages |
|||
namespace LY.MicroService.AuthServer.Pages; |
|||
|
|||
public class IndexModel : AbpPageModel |
|||
{ |
|||
public class IndexModel : AbpPageModel |
|||
public void OnGet() |
|||
{ |
|||
public void OnGet() |
|||
{ |
|||
} |
|||
} |
|||
} |
|||
@ -1,103 +0,0 @@ |
|||
@using Volo.Abp.Account.Localization |
|||
@using Volo.Abp.Users |
|||
@using Microsoft.AspNetCore.Mvc.Localization |
|||
@using Microsoft.Extensions.Localization |
|||
@using Volo.Abp.Account.Web.Pages.Account.Components.ProfileManagementGroup.PersonalInfo |
|||
@using Volo.Abp.AspNetCore.Mvc.UI.Theming |
|||
@using Volo.Abp.Data |
|||
@using Volo.Abp.Identity.Settings |
|||
@using Volo.Abp.Localization |
|||
@using Volo.Abp.Settings |
|||
@using Volo.Abp.ObjectExtending |
|||
@inject IHtmlLocalizer<AccountResource> L |
|||
@inject ICurrentUser CurrentUser |
|||
@inject ISettingProvider SettingManager |
|||
@inject IThemeManager ThemeManager |
|||
@inject IStringLocalizerFactory StringLocalizerFactory |
|||
@model Volo.Abp.Account.Web.Pages.Account.Components.ProfileManagementGroup.PersonalInfo.AccountProfilePersonalInfoManagementGroupViewComponent.PersonalInfoModel |
|||
@{ |
|||
var isUserNameUpdateEnabled = string.Equals(await SettingManager.GetOrNullAsync(IdentitySettingNames.User.IsUserNameUpdateEnabled), "true", |
|||
StringComparison.OrdinalIgnoreCase); |
|||
|
|||
var isEmailUpdateEnabled = string.Equals(await SettingManager.GetOrNullAsync(IdentitySettingNames.User.IsEmailUpdateEnabled), "true", |
|||
StringComparison.OrdinalIgnoreCase); |
|||
} |
|||
|
|||
<h4>@L["PersonalSettings"]</h4><hr/> |
|||
<form method="post" id="PersonalSettingsForm"> |
|||
|
|||
<input asp-for="ConcurrencyStamp" /> |
|||
|
|||
<abp-input asp-for="UserName" readonly="!isUserNameUpdateEnabled"/> |
|||
|
|||
<abp-row> |
|||
<abp-column size-md="_6"> |
|||
<abp-input asp-for="Name"/> |
|||
</abp-column> |
|||
<abp-column size-md="_6"> |
|||
<abp-input asp-for="Surname"/> |
|||
</abp-column> |
|||
</abp-row> |
|||
|
|||
<abp-row> |
|||
<abp-column size-md="_9"> |
|||
<abp-input asp-for="Email" readonly="!isEmailUpdateEnabled"/> |
|||
</abp-column> |
|||
<abp-column size-md="_3"> |
|||
|
|||
@if (CurrentUser.EmailVerified) |
|||
{ |
|||
<abp-button button-type="Success" text="@L["Confirmed"].Value"/> |
|||
} |
|||
else |
|||
{ |
|||
<a href="/Account/SendEmailConfirm">@L["Validation"].Value</a> |
|||
} |
|||
</abp-column> |
|||
</abp-row> |
|||
|
|||
<abp-input asp-for="PhoneNumber"/> |
|||
|
|||
@foreach (var propertyInfo in ObjectExtensionManager.Instance.GetProperties<AccountProfilePersonalInfoManagementGroupViewComponent.PersonalInfoModel>()) |
|||
{ |
|||
var isAllowed = propertyInfo.Configuration.GetOrDefault(IdentityModuleExtensionConsts.ConfigurationNames.AllowUserToEdit); |
|||
|
|||
if (isAllowed == null || !isAllowed.Equals(true)) |
|||
{ |
|||
continue; |
|||
} |
|||
|
|||
if (!propertyInfo.Name.EndsWith("_Text")) |
|||
{ |
|||
if (propertyInfo.Type.IsEnum || !propertyInfo.Lookup.Url.IsNullOrEmpty()) |
|||
{ |
|||
if (propertyInfo.Type.IsEnum) |
|||
{ |
|||
Model.ExtraProperties.ToEnum(propertyInfo.Name, propertyInfo.Type); |
|||
} |
|||
<abp-select asp-for="ExtraProperties[propertyInfo.Name]" |
|||
name="ExtraProperties.@propertyInfo.Name" |
|||
label="@propertyInfo.GetLocalizedDisplayName(StringLocalizerFactory)" |
|||
autocomplete-api-url="@propertyInfo.Lookup.Url" |
|||
autocomplete-selected-item-name="@Model.GetProperty(propertyInfo.Name + "_Text")" |
|||
autocomplete-selected-item-value="@Model.GetProperty(propertyInfo.Name)" |
|||
autocomplete-filter-param-name="@propertyInfo.Lookup.FilterParamName" |
|||
autocomplete-items-property-name="@propertyInfo.Lookup.ResultListPropertyName" |
|||
autocomplete-display-property-name="@propertyInfo.Lookup.DisplayPropertyName" |
|||
autocomplete-value-property-name="@propertyInfo.Lookup.ValuePropertyName"> |
|||
</abp-select> |
|||
} |
|||
else |
|||
{ |
|||
<abp-input type="@propertyInfo.GetInputType()" |
|||
asp-for="ExtraProperties[propertyInfo.Name]" |
|||
name="ExtraProperties.@propertyInfo.Name" |
|||
label="@propertyInfo.GetLocalizedDisplayName(StringLocalizerFactory)" |
|||
asp-format="@propertyInfo.GetInputFormatOrNull()" |
|||
value="@propertyInfo.GetInputValueOrNull(Model.GetProperty(propertyInfo.Name))" /> |
|||
} |
|||
} |
|||
} |
|||
|
|||
<abp-button type="submit" button-type="Primary" text="@L["Submit"].Value"/> |
|||
</form> |
|||
@ -1,28 +0,0 @@ |
|||
(function ($) { |
|||
$(function () { |
|||
var l = abp.localization.getResource("AbpAccount"); |
|||
|
|||
$('#PersonalSettingsForm').submit(function (e) { |
|||
e.preventDefault(); |
|||
|
|||
if (!$('#PersonalSettingsForm').valid()) { |
|||
return false; |
|||
} |
|||
|
|||
var input = $('#PersonalSettingsForm').serializeFormToObject(); |
|||
|
|||
volo.abp.account.profile.update(input).then(function (result) { |
|||
abp.notify.success(l('PersonalSettingsSaved')); |
|||
updateConcurrencyStamp(); |
|||
}); |
|||
}); |
|||
}); |
|||
|
|||
abp.event.on('passwordChanged', updateConcurrencyStamp); |
|||
|
|||
function updateConcurrencyStamp(){ |
|||
volo.abp.account.profile.get().then(function(profile){ |
|||
$("#ConcurrencyStamp").val(profile.concurrencyStamp); |
|||
}); |
|||
} |
|||
})(jQuery); |
|||
@ -1,17 +0,0 @@ |
|||
@page |
|||
@inject IHtmlLocalizer<AccountResource> L |
|||
@using Microsoft.AspNetCore.Mvc.Localization |
|||
@using Volo.Abp.Account.Localization |
|||
@model LY.MicroService.IdentityServer.Pages.Account.EmailConfirmModel |
|||
@inject Volo.Abp.AspNetCore.Mvc.UI.Layout.IPageLayout PageLayout |
|||
<div class="card mt-3 shadow-sm rounded"> |
|||
<div class="card-body p-5"> |
|||
<h4>@L["EmailConfirm"]</h4> |
|||
<form method="post"> |
|||
<abp-input asp-for="UserId" /> |
|||
<abp-input asp-for="ConfirmToken" /> |
|||
<a abp-button="Secondary" asp-page="./">@L["Cancel"]</a> |
|||
<abp-button type="submit" button-type="Primary">@L["Submit"]</abp-button> |
|||
</form> |
|||
</div> |
|||
</div> |
|||
@ -1,74 +0,0 @@ |
|||
using LINGYUN.Abp.Account; |
|||
using Microsoft.AspNetCore.Mvc; |
|||
using System; |
|||
using System.ComponentModel.DataAnnotations; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.Account.Localization; |
|||
using Volo.Abp.Account.Web.Pages.Account; |
|||
using Volo.Abp.Identity; |
|||
using Volo.Abp.Validation; |
|||
|
|||
namespace LY.MicroService.IdentityServer.Pages.Account |
|||
{ |
|||
public class EmailConfirmModel : AccountPageModel |
|||
{ |
|||
[Required] |
|||
[HiddenInput] |
|||
[BindProperty(SupportsGet = true)] |
|||
public Guid UserId { get; set; } |
|||
|
|||
[Required] |
|||
[HiddenInput] |
|||
[BindProperty(SupportsGet = true)] |
|||
public string ConfirmToken { get; set; } |
|||
|
|||
[HiddenInput] |
|||
[BindProperty(SupportsGet = true)] |
|||
public string ReturnUrl { get; set; } |
|||
|
|||
[HiddenInput] |
|||
[BindProperty(SupportsGet = true)] |
|||
public string ReturnUrlHash { get; set; } |
|||
|
|||
public IMyProfileAppService MyProfileAppService { get; set; } |
|||
|
|||
public EmailConfirmModel() |
|||
{ |
|||
LocalizationResourceType = typeof(AccountResource); |
|||
} |
|||
|
|||
public async virtual Task<IActionResult> OnPostAsync() |
|||
{ |
|||
try |
|||
{ |
|||
ValidateModel(); |
|||
|
|||
await MyProfileAppService.ConfirmEmailAsync( |
|||
new ConfirmEmailInput |
|||
{ |
|||
ConfirmToken = ConfirmToken, |
|||
}); |
|||
} |
|||
catch (AbpIdentityResultException e) |
|||
{ |
|||
if (!string.IsNullOrWhiteSpace(e.Message)) |
|||
{ |
|||
Alerts.Warning(GetLocalizeExceptionMessage(e)); |
|||
return Page(); |
|||
} |
|||
|
|||
throw; |
|||
} |
|||
catch (AbpValidationException) |
|||
{ |
|||
return Page(); |
|||
} |
|||
|
|||
return RedirectToPage("EmailConfirmConfirmation", new |
|||
{ |
|||
returnUrl = ReturnUrl, |
|||
returnUrlHash = ReturnUrlHash |
|||
}); |
|||
} |
|||
} |
|||
} |
|||
@ -1,13 +0,0 @@ |
|||
@page |
|||
@model LY.MicroService.IdentityServer.Pages.Account.EmailConfirmConfirmationModel |
|||
@inject Volo.Abp.AspNetCore.Mvc.UI.Layout.IPageLayout PageLayout |
|||
@using Microsoft.AspNetCore.Mvc.Localization |
|||
@using Volo.Abp.Account.Localization |
|||
@inject IHtmlLocalizer<AccountResource> L |
|||
<div class="card mt-3 shadow-sm rounded"> |
|||
<div class="card-body p-5"> |
|||
<h4>@L["EmailConfirm"]</h4> |
|||
<p>@L["YourEmailIsSuccessfullyConfirm"]</p> |
|||
<a abp-button="Primary" href="@Url.Content(Model.ReturnUrl)">@L["GoToTheApplication"]</a> |
|||
</div> |
|||
</div> |
|||
@ -1,17 +0,0 @@ |
|||
using Microsoft.AspNetCore.Authorization; |
|||
using Microsoft.AspNetCore.Mvc; |
|||
using System; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.Account.Web.Pages.Account; |
|||
|
|||
namespace LY.MicroService.IdentityServer.Pages.Account; |
|||
|
|||
[AllowAnonymous] |
|||
public class EmailConfirmConfirmationModel : AccountPageModel |
|||
{ |
|||
[BindProperty(SupportsGet = true)] |
|||
public string ReturnUrl { get; set; } |
|||
|
|||
[BindProperty(SupportsGet = true)] |
|||
public string ReturnUrlHash { get; set; } |
|||
} |
|||
@ -1,26 +0,0 @@ |
|||
@page |
|||
@using Microsoft.AspNetCore.Mvc.Localization |
|||
@using Volo.Abp.Account.Localization |
|||
@model LY.MicroService.IdentityServer.Pages.Account.SendCodeModel |
|||
@inject IHtmlLocalizer<AccountResource> L |
|||
|
|||
<div class="card mt-3 shadow-sm rounded"> |
|||
<div class="card-body p-5"> |
|||
<h4>@L["TwoFactor"]</h4> |
|||
<form method="post" class="mt-4"> |
|||
<abp-input asp-for="RememberMe" /> |
|||
<input asp-for="ReturnUrl" /> |
|||
<input asp-for="ReturnUrlHash" /> |
|||
<div class="form-group"> |
|||
<abp-select asp-for="Input.SelectedProvider" label="@L["SelectedProvider"].Value" asp-items="@Model.Providers"></abp-select> |
|||
</div> |
|||
<div class="d-grid gap-2"> |
|||
<abp-button type="submit" button-type="Primary" class="mt-2 mb-3">@L["SendVerifyCode"]</abp-button> |
|||
</div> |
|||
<a asp-page="./Login" asp-all-route-data="@(new Dictionary<string, string> {{"returnUrl", Model.ReturnUrl}, {"returnUrlHash", Model.ReturnUrlHash}})"> |
|||
<i class="fa fa-long-arrow-left"></i> @L["Login"] |
|||
</a> |
|||
</form> |
|||
</div> |
|||
</div> |
|||
|
|||
@ -1,128 +0,0 @@ |
|||
using LINGYUN.Abp.Account.Emailing; |
|||
using LINGYUN.Abp.Identity.Settings; |
|||
using Microsoft.AspNetCore.Mvc; |
|||
using Microsoft.AspNetCore.Mvc.Rendering; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp; |
|||
using Volo.Abp.Account.Localization; |
|||
using Volo.Abp.Account.Web.Pages.Account; |
|||
using Volo.Abp.Sms; |
|||
|
|||
namespace LY.MicroService.IdentityServer.Pages.Account |
|||
{ |
|||
public class SendCodeModel : AccountPageModel |
|||
{ |
|||
[BindProperty] |
|||
public SendCodeInputModel Input { get; set; } |
|||
|
|||
[HiddenInput] |
|||
[BindProperty(SupportsGet = true)] |
|||
public string ReturnUrl { get; set; } |
|||
|
|||
[HiddenInput] |
|||
[BindProperty(SupportsGet = true)] |
|||
public string ReturnUrlHash { get; set; } |
|||
|
|||
[HiddenInput] |
|||
[BindProperty(SupportsGet = true)] |
|||
public bool RememberMe { get; set; } |
|||
|
|||
public IEnumerable<SelectListItem> Providers { get; set; } |
|||
|
|||
protected ISmsSender SmsSender { get; } |
|||
|
|||
protected IAccountEmailVerifySender AccountEmailVerifySender { get; } |
|||
|
|||
public SendCodeModel( |
|||
ISmsSender smsSender, |
|||
IAccountEmailVerifySender accountEmailVerifySender) |
|||
{ |
|||
SmsSender = smsSender; |
|||
AccountEmailVerifySender = accountEmailVerifySender; |
|||
|
|||
LocalizationResourceType = typeof(AccountResource); |
|||
} |
|||
|
|||
public async virtual Task<IActionResult> OnGetAsync() |
|||
{ |
|||
Input = new SendCodeInputModel(); |
|||
|
|||
var user = await SignInManager.GetTwoFactorAuthenticationUserAsync(); |
|||
if (user == null) |
|||
{ |
|||
// 双因素信息验证失败,一般都是超时了或者用户信息变更
|
|||
Alerts.Warning(L["TwoFactorAuthenticationInvaidUser"]); |
|||
return Page(); |
|||
} |
|||
var userFactors = await UserManager.GetValidTwoFactorProvidersAsync(user); |
|||
Providers = userFactors.Select(purpose => new SelectListItem { Text = purpose, Value = purpose }).ToList(); |
|||
|
|||
return Page(); |
|||
} |
|||
|
|||
public async virtual Task<IActionResult> OnPostAsync() |
|||
{ |
|||
var user = await SignInManager.GetTwoFactorAuthenticationUserAsync(); |
|||
if (user == null) |
|||
{ |
|||
Alerts.Warning(L["TwoFactorAuthenticationInvaidUser"]); |
|||
return Page(); |
|||
} |
|||
|
|||
if (Input.SelectedProvider == "Authenticator") |
|||
{ |
|||
// 用户通过邮件/短信链接进入授权页面
|
|||
return RedirectToPage("VerifyAuthenticatorCode", new |
|||
{ |
|||
returnUrl = ReturnUrl, |
|||
returnUrlHash = ReturnUrlHash, |
|||
rememberMe = RememberMe |
|||
}); |
|||
} |
|||
// 生成验证码
|
|||
var code = await UserManager.GenerateTwoFactorTokenAsync(user, Input.SelectedProvider); |
|||
if (string.IsNullOrWhiteSpace(code)) |
|||
{ |
|||
Alerts.Warning(L["InvaidGenerateTwoFactorToken"]); |
|||
return Page(); |
|||
} |
|||
|
|||
if (Input.SelectedProvider == "Email") |
|||
{ |
|||
await AccountEmailVerifySender |
|||
.SendMailLoginVerifyCodeAsync( |
|||
code, |
|||
user.UserName, |
|||
user.Email); |
|||
} |
|||
else if (Input.SelectedProvider == "Phone") |
|||
{ |
|||
var phoneNumber = await UserManager.GetPhoneNumberAsync(user); |
|||
var templateCode = await SettingProvider.GetOrNullAsync(IdentitySettingNames.User.SmsUserSignin); |
|||
Check.NotNullOrWhiteSpace(templateCode, nameof(IdentitySettingNames.User.SmsUserSignin)); |
|||
|
|||
// TODO: 以后扩展短信模板发送
|
|||
var smsMessage = new SmsMessage(phoneNumber, code); |
|||
smsMessage.Properties.Add("code", code); |
|||
smsMessage.Properties.Add("TemplateCode", templateCode); |
|||
|
|||
await SmsSender.SendAsync(smsMessage); |
|||
} |
|||
|
|||
return RedirectToPage("VerifyCode", new |
|||
{ |
|||
provider = Input.SelectedProvider, |
|||
returnUrl = ReturnUrl, |
|||
returnUrlHash = ReturnUrlHash, |
|||
rememberMe = RememberMe |
|||
}); |
|||
} |
|||
} |
|||
|
|||
public class SendCodeInputModel |
|||
{ |
|||
public string SelectedProvider { get; set; } |
|||
} |
|||
} |
|||
@ -1,16 +0,0 @@ |
|||
@page |
|||
@inject IHtmlLocalizer<AccountResource> L |
|||
@using Microsoft.AspNetCore.Mvc.Localization |
|||
@using Volo.Abp.Account.Localization |
|||
@model LY.MicroService.IdentityServer.Pages.Account.SendEmailConfirmModel |
|||
@inject Volo.Abp.AspNetCore.Mvc.UI.Layout.IPageLayout PageLayout |
|||
<div class="card mt-3 shadow-sm rounded"> |
|||
<div class="card-body p-5"> |
|||
<h4>@L["EmailConfirm"]</h4> |
|||
<form method="post"> |
|||
<abp-input asp-for="Email" readonly="true" /> |
|||
<a abp-button="Secondary" asp-page="./Login">@L["Cancel"]</a> |
|||
<abp-button type="submit" button-type="Primary" text="@L["ClickToValidation"].Value"/> |
|||
</form> |
|||
</div> |
|||
</div> |
|||
@ -1,75 +0,0 @@ |
|||
using LINGYUN.Abp.Account; |
|||
using Microsoft.AspNetCore.Mvc; |
|||
using System.ComponentModel.DataAnnotations; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.Account.Localization; |
|||
using Volo.Abp.Account.Web.Pages.Account; |
|||
using Volo.Abp.Identity; |
|||
using Volo.Abp.Validation; |
|||
|
|||
namespace LY.MicroService.IdentityServer.Pages.Account |
|||
{ |
|||
public class SendEmailConfirmModel : AccountPageModel |
|||
{ |
|||
[BindProperty(SupportsGet = true)] |
|||
public string Email { get; set; } |
|||
|
|||
[HiddenInput] |
|||
[BindProperty(SupportsGet = true)] |
|||
public string ReturnUrl { get; set; } |
|||
|
|||
[HiddenInput] |
|||
[BindProperty(SupportsGet = true)] |
|||
public string ReturnUrlHash { get; set; } |
|||
|
|||
public IMyProfileAppService MyProfileAppService { get; set; } |
|||
|
|||
public SendEmailConfirmModel() |
|||
{ |
|||
LocalizationResourceType = typeof(AccountResource); |
|||
} |
|||
|
|||
public virtual Task<IActionResult> OnGetAsync() |
|||
{ |
|||
Email = CurrentUser.Email; |
|||
|
|||
return Task.FromResult<IActionResult>(Page()); |
|||
} |
|||
|
|||
public async virtual Task<IActionResult> OnPostAsync() |
|||
{ |
|||
try |
|||
{ |
|||
ValidateModel(); |
|||
|
|||
await MyProfileAppService.SendEmailConfirmLinkAsync( |
|||
new SendEmailConfirmCodeDto |
|||
{ |
|||
Email = Email, |
|||
AppName = "MVC", |
|||
ReturnUrl = ReturnUrl, |
|||
ReturnUrlHash = ReturnUrlHash |
|||
}); |
|||
} |
|||
catch (AbpIdentityResultException e) |
|||
{ |
|||
if (!string.IsNullOrWhiteSpace(e.Message)) |
|||
{ |
|||
Alerts.Warning(GetLocalizeExceptionMessage(e)); |
|||
return Page(); |
|||
} |
|||
|
|||
throw; |
|||
} |
|||
catch (AbpValidationException) |
|||
{ |
|||
return Page(); |
|||
} |
|||
|
|||
return RedirectToPage("~/Account/Manage", new |
|||
{ |
|||
returnUrl = ReturnUrl |
|||
}); |
|||
} |
|||
} |
|||
} |
|||
@ -1,4 +0,0 @@ |
|||
@page |
|||
@model LY.MicroService.IdentityServer.Pages.Account.UseRecoveryCodeModel |
|||
@{ |
|||
} |
|||
@ -1,16 +0,0 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Threading.Tasks; |
|||
using Microsoft.AspNetCore.Mvc; |
|||
using Microsoft.AspNetCore.Mvc.RazorPages; |
|||
|
|||
namespace LY.MicroService.IdentityServer.Pages.Account |
|||
{ |
|||
public class UseRecoveryCodeModel : PageModel |
|||
{ |
|||
public void OnGet() |
|||
{ |
|||
} |
|||
} |
|||
} |
|||
@ -1,26 +0,0 @@ |
|||
@page |
|||
@using Microsoft.AspNetCore.Mvc.Localization |
|||
@using Volo.Abp.Account.Localization |
|||
@model LY.MicroService.IdentityServer.Pages.Account.VerifyAuthenticatorCodeModel |
|||
@inject IHtmlLocalizer<AccountResource> L |
|||
<div class="card mt-3 shadow-sm rounded"> |
|||
<div class="card-body p-5"> |
|||
<form method="post" class="mt-4"> |
|||
<input asp-for="RememberMe" /> |
|||
<input asp-for="ReturnUrlHash" /> |
|||
<div class="form-group"> |
|||
<label asp-for="Input.VerifyCode"></label> |
|||
<input asp-for="Input.VerifyCode" class="form-control" /> |
|||
<span asp-validation-for="Input.VerifyCode" class="text-danger"></span> |
|||
</div> |
|||
<div class="form-group"> |
|||
<label asp-for="RememberBrowser"></label> |
|||
<abp-input asp-for="RememberBrowser" /> |
|||
</div> |
|||
<abp-button type="submit" button-type="Primary" class="btn-block btn-lg mt-3">@L["VerifyAuthenticatorCode"]</abp-button> |
|||
<a asp-page="./Login" asp-all-route-data="@(new Dictionary<string, string> {{"returnUrl", Model.ReturnUrl}, {"returnUrlHash", Model.ReturnUrlHash}})"> |
|||
<i class="fa fa-long-arrow-left"></i> @L["Login"] |
|||
</a> |
|||
</form> |
|||
</div> |
|||
</div> |
|||
@ -1,61 +0,0 @@ |
|||
using Microsoft.AspNetCore.Mvc; |
|||
using Microsoft.Extensions.Logging; |
|||
using System.ComponentModel.DataAnnotations; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.Account.Web.Pages.Account; |
|||
|
|||
namespace LY.MicroService.IdentityServer.Pages.Account |
|||
{ |
|||
public class VerifyAuthenticatorCodeModel : AccountPageModel |
|||
{ |
|||
[BindProperty] |
|||
public VerifyAuthenticatorCodeInputModel Input { get; set; } |
|||
|
|||
[HiddenInput] |
|||
[BindProperty(SupportsGet = true)] |
|||
public string ReturnUrl { get; set; } |
|||
|
|||
[HiddenInput] |
|||
[BindProperty(SupportsGet = true)] |
|||
public string ReturnUrlHash { get; set; } |
|||
|
|||
[BindProperty(SupportsGet = true)] |
|||
public bool RememberBrowser { get; set; } |
|||
|
|||
[HiddenInput] |
|||
public bool RememberMe { get; set; } |
|||
|
|||
public virtual IActionResult OnGet() |
|||
{ |
|||
Input = new VerifyAuthenticatorCodeInputModel(); |
|||
|
|||
return Page(); |
|||
} |
|||
|
|||
public async virtual Task<IActionResult> OnPostAsync() |
|||
{ |
|||
var result = await SignInManager.TwoFactorAuthenticatorSignInAsync(Input.VerifyCode, RememberMe, RememberBrowser); |
|||
if (result.Succeeded) |
|||
{ |
|||
return await RedirectSafelyAsync(ReturnUrl, ReturnUrlHash); |
|||
} |
|||
if (result.IsLockedOut) |
|||
{ |
|||
Logger.LogWarning(7, "User account locked out."); |
|||
Alerts.Warning(L["UserLockedOutMessage"]); |
|||
return Page(); |
|||
} |
|||
else |
|||
{ |
|||
Alerts.Danger(L["TwoFactorAuthenticationInvaidUser"]);// TODO: ¸ü¶à״̬ÂëµÄ½â¶Á
|
|||
return Page(); |
|||
} |
|||
} |
|||
} |
|||
|
|||
public class VerifyAuthenticatorCodeInputModel |
|||
{ |
|||
[Required] |
|||
public string VerifyCode { get; set; } |
|||
} |
|||
} |
|||
@ -1,29 +0,0 @@ |
|||
@page |
|||
@inject IHtmlLocalizer<AccountResource> L |
|||
@using Microsoft.AspNetCore.Mvc.Localization |
|||
@using Volo.Abp.Account.Localization |
|||
@model LY.MicroService.IdentityServer.Pages.Account.VerifyCodeModel |
|||
<div class="card mt-3 shadow-sm rounded"> |
|||
<div class="card-body p-5"> |
|||
<form method="post" class="mt-4"> |
|||
<input asp-for="Provider" /> |
|||
<input asp-for="ReturnUrl" /> |
|||
<input asp-for="ReturnUrlHash" /> |
|||
<input asp-for="RememberMe" /> |
|||
<div class="form-group"> |
|||
<abp-input asp-for="Input.VerifyCode" label="@L["VerifyCode"].Value" class="form-control" /> |
|||
</div> |
|||
<abp-row> |
|||
<abp-column> |
|||
<abp-input asp-for="Input.RememberBrowser" label="@L["RememberBrowser"].Value" /> |
|||
</abp-column> |
|||
</abp-row> |
|||
<div class="d-grid gap-2"> |
|||
<abp-button type="submit" button-type="Primary" class="mt-2 mb-3">@L["VerifyAuthenticatorCode"]</abp-button> |
|||
</div> |
|||
<a asp-page="./SendCode" asp-all-route-data="@(new Dictionary<string, string> {{"returnUrl", Model.ReturnUrl}, {"returnUrlHash", Model.ReturnUrlHash}})"> |
|||
<i class="fa fa-long-arrow-left"></i> @L["ReSendVerifyCode"] |
|||
</a> |
|||
</form> |
|||
</div> |
|||
</div> |
|||
@ -1,92 +0,0 @@ |
|||
using Microsoft.AspNetCore.Mvc; |
|||
using Microsoft.Extensions.Logging; |
|||
using System.ComponentModel.DataAnnotations; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.Account.Localization; |
|||
using Volo.Abp.Account.Web.Pages.Account; |
|||
|
|||
namespace LY.MicroService.IdentityServer.Pages.Account |
|||
{ |
|||
public class VerifyCodeModel : AccountPageModel |
|||
{ |
|||
[BindProperty] |
|||
public VerifyCodeInputModel Input { get; set; } |
|||
/// <summary>
|
|||
/// 双因素认证提供程序
|
|||
/// </summary>
|
|||
[HiddenInput] |
|||
[BindProperty(SupportsGet = true)] |
|||
public string Provider { get; set; } |
|||
/// <summary>
|
|||
/// 重定向Url
|
|||
/// </summary>
|
|||
[HiddenInput] |
|||
[BindProperty(SupportsGet = true)] |
|||
public string ReturnUrl { get; set; } |
|||
/// <summary>
|
|||
///
|
|||
/// </summary>
|
|||
[HiddenInput] |
|||
[BindProperty(SupportsGet = true)] |
|||
public string ReturnUrlHash { get; set; } |
|||
/// <summary>
|
|||
/// 是否记住登录状态
|
|||
/// </summary>
|
|||
[HiddenInput] |
|||
[BindProperty(SupportsGet = true)] |
|||
public bool RememberMe { get; set; } |
|||
|
|||
public VerifyCodeModel() |
|||
{ |
|||
LocalizationResourceType = typeof(AccountResource); |
|||
} |
|||
|
|||
public virtual IActionResult OnGet() |
|||
{ |
|||
Input = new VerifyCodeInputModel(); |
|||
|
|||
return Page(); |
|||
} |
|||
|
|||
public async virtual Task<IActionResult> OnPostAsync() |
|||
{ |
|||
// 验证用户登录状态
|
|||
var user = await SignInManager.GetTwoFactorAuthenticationUserAsync(); |
|||
if (user == null) |
|||
{ |
|||
Alerts.Warning(L["TwoFactorAuthenticationInvaidUser"]); |
|||
return Page(); |
|||
} |
|||
// 双因素登录
|
|||
var result = await SignInManager.TwoFactorSignInAsync(Provider, Input.VerifyCode, RememberMe, Input.RememberBrowser); |
|||
if (result.Succeeded) |
|||
{ |
|||
return await RedirectSafelyAsync(ReturnUrl, ReturnUrlHash); |
|||
} |
|||
if (result.IsLockedOut) |
|||
{ |
|||
Logger.LogWarning(7, "User account locked out."); |
|||
Alerts.Warning(L["UserLockedOutMessage"]); |
|||
return Page(); |
|||
} |
|||
else |
|||
{ |
|||
Alerts.Danger(L["TwoFactorAuthenticationInvaidUser"]);// TODO: 更多状态码的解读
|
|||
return Page(); |
|||
} |
|||
} |
|||
} |
|||
|
|||
public class VerifyCodeInputModel |
|||
{ |
|||
/// <summary>
|
|||
/// 是否在浏览器中记住登录状态
|
|||
/// </summary>
|
|||
public bool RememberBrowser { get; set; } |
|||
/// <summary>
|
|||
/// 发送的验证码
|
|||
/// </summary>
|
|||
[Required] |
|||
public string VerifyCode { get; set; } |
|||
} |
|||
} |
|||
@ -1,11 +1,10 @@ |
|||
using Volo.Abp.AspNetCore.Mvc.UI.RazorPages; |
|||
|
|||
namespace LY.MicroService.IdentityServer.Pages |
|||
namespace LY.MicroService.IdentityServer.Pages; |
|||
|
|||
public class IndexModel : AbpPageModel |
|||
{ |
|||
public class IndexModel : AbpPageModel |
|||
public void OnGet() |
|||
{ |
|||
public void OnGet() |
|||
{ |
|||
} |
|||
} |
|||
} |
|||
@ -1,5 +1,4 @@ |
|||
@using Microsoft.Extensions.Configuration |
|||
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers |
|||
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers |
|||
@addTagHelper *, Volo.Abp.AspNetCore.Mvc.UI |
|||
@addTagHelper *, Volo.Abp.AspNetCore.Mvc.UI.Bootstrap |
|||
@addTagHelper *, Volo.Abp.AspNetCore.Mvc.UI.Bundling |
|||
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue