mirror of https://github.com/abpframework/abp.git
111 changed files with 2235 additions and 414 deletions
@ -0,0 +1,13 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
|
||||
|
namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations.ObjectExtending |
||||
|
{ |
||||
|
[Serializable] |
||||
|
public class ExtensionEnumDto |
||||
|
{ |
||||
|
public List<ExtensionEnumFieldDto> Fields { get; set; } |
||||
|
|
||||
|
public string LocalizationResource { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,12 @@ |
|||||
|
using System; |
||||
|
|
||||
|
namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations.ObjectExtending |
||||
|
{ |
||||
|
[Serializable] |
||||
|
public class ExtensionEnumFieldDto |
||||
|
{ |
||||
|
public string Name { get; set; } |
||||
|
|
||||
|
public object Value { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,150 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.ComponentModel.DataAnnotations; |
||||
|
using Microsoft.AspNetCore.Mvc; |
||||
|
using Volo.Abp.Reflection; |
||||
|
|
||||
|
namespace Volo.Abp.ObjectExtending |
||||
|
{ |
||||
|
public static class MvcUiObjectExtensionPropertyInfoExtensions |
||||
|
{ |
||||
|
private static readonly HashSet<Type> NumberTypes = new HashSet<Type> { |
||||
|
typeof(int), |
||||
|
typeof(long), |
||||
|
typeof(byte), |
||||
|
typeof(sbyte), |
||||
|
typeof(short), |
||||
|
typeof(ushort), |
||||
|
typeof(uint), |
||||
|
typeof(long), |
||||
|
typeof(ulong), |
||||
|
typeof(float), |
||||
|
typeof(double), |
||||
|
typeof(decimal), |
||||
|
typeof(int?), |
||||
|
typeof(long?), |
||||
|
typeof(byte?), |
||||
|
typeof(sbyte?), |
||||
|
typeof(short?), |
||||
|
typeof(ushort?), |
||||
|
typeof(uint?), |
||||
|
typeof(long?), |
||||
|
typeof(ulong?), |
||||
|
typeof(float?), |
||||
|
typeof(double?), |
||||
|
typeof(decimal?) |
||||
|
}; |
||||
|
|
||||
|
public static string GetInputFormatOrNull(this IBasicObjectExtensionPropertyInfo property) |
||||
|
{ |
||||
|
if (property.IsDate()) |
||||
|
{ |
||||
|
return "{0:yyyy-MM-dd}"; |
||||
|
} |
||||
|
|
||||
|
if (property.IsDateTime()) |
||||
|
{ |
||||
|
return "{0:yyyy-MM-ddTHH:mm}"; |
||||
|
} |
||||
|
|
||||
|
return null; |
||||
|
} |
||||
|
|
||||
|
public static string GetInputValueOrNull(this IBasicObjectExtensionPropertyInfo property, object value) |
||||
|
{ |
||||
|
if (value == null) |
||||
|
{ |
||||
|
return null; |
||||
|
} |
||||
|
|
||||
|
if (TypeHelper.IsFloatingType(property.Type)) |
||||
|
{ |
||||
|
return value.ToString()?.Replace(',', '.'); |
||||
|
} |
||||
|
|
||||
|
/* Let the ASP.NET Core handle it! */ |
||||
|
return null; |
||||
|
} |
||||
|
|
||||
|
public static string GetInputType(this ObjectExtensionPropertyInfo propertyInfo) |
||||
|
{ |
||||
|
foreach (var attribute in propertyInfo.Attributes) |
||||
|
{ |
||||
|
var inputTypeByAttribute = GetInputTypeFromAttributeOrNull(attribute); |
||||
|
if (inputTypeByAttribute != null) |
||||
|
{ |
||||
|
return inputTypeByAttribute; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return GetInputTypeFromTypeOrNull(propertyInfo.Type) |
||||
|
?? "text"; //default
|
||||
|
} |
||||
|
|
||||
|
private static string GetInputTypeFromAttributeOrNull(Attribute attribute) |
||||
|
{ |
||||
|
if (attribute is EmailAddressAttribute) |
||||
|
{ |
||||
|
return "email"; |
||||
|
} |
||||
|
|
||||
|
if (attribute is UrlAttribute) |
||||
|
{ |
||||
|
return "url"; |
||||
|
} |
||||
|
|
||||
|
if (attribute is HiddenInputAttribute) |
||||
|
{ |
||||
|
return "hidden"; |
||||
|
} |
||||
|
|
||||
|
if (attribute is PhoneAttribute) |
||||
|
{ |
||||
|
return "tel"; |
||||
|
} |
||||
|
|
||||
|
if (attribute is DataTypeAttribute dataTypeAttribute) |
||||
|
{ |
||||
|
switch (dataTypeAttribute.DataType) |
||||
|
{ |
||||
|
case DataType.Password: |
||||
|
return "password"; |
||||
|
case DataType.Date: |
||||
|
return "date"; |
||||
|
case DataType.Time: |
||||
|
return "time"; |
||||
|
case DataType.EmailAddress: |
||||
|
return "email"; |
||||
|
case DataType.Url: |
||||
|
return "url"; |
||||
|
case DataType.PhoneNumber: |
||||
|
return "tel"; |
||||
|
case DataType.DateTime: |
||||
|
return "datetime-local"; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return null; |
||||
|
} |
||||
|
|
||||
|
private static string GetInputTypeFromTypeOrNull(Type type) |
||||
|
{ |
||||
|
if (type == typeof(bool)) |
||||
|
{ |
||||
|
return "checkbox"; |
||||
|
} |
||||
|
|
||||
|
if (type == typeof(DateTime)) |
||||
|
{ |
||||
|
return "datetime-local"; |
||||
|
} |
||||
|
|
||||
|
if (NumberTypes.Contains(type)) |
||||
|
{ |
||||
|
return "number"; |
||||
|
} |
||||
|
|
||||
|
return null; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -1,116 +1,35 @@ |
|||||
using System; |
using System; |
||||
using System.Collections.Generic; |
|
||||
using System.ComponentModel.DataAnnotations; |
using System.ComponentModel.DataAnnotations; |
||||
using Microsoft.AspNetCore.Mvc; |
using System.Linq; |
||||
|
|
||||
namespace Volo.Abp.ObjectExtending |
namespace Volo.Abp.ObjectExtending |
||||
{ |
{ |
||||
public static class ObjectExtensionPropertyInfoAspNetCoreMvcExtensions |
public static class ObjectExtensionPropertyInfoAspNetCoreMvcExtensions |
||||
{ |
{ |
||||
private static readonly HashSet<Type> NumberTypes = new HashSet<Type> { |
private static readonly Type[] DateTimeTypes = |
||||
typeof(int), |
{ |
||||
typeof(long), |
typeof(DateTime), |
||||
typeof(byte), |
typeof(DateTimeOffset) |
||||
typeof(sbyte), |
|
||||
typeof(short), |
|
||||
typeof(ushort), |
|
||||
typeof(uint), |
|
||||
typeof(long), |
|
||||
typeof(ulong), |
|
||||
typeof(float), |
|
||||
typeof(double), |
|
||||
typeof(int?), |
|
||||
typeof(long?), |
|
||||
typeof(byte?), |
|
||||
typeof(sbyte?), |
|
||||
typeof(short?), |
|
||||
typeof(ushort?), |
|
||||
typeof(uint?), |
|
||||
typeof(long?), |
|
||||
typeof(ulong?), |
|
||||
typeof(float?), |
|
||||
typeof(double?), |
|
||||
}; |
}; |
||||
|
|
||||
public static string GetInputType(this ObjectExtensionPropertyInfo propertyInfo) |
public static bool IsDate(this IBasicObjectExtensionPropertyInfo property) |
||||
{ |
{ |
||||
foreach (var attribute in propertyInfo.Attributes) |
return DateTimeTypes.Contains(property.Type) && |
||||
{ |
property.GetDataTypeOrNull() == DataType.Date; |
||||
var inputTypeByAttribute = GetInputTypeFromAttributeOrNull(attribute); |
|
||||
if (inputTypeByAttribute != null) |
|
||||
{ |
|
||||
return inputTypeByAttribute; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
return GetInputTypeFromTypeOrNull(propertyInfo.Type) |
|
||||
?? "text"; //default
|
|
||||
} |
} |
||||
|
|
||||
private static string GetInputTypeFromAttributeOrNull(Attribute attribute) |
public static bool IsDateTime(this IBasicObjectExtensionPropertyInfo property) |
||||
{ |
{ |
||||
if (attribute is EmailAddressAttribute) |
return DateTimeTypes.Contains(property.Type) && |
||||
{ |
!property.IsDate(); |
||||
return "email"; |
|
||||
} |
|
||||
|
|
||||
if (attribute is UrlAttribute) |
|
||||
{ |
|
||||
return "url"; |
|
||||
} |
|
||||
|
|
||||
if (attribute is HiddenInputAttribute) |
|
||||
{ |
|
||||
return "hidden"; |
|
||||
} |
|
||||
|
|
||||
if (attribute is PhoneAttribute) |
|
||||
{ |
|
||||
return "tel"; |
|
||||
} |
|
||||
|
|
||||
if (attribute is DataTypeAttribute dataTypeAttribute) |
|
||||
{ |
|
||||
switch (dataTypeAttribute.DataType) |
|
||||
{ |
|
||||
case DataType.Password: |
|
||||
return "password"; |
|
||||
case DataType.Date: |
|
||||
return "date"; |
|
||||
case DataType.Time: |
|
||||
return "time"; |
|
||||
case DataType.EmailAddress: |
|
||||
return "email"; |
|
||||
case DataType.Url: |
|
||||
return "url"; |
|
||||
case DataType.PhoneNumber: |
|
||||
return "tel"; |
|
||||
case DataType.DateTime: |
|
||||
return "datetime-local"; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
return null; |
|
||||
} |
} |
||||
|
|
||||
private static string GetInputTypeFromTypeOrNull(Type type) |
public static DataType? GetDataTypeOrNull(this IBasicObjectExtensionPropertyInfo property) |
||||
{ |
{ |
||||
if (type == typeof(bool)) |
return property |
||||
{ |
.Attributes |
||||
return "checkbox"; |
.OfType<DataTypeAttribute>() |
||||
} |
.FirstOrDefault()?.DataType; |
||||
|
|
||||
if (type == typeof(DateTime)) |
|
||||
{ |
|
||||
return "datetime-local"; |
|
||||
} |
|
||||
|
|
||||
if (NumberTypes.Contains(type)) |
|
||||
{ |
|
||||
return "number"; |
|
||||
} |
|
||||
|
|
||||
return null; |
|
||||
} |
} |
||||
} |
} |
||||
} |
} |
||||
|
|||||
@ -1,21 +1,28 @@ |
|||||
using Microsoft.AspNetCore.SignalR; |
using Microsoft.AspNetCore.SignalR; |
||||
using Volo.Abp.DependencyInjection; |
using Volo.Abp.DependencyInjection; |
||||
|
using Volo.Abp.Security.Claims; |
||||
using Volo.Abp.Users; |
using Volo.Abp.Users; |
||||
|
|
||||
namespace Volo.Abp.AspNetCore.SignalR |
namespace Volo.Abp.AspNetCore.SignalR |
||||
{ |
{ |
||||
public class AbpSignalRUserIdProvider : IUserIdProvider, ITransientDependency |
public class AbpSignalRUserIdProvider : IUserIdProvider, ITransientDependency |
||||
{ |
{ |
||||
public ICurrentUser CurrentUser { get; } |
private readonly ICurrentPrincipalAccessor _currentPrincipalAccessor; |
||||
|
|
||||
public AbpSignalRUserIdProvider(ICurrentUser currentUser) |
private readonly ICurrentUser _currentUser; |
||||
|
|
||||
|
public AbpSignalRUserIdProvider(ICurrentPrincipalAccessor currentPrincipalAccessor, ICurrentUser currentUser) |
||||
{ |
{ |
||||
CurrentUser = currentUser; |
_currentPrincipalAccessor = currentPrincipalAccessor; |
||||
|
_currentUser = currentUser; |
||||
} |
} |
||||
|
|
||||
public virtual string GetUserId(HubConnectionContext connection) |
public virtual string GetUserId(HubConnectionContext connection) |
||||
{ |
{ |
||||
return CurrentUser.Id?.ToString(); |
using (_currentPrincipalAccessor.Change(connection.User)) |
||||
|
{ |
||||
|
return _currentUser.Id?.ToString(); |
||||
|
} |
||||
} |
} |
||||
} |
} |
||||
} |
} |
||||
|
|||||
@ -0,0 +1,16 @@ |
|||||
|
namespace Volo.Abp.Cli.ProjectBuilding.Templates.Console |
||||
|
{ |
||||
|
public class ConsoleTemplate : ConsoleTemplateBase |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// "console".
|
||||
|
/// </summary>
|
||||
|
public const string TemplateName = "console"; |
||||
|
|
||||
|
public ConsoleTemplate() |
||||
|
: base(TemplateName) |
||||
|
{ |
||||
|
DocumentUrl = CliConsts.DocsLink + "/en/abp/latest/Getting-Started-Console-Application"; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,13 @@ |
|||||
|
using JetBrains.Annotations; |
||||
|
using Volo.Abp.Cli.ProjectBuilding.Building; |
||||
|
|
||||
|
namespace Volo.Abp.Cli.ProjectBuilding.Templates.Console |
||||
|
{ |
||||
|
public abstract class ConsoleTemplateBase : TemplateInfo |
||||
|
{ |
||||
|
protected ConsoleTemplateBase([NotNull] string name) : |
||||
|
base(name) |
||||
|
{ |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,46 @@ |
|||||
|
using System; |
||||
|
using System.Runtime.Serialization; |
||||
|
|
||||
|
namespace Volo.Abp |
||||
|
{ |
||||
|
public class AbpInitializationException : AbpException |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Creates a new <see cref="AbpException"/> object.
|
||||
|
/// </summary>
|
||||
|
public AbpInitializationException() |
||||
|
{ |
||||
|
|
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Creates a new <see cref="AbpException"/> object.
|
||||
|
/// </summary>
|
||||
|
/// <param name="message">Exception message</param>
|
||||
|
public AbpInitializationException(string message) |
||||
|
: base(message) |
||||
|
{ |
||||
|
|
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Creates a new <see cref="AbpException"/> object.
|
||||
|
/// </summary>
|
||||
|
/// <param name="message">Exception message</param>
|
||||
|
/// <param name="innerException">Inner exception</param>
|
||||
|
public AbpInitializationException(string message, Exception innerException) |
||||
|
: base(message, innerException) |
||||
|
{ |
||||
|
|
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Constructor for serializing.
|
||||
|
/// </summary>
|
||||
|
public AbpInitializationException(SerializationInfo serializationInfo, StreamingContext context) |
||||
|
: base(serializationInfo, context) |
||||
|
{ |
||||
|
|
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,50 @@ |
|||||
|
using Microsoft.Extensions.Localization; |
||||
|
|
||||
|
namespace Volo.Abp.Localization |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// This class is designed to be used internal by the framework.
|
||||
|
/// </summary>
|
||||
|
public static class AbpInternalLocalizationHelper |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Searches an array of keys in an array of localizers.
|
||||
|
/// </summary>
|
||||
|
/// <param name="localizers">
|
||||
|
/// An array of localizers. Search the keys on the localizers.
|
||||
|
/// Can contain null items in the array.
|
||||
|
/// </param>
|
||||
|
/// <param name="keys">
|
||||
|
/// An array of keys. Search the keys on the localizers.
|
||||
|
/// Should not contain null items in the array.
|
||||
|
/// </param>
|
||||
|
/// <param name="defaultValue">
|
||||
|
/// Return value if none of the localizers has none of the keys.
|
||||
|
/// </param>
|
||||
|
/// <returns></returns>
|
||||
|
public static string LocalizeWithFallback( |
||||
|
IStringLocalizer[] localizers, |
||||
|
string[] keys, |
||||
|
string defaultValue) |
||||
|
{ |
||||
|
foreach (var key in keys) |
||||
|
{ |
||||
|
foreach (var localizer in localizers) |
||||
|
{ |
||||
|
if (localizer == null) |
||||
|
{ |
||||
|
continue; |
||||
|
} |
||||
|
|
||||
|
var localizedString = localizer[key]; |
||||
|
if (!localizedString.ResourceNotFound) |
||||
|
{ |
||||
|
return localizedString.Value; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return defaultValue; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,38 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using JetBrains.Annotations; |
||||
|
using Volo.Abp.Localization; |
||||
|
|
||||
|
namespace Volo.Abp.ObjectExtending |
||||
|
{ |
||||
|
public interface IBasicObjectExtensionPropertyInfo |
||||
|
{ |
||||
|
[NotNull] |
||||
|
public string Name { get; } |
||||
|
|
||||
|
[NotNull] |
||||
|
public Type Type { get; } |
||||
|
|
||||
|
[NotNull] |
||||
|
public List<Attribute> Attributes { get; } |
||||
|
|
||||
|
[NotNull] |
||||
|
public List<Action<ObjectExtensionPropertyValidationContext>> Validators { get; } |
||||
|
|
||||
|
[CanBeNull] |
||||
|
public ILocalizableString DisplayName { get; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Uses as the default value if <see cref="DefaultValueFactory"/> was not set.
|
||||
|
/// </summary>
|
||||
|
[CanBeNull] |
||||
|
public object DefaultValue { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Used with the first priority to create the default value for the property.
|
||||
|
/// Uses to the <see cref="DefaultValue"/> if this was not set.
|
||||
|
/// </summary>
|
||||
|
[CanBeNull] |
||||
|
public Func<object> DefaultValueFactory { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,32 @@ |
|||||
|
using System; |
||||
|
using Volo.Abp.Localization; |
||||
|
|
||||
|
namespace Volo.Abp.ObjectExtending.Modularity |
||||
|
{ |
||||
|
public static class ExtensionPropertyConfigurationExtensions |
||||
|
{ |
||||
|
public static string GetLocalizationResourceNameOrNull( |
||||
|
this ExtensionPropertyConfiguration property) |
||||
|
{ |
||||
|
var resourceType = property.GetLocalizationResourceTypeOrNull(); |
||||
|
if (resourceType == null) |
||||
|
{ |
||||
|
return null; |
||||
|
} |
||||
|
|
||||
|
return LocalizationResourceNameAttribute.GetName(resourceType); |
||||
|
} |
||||
|
|
||||
|
public static Type GetLocalizationResourceTypeOrNull( |
||||
|
this ExtensionPropertyConfiguration property) |
||||
|
{ |
||||
|
if (property.DisplayName != null && |
||||
|
property.DisplayName is LocalizableString localizableString) |
||||
|
{ |
||||
|
return localizableString.ResourceType; |
||||
|
} |
||||
|
|
||||
|
return null; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -1,9 +1,12 @@ |
|||||
using System.Security.Claims; |
using System; |
||||
|
using System.Security.Claims; |
||||
|
|
||||
namespace Volo.Abp.Security.Claims |
namespace Volo.Abp.Security.Claims |
||||
{ |
{ |
||||
public interface ICurrentPrincipalAccessor |
public interface ICurrentPrincipalAccessor |
||||
{ |
{ |
||||
ClaimsPrincipal Principal { get; } |
ClaimsPrincipal Principal { get; } |
||||
|
|
||||
|
IDisposable Change(ClaimsPrincipal principal); |
||||
} |
} |
||||
} |
} |
||||
|
|||||
@ -0,0 +1,50 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Linq; |
||||
|
using System.Threading.Tasks; |
||||
|
using Microsoft.Extensions.Localization; |
||||
|
using Scriban; |
||||
|
using Scriban.Runtime; |
||||
|
using Scriban.Syntax; |
||||
|
|
||||
|
namespace Volo.Abp.TextTemplating |
||||
|
{ |
||||
|
public class TemplateLocalizer : IScriptCustomFunction |
||||
|
{ |
||||
|
private readonly IStringLocalizer _localizer; |
||||
|
|
||||
|
public TemplateLocalizer(IStringLocalizer localizer) |
||||
|
{ |
||||
|
_localizer = localizer; |
||||
|
} |
||||
|
|
||||
|
public object Invoke(TemplateContext context, ScriptNode callerContext, ScriptArray arguments, |
||||
|
ScriptBlockStatement blockStatement) |
||||
|
{ |
||||
|
return GetString(arguments); |
||||
|
} |
||||
|
|
||||
|
public ValueTask<object> InvokeAsync(TemplateContext context, ScriptNode callerContext, ScriptArray arguments, |
||||
|
ScriptBlockStatement blockStatement) |
||||
|
{ |
||||
|
return new ValueTask<object>(GetString(arguments)); |
||||
|
} |
||||
|
|
||||
|
private string GetString(ScriptArray arguments) |
||||
|
{ |
||||
|
if (arguments.IsNullOrEmpty()) |
||||
|
{ |
||||
|
return string.Empty; |
||||
|
} |
||||
|
|
||||
|
var name = arguments[0]; |
||||
|
if (name == null || name.ToString().IsNullOrWhiteSpace()) |
||||
|
{ |
||||
|
return string.Empty; |
||||
|
} |
||||
|
|
||||
|
var args = arguments.Skip(1).Where(x => x != null && !x.ToString().IsNullOrWhiteSpace()).ToArray(); |
||||
|
return args.Any() ? _localizer[name.ToString(), args] : _localizer[name.ToString()]; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -1,18 +1,35 @@ |
|||||
using Microsoft.AspNetCore.Mvc; |
using System.Threading.Tasks; |
||||
|
using Microsoft.AspNetCore.Mvc; |
||||
using Volo.Abp.AspNetCore.Mvc.UI.RazorPages; |
using Volo.Abp.AspNetCore.Mvc.UI.RazorPages; |
||||
|
|
||||
namespace Volo.Abp.AspNetCore.Mvc.ExceptionHandling |
namespace Volo.Abp.AspNetCore.Mvc.ExceptionHandling |
||||
{ |
{ |
||||
public class ExceptionTestPage : AbpPageModel |
public class ExceptionTestPage : AbpPageModel |
||||
{ |
{ |
||||
public void OnGetUserFriendlyException1() |
public void OnGetUserFriendlyException_void() |
||||
{ |
{ |
||||
throw new UserFriendlyException("This is a sample exception!"); |
throw new UserFriendlyException("This is a sample exception!"); |
||||
} |
} |
||||
|
|
||||
public IActionResult OnGetUserFriendlyException2() |
public Task OnGetUserFriendlyException_Task() |
||||
|
{ |
||||
|
throw new UserFriendlyException("This is a sample exception!"); |
||||
|
} |
||||
|
|
||||
|
public IActionResult OnGetUserFriendlyException_ActionResult() |
||||
|
{ |
||||
|
throw new UserFriendlyException("This is a sample exception!"); |
||||
|
} |
||||
|
|
||||
|
public JsonResult OnGetUserFriendlyException_JsonResult() |
||||
{ |
{ |
||||
throw new UserFriendlyException("This is a sample exception!"); |
throw new UserFriendlyException("This is a sample exception!"); |
||||
} |
} |
||||
|
|
||||
|
public Task<JsonResult> OnGetUserFriendlyException_Task_JsonResult() |
||||
|
{ |
||||
|
throw new UserFriendlyException("This is a sample exception!"); |
||||
|
} |
||||
|
|
||||
} |
} |
||||
} |
} |
||||
|
|||||
@ -0,0 +1,6 @@ |
|||||
|
{ |
||||
|
"culture": "de", |
||||
|
"texts": { |
||||
|
"hello": "Hello" |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,50 @@ |
|||||
|
using System.Collections.Generic; |
||||
|
using System.Security.Claims; |
||||
|
using Shouldly; |
||||
|
using Volo.Abp.Testing; |
||||
|
using Xunit; |
||||
|
|
||||
|
namespace Volo.Abp.Security.Claims |
||||
|
{ |
||||
|
public class CurrentPrincipalAccessor_Test : AbpIntegratedTest<AbpSecurityTestModule> |
||||
|
{ |
||||
|
private readonly ICurrentPrincipalAccessor _currentPrincipalAccessor; |
||||
|
|
||||
|
public CurrentPrincipalAccessor_Test() |
||||
|
{ |
||||
|
_currentPrincipalAccessor = GetRequiredService<ICurrentPrincipalAccessor>(); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Should_Get_Changed_Principal_If() |
||||
|
{ |
||||
|
var claimsPrincipal = new ClaimsPrincipal(new ClaimsIdentity(new List<Claim> |
||||
|
{ |
||||
|
new Claim(ClaimTypes.Name,"bob"), |
||||
|
new Claim(ClaimTypes.NameIdentifier,"123456") |
||||
|
})); |
||||
|
|
||||
|
var claimsPrincipal2 = new ClaimsPrincipal(new ClaimsIdentity(new List<Claim> |
||||
|
{ |
||||
|
new Claim(ClaimTypes.Name,"lee"), |
||||
|
new Claim(ClaimTypes.NameIdentifier,"654321") |
||||
|
})); |
||||
|
|
||||
|
|
||||
|
_currentPrincipalAccessor.Principal.ShouldBe(null); |
||||
|
|
||||
|
using (_currentPrincipalAccessor.Change(claimsPrincipal)) |
||||
|
{ |
||||
|
_currentPrincipalAccessor.Principal.ShouldBe(claimsPrincipal); |
||||
|
|
||||
|
using (_currentPrincipalAccessor.Change(claimsPrincipal2)) |
||||
|
{ |
||||
|
_currentPrincipalAccessor.Principal.ShouldBe(claimsPrincipal2); |
||||
|
} |
||||
|
|
||||
|
_currentPrincipalAccessor.Principal.ShouldBe(claimsPrincipal); |
||||
|
} |
||||
|
_currentPrincipalAccessor.Principal.ShouldBeNull(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -1,6 +1,7 @@ |
|||||
{ |
{ |
||||
"culture": "en", |
"culture": "en", |
||||
"texts": { |
"texts": { |
||||
"HelloText": "Hello" |
"HelloText": "Hello {0}", |
||||
} |
"HowAreYou": "how are you?" |
||||
} |
} |
||||
|
} |
||||
|
|||||
@ -1,6 +1,7 @@ |
|||||
{ |
{ |
||||
"culture": "tr", |
"culture": "tr", |
||||
"texts": { |
"texts": { |
||||
"HelloText": "Merhaba" |
"HelloText": "Merhaba {0}", |
||||
} |
"HowAreYou": "nasılsın?" |
||||
} |
} |
||||
|
} |
||||
|
|||||
@ -1 +1 @@ |
|||||
{{L "HelloText"}}. Please click to the following link to get an email to reset your password! |
{{L "HelloText" model.name}}, {{L "HowAreYou" }}. Please click to the following link to get an email to reset your password! |
||||
@ -1,12 +0,0 @@ |
|||||
using System; |
|
||||
using System.Collections.Generic; |
|
||||
using System.Linq; |
|
||||
using System.Threading.Tasks; |
|
||||
|
|
||||
namespace Volo.Blogging |
|
||||
{ |
|
||||
public class BloggingTwitterOptions |
|
||||
{ |
|
||||
public string Site { get; set; } |
|
||||
} |
|
||||
} |
|
||||
@ -0,0 +1,7 @@ |
|||||
|
namespace Volo.Blogging.SocialMedia |
||||
|
{ |
||||
|
public class BloggingTwitterOptions |
||||
|
{ |
||||
|
public string Site { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,7 @@ |
|||||
|
namespace Volo.Docs.Admin |
||||
|
{ |
||||
|
public static class DocsAdminRemoteServiceConsts |
||||
|
{ |
||||
|
public const string RemoteServiceName = "AbpDocsAdmin"; |
||||
|
} |
||||
|
} |
||||
@ -1,11 +1,17 @@ |
|||||
using Volo.Abp.Modularity; |
using Microsoft.Extensions.DependencyInjection; |
||||
|
using Volo.Abp.Http.Client; |
||||
|
using Volo.Abp.Modularity; |
||||
|
|
||||
namespace Volo.Docs.Admin |
namespace Volo.Docs.Admin |
||||
{ |
{ |
||||
[DependsOn( |
[DependsOn( |
||||
typeof(DocsAdminApplicationContractsModule))] |
typeof(DocsAdminApplicationContractsModule), |
||||
|
typeof(AbpHttpClientModule))] |
||||
public class DocsAdminHttpApiClientModule : AbpModule |
public class DocsAdminHttpApiClientModule : AbpModule |
||||
{ |
{ |
||||
//TODO: Create client proxies!
|
public override void ConfigureServices(ServiceConfigurationContext context) |
||||
|
{ |
||||
|
context.Services.AddHttpClientProxies(typeof(DocsAdminApplicationContractsModule).Assembly, DocsAdminRemoteServiceConsts.RemoteServiceName); |
||||
|
} |
||||
} |
} |
||||
} |
} |
||||
|
|||||
@ -0,0 +1,7 @@ |
|||||
|
namespace Volo.Docs |
||||
|
{ |
||||
|
public static class DocsRemoteServiceConsts |
||||
|
{ |
||||
|
public const string RemoteServiceName = "AbpDocs"; |
||||
|
} |
||||
|
} |
||||
@ -1,11 +1,18 @@ |
|||||
using Volo.Abp.Modularity; |
using Microsoft.Extensions.DependencyInjection; |
||||
|
using Volo.Abp.Http.Client; |
||||
|
using Volo.Abp.Modularity; |
||||
|
|
||||
namespace Volo.Docs |
namespace Volo.Docs |
||||
{ |
{ |
||||
[DependsOn( |
[DependsOn( |
||||
typeof(DocsApplicationContractsModule))] |
typeof(DocsApplicationContractsModule), |
||||
|
typeof(AbpHttpClientModule) |
||||
|
)] |
||||
public class DocsHttpApiClientModule : AbpModule |
public class DocsHttpApiClientModule : AbpModule |
||||
{ |
{ |
||||
//TODO: Create client proxies
|
public override void ConfigureServices(ServiceConfigurationContext context) |
||||
|
{ |
||||
|
context.Services.AddHttpClientProxies(typeof(DocsApplicationContractsModule).Assembly, DocsRemoteServiceConsts.RemoteServiceName); |
||||
|
} |
||||
} |
} |
||||
} |
} |
||||
|
|||||
@ -0,0 +1,7 @@ |
|||||
|
namespace Volo.Abp.Identity |
||||
|
{ |
||||
|
public class UserLookupCountInputDto |
||||
|
{ |
||||
|
public string Filter { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,140 @@ |
|||||
|
import { |
||||
|
createLocalizationPipeKeyGenerator, |
||||
|
createLocalizer, |
||||
|
createLocalizerWithFallback, |
||||
|
} from '../utils/localization-utils'; |
||||
|
|
||||
|
describe('Localization Utils', () => { |
||||
|
describe('#createLocalizer', () => { |
||||
|
const localize = createLocalizer({ |
||||
|
values: { foo: { bar: 'baz' }, x: { y: 'z' } }, |
||||
|
defaultResourceName: 'x', |
||||
|
currentCulture: null, |
||||
|
languages: [], |
||||
|
}); |
||||
|
|
||||
|
test.each` |
||||
|
resource | key | defaultValue | expected |
||||
|
${'_'} | ${'TEST'} | ${'DEFAULT'} | ${'TEST'} |
||||
|
${'foo'} | ${'bar'} | ${'DEFAULT'} | ${'baz'} |
||||
|
${'x'} | ${'bar'} | ${'DEFAULT'} | ${'DEFAULT'} |
||||
|
${'a'} | ${'bar'} | ${'DEFAULT'} | ${'DEFAULT'} |
||||
|
${''} | ${'bar'} | ${'DEFAULT'} | ${'DEFAULT'} |
||||
|
${undefined} | ${'bar'} | ${'DEFAULT'} | ${'DEFAULT'} |
||||
|
${'foo'} | ${'y'} | ${'DEFAULT'} | ${'DEFAULT'} |
||||
|
${'x'} | ${'y'} | ${'DEFAULT'} | ${'z'} |
||||
|
${'a'} | ${'y'} | ${'DEFAULT'} | ${'DEFAULT'} |
||||
|
${''} | ${'y'} | ${'DEFAULT'} | ${'DEFAULT'} |
||||
|
${undefined} | ${'y'} | ${'DEFAULT'} | ${'DEFAULT'} |
||||
|
${'foo'} | ${''} | ${'DEFAULT'} | ${'DEFAULT'} |
||||
|
${'x'} | ${''} | ${'DEFAULT'} | ${'DEFAULT'} |
||||
|
${'a'} | ${''} | ${'DEFAULT'} | ${'DEFAULT'} |
||||
|
${''} | ${''} | ${'DEFAULT'} | ${'DEFAULT'} |
||||
|
${undefined} | ${''} | ${'DEFAULT'} | ${'DEFAULT'} |
||||
|
${'foo'} | ${undefined} | ${'DEFAULT'} | ${'DEFAULT'} |
||||
|
${'x'} | ${undefined} | ${'DEFAULT'} | ${'DEFAULT'} |
||||
|
${'a'} | ${undefined} | ${'DEFAULT'} | ${'DEFAULT'} |
||||
|
${''} | ${undefined} | ${'DEFAULT'} | ${'DEFAULT'} |
||||
|
${undefined} | ${undefined} | ${'DEFAULT'} | ${'DEFAULT'} |
||||
|
`(
|
||||
|
'should return $expected when resource name is $resource and key is $key', |
||||
|
({ resource, key, defaultValue, expected }) => { |
||||
|
const result = localize(resource, key, defaultValue); |
||||
|
|
||||
|
expect(result).toBe(expected); |
||||
|
}, |
||||
|
); |
||||
|
}); |
||||
|
|
||||
|
describe('#createLocalizerWithFallback', () => { |
||||
|
const localizeWithFallback = createLocalizerWithFallback({ |
||||
|
values: { foo: { bar: 'baz' }, x: { y: 'z' } }, |
||||
|
defaultResourceName: 'x', |
||||
|
currentCulture: null, |
||||
|
languages: [], |
||||
|
}); |
||||
|
|
||||
|
test.each` |
||||
|
resources | keys | defaultValue | expected |
||||
|
${['', '_']} | ${['TEST', 'OTHER']} | ${'DEFAULT'} | ${'TEST'} |
||||
|
${['foo']} | ${['bar']} | ${'DEFAULT'} | ${'baz'} |
||||
|
${['x']} | ${['bar']} | ${'DEFAULT'} | ${'DEFAULT'} |
||||
|
${['a', 'b', 'c']} | ${['bar']} | ${'DEFAULT'} | ${'DEFAULT'} |
||||
|
${['']} | ${['bar']} | ${'DEFAULT'} | ${'DEFAULT'} |
||||
|
${[]} | ${['bar']} | ${'DEFAULT'} | ${'DEFAULT'} |
||||
|
${['foo']} | ${['y']} | ${'DEFAULT'} | ${'z'} |
||||
|
${['x']} | ${['y']} | ${'DEFAULT'} | ${'z'} |
||||
|
${['a', 'b', 'c']} | ${['y']} | ${'DEFAULT'} | ${'z'} |
||||
|
${['']} | ${['y']} | ${'DEFAULT'} | ${'z'} |
||||
|
${[]} | ${['y']} | ${'DEFAULT'} | ${'z'} |
||||
|
${['foo']} | ${['bar', 'y']} | ${'DEFAULT'} | ${'baz'} |
||||
|
${['x']} | ${['bar', 'y']} | ${'DEFAULT'} | ${'z'} |
||||
|
${['a', 'b', 'c']} | ${['bar', 'y']} | ${'DEFAULT'} | ${'z'} |
||||
|
${['']} | ${['bar', 'y']} | ${'DEFAULT'} | ${'z'} |
||||
|
${[]} | ${['bar', 'y']} | ${'DEFAULT'} | ${'z'} |
||||
|
${['foo']} | ${['']} | ${'DEFAULT'} | ${'DEFAULT'} |
||||
|
${['x']} | ${['']} | ${'DEFAULT'} | ${'DEFAULT'} |
||||
|
${['a', 'b', 'c']} | ${['']} | ${'DEFAULT'} | ${'DEFAULT'} |
||||
|
${['']} | ${['']} | ${'DEFAULT'} | ${'DEFAULT'} |
||||
|
${[]} | ${['']} | ${'DEFAULT'} | ${'DEFAULT'} |
||||
|
${['foo']} | ${[]} | ${'DEFAULT'} | ${'DEFAULT'} |
||||
|
${['x']} | ${[]} | ${'DEFAULT'} | ${'DEFAULT'} |
||||
|
${['a', 'b', 'c']} | ${[]} | ${'DEFAULT'} | ${'DEFAULT'} |
||||
|
${['']} | ${[]} | ${'DEFAULT'} | ${'DEFAULT'} |
||||
|
${[]} | ${[]} | ${'DEFAULT'} | ${'DEFAULT'} |
||||
|
`(
|
||||
|
'should return $expected when resource names are $resources and keys are $keys', |
||||
|
({ resources, keys, defaultValue, expected }) => { |
||||
|
const result = localizeWithFallback(resources, keys, defaultValue); |
||||
|
|
||||
|
expect(result).toBe(expected); |
||||
|
}, |
||||
|
); |
||||
|
}); |
||||
|
|
||||
|
describe('#createLocalizationPipeKeyGenerator', () => { |
||||
|
const generateLocalizationPipeKey = createLocalizationPipeKeyGenerator({ |
||||
|
values: { foo: { bar: 'baz' }, x: { y: 'z' } }, |
||||
|
defaultResourceName: 'x', |
||||
|
currentCulture: null, |
||||
|
languages: [], |
||||
|
}); |
||||
|
|
||||
|
test.each` |
||||
|
resources | keys | defaultKey | expected |
||||
|
${['', '_']} | ${['TEST', 'OTHER']} | ${'DEFAULT'} | ${'TEST'} |
||||
|
${['foo']} | ${['bar']} | ${'DEFAULT'} | ${'foo::bar'} |
||||
|
${['x']} | ${['bar']} | ${'DEFAULT'} | ${'DEFAULT'} |
||||
|
${['a', 'b', 'c']} | ${['bar']} | ${'DEFAULT'} | ${'DEFAULT'} |
||||
|
${['']} | ${['bar']} | ${'DEFAULT'} | ${'DEFAULT'} |
||||
|
${[]} | ${['bar']} | ${'DEFAULT'} | ${'DEFAULT'} |
||||
|
${['foo']} | ${['y']} | ${'DEFAULT'} | ${'x::y'} |
||||
|
${['x']} | ${['y']} | ${'DEFAULT'} | ${'x::y'} |
||||
|
${['a', 'b', 'c']} | ${['y']} | ${'DEFAULT'} | ${'x::y'} |
||||
|
${['']} | ${['y']} | ${'DEFAULT'} | ${'x::y'} |
||||
|
${[]} | ${['y']} | ${'DEFAULT'} | ${'x::y'} |
||||
|
${['foo']} | ${['bar', 'y']} | ${'DEFAULT'} | ${'foo::bar'} |
||||
|
${['x']} | ${['bar', 'y']} | ${'DEFAULT'} | ${'x::y'} |
||||
|
${['a', 'b', 'c']} | ${['bar', 'y']} | ${'DEFAULT'} | ${'x::y'} |
||||
|
${['']} | ${['bar', 'y']} | ${'DEFAULT'} | ${'x::y'} |
||||
|
${[]} | ${['bar', 'y']} | ${'DEFAULT'} | ${'x::y'} |
||||
|
${['foo']} | ${['']} | ${'DEFAULT'} | ${'DEFAULT'} |
||||
|
${['x']} | ${['']} | ${'DEFAULT'} | ${'DEFAULT'} |
||||
|
${['a', 'b', 'c']} | ${['']} | ${'DEFAULT'} | ${'DEFAULT'} |
||||
|
${['']} | ${['']} | ${'DEFAULT'} | ${'DEFAULT'} |
||||
|
${[]} | ${['']} | ${'DEFAULT'} | ${'DEFAULT'} |
||||
|
${['foo']} | ${[]} | ${'DEFAULT'} | ${'DEFAULT'} |
||||
|
${['x']} | ${[]} | ${'DEFAULT'} | ${'DEFAULT'} |
||||
|
${['a', 'b', 'c']} | ${[]} | ${'DEFAULT'} | ${'DEFAULT'} |
||||
|
${['']} | ${[]} | ${'DEFAULT'} | ${'DEFAULT'} |
||||
|
${[]} | ${[]} | ${'DEFAULT'} | ${'DEFAULT'} |
||||
|
`(
|
||||
|
'should return $expected when resource names are $resources and keys are $keys', |
||||
|
({ resources, keys, defaultKey, expected }) => { |
||||
|
const result = generateLocalizationPipeKey(resources, keys, defaultKey); |
||||
|
|
||||
|
expect(result).toBe(expected); |
||||
|
}, |
||||
|
); |
||||
|
}); |
||||
|
}); |
||||
@ -0,0 +1,56 @@ |
|||||
|
import { ApplicationConfiguration } from '../models/application-configuration'; |
||||
|
|
||||
|
export function createLocalizer(localization: ApplicationConfiguration.Localization) { |
||||
|
return (resourceName: string, key: string, defaultValue: string) => { |
||||
|
if (resourceName === '_') return key; |
||||
|
|
||||
|
const resource = localization.values[resourceName]; |
||||
|
|
||||
|
if (!resource) return defaultValue; |
||||
|
|
||||
|
return resource[key] || defaultValue; |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
export function createLocalizerWithFallback(localization: ApplicationConfiguration.Localization) { |
||||
|
const findLocalization = createLocalizationFinder(localization); |
||||
|
|
||||
|
return (resourceNames: string[], keys: string[], defaultValue: string) => { |
||||
|
const { localized } = findLocalization(resourceNames, keys); |
||||
|
return localized || defaultValue; |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
export function createLocalizationPipeKeyGenerator( |
||||
|
localization: ApplicationConfiguration.Localization, |
||||
|
) { |
||||
|
const findLocalization = createLocalizationFinder(localization); |
||||
|
|
||||
|
return (resourceNames: string[], keys: string[], defaultKey: string) => { |
||||
|
const { resourceName, key } = findLocalization(resourceNames, keys); |
||||
|
return !resourceName ? defaultKey : resourceName === '_' ? key : `${resourceName}::${key}`; |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
function createLocalizationFinder(localization: ApplicationConfiguration.Localization) { |
||||
|
const localize = createLocalizer(localization); |
||||
|
|
||||
|
return (resourceNames: string[], keys: string[]) => { |
||||
|
resourceNames = resourceNames.concat(localization.defaultResourceName).filter(Boolean); |
||||
|
|
||||
|
const resourceCount = resourceNames.length; |
||||
|
const keyCount = keys.length; |
||||
|
|
||||
|
for (let i = 0; i < resourceCount; i++) { |
||||
|
const resourceName = resourceNames[i]; |
||||
|
|
||||
|
for (let j = 0; j < keyCount; j++) { |
||||
|
const key = keys[j]; |
||||
|
const localized = localize(resourceName, key, null); |
||||
|
if (localized) return { resourceName, key, localized }; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return { resourceName: undefined, key: undefined, localized: undefined }; |
||||
|
}; |
||||
|
} |
||||
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue