|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 4.5 KiB |
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 4.1 KiB |
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 142 KiB After Width: | Height: | Size: 40 KiB |
|
Before Width: | Height: | Size: 135 KiB After Width: | Height: | Size: 29 KiB |
@ -1,86 +1,16 @@ |
|||||
using System; |
using System; |
||||
using System.Threading.Tasks; |
|
||||
using Duende.IdentityModel.Client; |
|
||||
using Microsoft.AspNetCore.Authentication.OpenIdConnect; |
|
||||
using Microsoft.Extensions.DependencyInjection; |
using Microsoft.Extensions.DependencyInjection; |
||||
using Microsoft.Extensions.Logging; |
|
||||
using Microsoft.Extensions.Options; |
|
||||
using Volo.Abp.Threading; |
|
||||
|
|
||||
namespace Microsoft.AspNetCore.Authentication.Cookies; |
namespace Microsoft.AspNetCore.Authentication.Cookies; |
||||
|
|
||||
public static class CookieAuthenticationOptionsExtensions |
public static class CookieAuthenticationOptionsExtensions |
||||
{ |
{ |
||||
/// <summary>
|
/// <summary>
|
||||
/// Introspect access token on validating the principal.
|
/// Check the access_token is expired or inactive.
|
||||
/// </summary>
|
/// </summary>
|
||||
/// <param name="options"></param>
|
[Obsolete("Use CheckTokenExpiration method instead.")] |
||||
/// <param name="oidcAuthenticationScheme"></param>
|
|
||||
/// <returns></returns>
|
|
||||
public static CookieAuthenticationOptions IntrospectAccessToken(this CookieAuthenticationOptions options, string oidcAuthenticationScheme = "oidc") |
public static CookieAuthenticationOptions IntrospectAccessToken(this CookieAuthenticationOptions options, string oidcAuthenticationScheme = "oidc") |
||||
{ |
{ |
||||
options.Events.OnValidatePrincipal = async principalContext => |
return options.CheckTokenExpiration(oidcAuthenticationScheme, null, TimeSpan.FromMinutes(1)); |
||||
{ |
|
||||
if (principalContext.Principal == null || principalContext.Principal.Identity == null || !principalContext.Principal.Identity.IsAuthenticated) |
|
||||
{ |
|
||||
return; |
|
||||
} |
|
||||
|
|
||||
var logger = principalContext.HttpContext.RequestServices.GetRequiredService<ILogger<CookieAuthenticationOptions>>(); |
|
||||
|
|
||||
var accessToken = principalContext.Properties.GetTokenValue("access_token"); |
|
||||
if (!accessToken.IsNullOrWhiteSpace()) |
|
||||
{ |
|
||||
var openIdConnectOptions = await GetOpenIdConnectOptions(principalContext, oidcAuthenticationScheme); |
|
||||
var response = await openIdConnectOptions.Backchannel.IntrospectTokenAsync(new TokenIntrospectionRequest |
|
||||
{ |
|
||||
Address = openIdConnectOptions.Configuration?.IntrospectionEndpoint ?? openIdConnectOptions.Authority!.EnsureEndsWith('/') + "connect/introspect", |
|
||||
ClientId = openIdConnectOptions.ClientId!, |
|
||||
ClientSecret = openIdConnectOptions.ClientSecret, |
|
||||
Token = accessToken |
|
||||
}); |
|
||||
|
|
||||
if (response.IsError) |
|
||||
{ |
|
||||
logger.LogError(response.Error); |
|
||||
await SignOutAsync(principalContext); |
|
||||
return; |
|
||||
} |
|
||||
|
|
||||
if (!response.IsActive) |
|
||||
{ |
|
||||
logger.LogError("The access_token is not active."); |
|
||||
await SignOutAsync(principalContext); |
|
||||
return; |
|
||||
} |
|
||||
|
|
||||
logger.LogInformation("The access_token is active."); |
|
||||
} |
|
||||
else |
|
||||
{ |
|
||||
logger.LogError("The access_token is not found in the cookie properties, Please make sure SaveTokens of OpenIdConnectOptions is set as true."); |
|
||||
await SignOutAsync(principalContext); |
|
||||
} |
|
||||
}; |
|
||||
|
|
||||
return options; |
|
||||
} |
|
||||
|
|
||||
private async static Task<OpenIdConnectOptions> GetOpenIdConnectOptions(CookieValidatePrincipalContext principalContext, string oidcAuthenticationScheme) |
|
||||
{ |
|
||||
var openIdConnectOptions = principalContext.HttpContext.RequestServices.GetRequiredService<IOptionsMonitor<OpenIdConnectOptions>>().Get(oidcAuthenticationScheme); |
|
||||
if (openIdConnectOptions.Configuration == null && openIdConnectOptions.ConfigurationManager != null) |
|
||||
{ |
|
||||
var cancellationTokenProvider = principalContext.HttpContext.RequestServices.GetRequiredService<ICancellationTokenProvider>(); |
|
||||
openIdConnectOptions.Configuration = await openIdConnectOptions.ConfigurationManager.GetConfigurationAsync(cancellationTokenProvider.Token); |
|
||||
} |
|
||||
|
|
||||
return openIdConnectOptions; |
|
||||
} |
|
||||
|
|
||||
private async static Task SignOutAsync(CookieValidatePrincipalContext principalContext) |
|
||||
{ |
|
||||
principalContext.RejectPrincipal(); |
|
||||
await principalContext.HttpContext.SignOutAsync(principalContext.Scheme.Name); |
|
||||
} |
} |
||||
} |
} |
||||
|
|||||
@ -1,84 +1,43 @@ |
|||||
using System; |
using System; |
||||
using System.Globalization; |
|
||||
using System.Linq; |
using System.Linq; |
||||
using System.Text.Json; |
using System.Text.Json; |
||||
using System.Text.Json.Serialization; |
|
||||
using Microsoft.Extensions.Options; |
using Microsoft.Extensions.Options; |
||||
using Volo.Abp.DependencyInjection; |
using Volo.Abp.DependencyInjection; |
||||
using Volo.Abp.Timing; |
using Volo.Abp.Timing; |
||||
|
|
||||
namespace Volo.Abp.Json.SystemTextJson.JsonConverters; |
namespace Volo.Abp.Json.SystemTextJson.JsonConverters; |
||||
|
|
||||
public class AbpDateTimeConverter : JsonConverter<DateTime>, ITransientDependency |
public class AbpDateTimeConverter : AbpDateTimeConverterBase<DateTime>, ITransientDependency |
||||
{ |
{ |
||||
private readonly IClock _clock; |
public AbpDateTimeConverter( |
||||
private readonly AbpJsonOptions _options; |
IClock clock, |
||||
private bool _skipDateTimeNormalization; |
IOptions<AbpJsonOptions> abpJsonOptions, |
||||
|
ICurrentTimezoneProvider currentTimezoneProvider, |
||||
public AbpDateTimeConverter(IClock clock, IOptions<AbpJsonOptions> abpJsonOptions) |
ITimezoneProvider timezoneProvider) |
||||
|
: base(clock, abpJsonOptions, currentTimezoneProvider, timezoneProvider) |
||||
{ |
{ |
||||
_clock = clock; |
|
||||
_options = abpJsonOptions.Value; |
|
||||
} |
} |
||||
|
|
||||
public virtual AbpDateTimeConverter SkipDateTimeNormalization() |
public virtual AbpDateTimeConverter SkipDateTimeNormalization() |
||||
{ |
{ |
||||
_skipDateTimeNormalization = true; |
IsSkipDateTimeNormalization = true; |
||||
return this; |
return this; |
||||
} |
} |
||||
|
|
||||
public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) |
public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) |
||||
{ |
{ |
||||
if (_options.InputDateTimeFormats.Any()) |
if (Options.InputDateTimeFormats.Any() && reader.TokenType != JsonTokenType.String) |
||||
{ |
|
||||
if (reader.TokenType == JsonTokenType.String) |
|
||||
{ |
|
||||
foreach (var format in _options.InputDateTimeFormats) |
|
||||
{ |
|
||||
var s = reader.GetString(); |
|
||||
if (DateTime.TryParseExact(s, format, CultureInfo.CurrentUICulture, DateTimeStyles.None, out var d1)) |
|
||||
{ |
|
||||
return Normalize(d1); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
else |
|
||||
{ |
|
||||
throw new JsonException("Reader's TokenType is not String!"); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
if (reader.TryGetDateTime(out var d3)) |
|
||||
{ |
|
||||
return Normalize(d3); |
|
||||
} |
|
||||
|
|
||||
var dateText = reader.GetString(); |
|
||||
if (!dateText.IsNullOrWhiteSpace()) |
|
||||
{ |
{ |
||||
if (DateTime.TryParse(dateText, CultureInfo.CurrentUICulture, DateTimeStyles.None, out var d4)) |
throw new JsonException("Reader's TokenType is not String!"); |
||||
{ |
|
||||
return Normalize(d4); |
|
||||
} |
|
||||
} |
} |
||||
|
|
||||
throw new JsonException("Can't get datetime from the reader!"); |
return TryReadDateTime(ref reader, out var result) |
||||
|
? result |
||||
|
: throw new JsonException("Can't get datetime from the reader!"); |
||||
} |
} |
||||
|
|
||||
public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options) |
public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options) |
||||
{ |
{ |
||||
if (_options.OutputDateTimeFormat.IsNullOrWhiteSpace()) |
WriteDateTime(writer, value); |
||||
{ |
|
||||
writer.WriteStringValue(Normalize(value)); |
|
||||
} |
|
||||
else |
|
||||
{ |
|
||||
writer.WriteStringValue(Normalize(value).ToString(_options.OutputDateTimeFormat, CultureInfo.CurrentUICulture)); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
protected virtual DateTime Normalize(DateTime dateTime) |
|
||||
{ |
|
||||
return _skipDateTimeNormalization ? dateTime : _clock.Normalize(dateTime); |
|
||||
} |
} |
||||
} |
} |
||||
|
|||||
@ -0,0 +1,116 @@ |
|||||
|
using System; |
||||
|
using System.Globalization; |
||||
|
using System.Linq; |
||||
|
using System.Text.Json; |
||||
|
using System.Text.Json.Serialization; |
||||
|
using Microsoft.Extensions.Logging; |
||||
|
using Microsoft.Extensions.Logging.Abstractions; |
||||
|
using Microsoft.Extensions.Options; |
||||
|
using Volo.Abp.Timing; |
||||
|
|
||||
|
namespace Volo.Abp.Json.SystemTextJson.JsonConverters; |
||||
|
|
||||
|
public abstract class AbpDateTimeConverterBase<T> : JsonConverter<T> |
||||
|
{ |
||||
|
public ILogger<AbpDateTimeConverterBase<T>> Logger { get; set; } |
||||
|
|
||||
|
protected IClock Clock { get; } |
||||
|
protected AbpJsonOptions Options { get; } |
||||
|
protected ICurrentTimezoneProvider CurrentTimezoneProvider { get; } |
||||
|
protected ITimezoneProvider TimezoneProvider { get; } |
||||
|
protected bool IsSkipDateTimeNormalization { get; set; } |
||||
|
|
||||
|
protected AbpDateTimeConverterBase( |
||||
|
IClock clock, |
||||
|
IOptions<AbpJsonOptions> abpJsonOptions, |
||||
|
ICurrentTimezoneProvider currentTimezoneProvider, |
||||
|
ITimezoneProvider timezoneProvider) |
||||
|
{ |
||||
|
Logger = NullLogger<AbpDateTimeConverterBase<T>>.Instance; |
||||
|
|
||||
|
Clock = clock; |
||||
|
CurrentTimezoneProvider = currentTimezoneProvider; |
||||
|
TimezoneProvider = timezoneProvider; |
||||
|
Options = abpJsonOptions.Value; |
||||
|
} |
||||
|
|
||||
|
protected bool TryReadDateTime(ref Utf8JsonReader reader, out DateTime value) |
||||
|
{ |
||||
|
value = default; |
||||
|
|
||||
|
if (Options.InputDateTimeFormats.Any()) |
||||
|
{ |
||||
|
if (reader.TokenType != JsonTokenType.String) |
||||
|
{ |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
var s = reader.GetString(); |
||||
|
foreach (var format in Options.InputDateTimeFormats) |
||||
|
{ |
||||
|
if (!DateTime.TryParseExact(s, format, CultureInfo.CurrentUICulture, DateTimeStyles.None, out var d1)) |
||||
|
{ |
||||
|
continue; |
||||
|
} |
||||
|
|
||||
|
value = Normalize(d1); |
||||
|
return true; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
if (reader.TryGetDateTime(out var d2)) |
||||
|
{ |
||||
|
value = Normalize(d2); |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
var dateText = reader.GetString(); |
||||
|
if (dateText.IsNullOrWhiteSpace()) |
||||
|
{ |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
if (!DateTime.TryParse(dateText, CultureInfo.CurrentUICulture, DateTimeStyles.None, out var d3)) |
||||
|
{ |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
value = Normalize(d3); |
||||
|
return true; |
||||
|
|
||||
|
} |
||||
|
|
||||
|
protected void WriteDateTime(Utf8JsonWriter writer, DateTime value) |
||||
|
{ |
||||
|
if (Options.OutputDateTimeFormat.IsNullOrWhiteSpace()) |
||||
|
{ |
||||
|
writer.WriteStringValue(Normalize(value)); |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
writer.WriteStringValue(Normalize(value).ToString(Options.OutputDateTimeFormat, CultureInfo.CurrentUICulture)); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
protected virtual DateTime Normalize(DateTime dateTime) |
||||
|
{ |
||||
|
if (dateTime.Kind != DateTimeKind.Unspecified || |
||||
|
!Clock.SupportsMultipleTimezone || |
||||
|
CurrentTimezoneProvider.TimeZone.IsNullOrWhiteSpace()) |
||||
|
{ |
||||
|
return IsSkipDateTimeNormalization ? dateTime : Clock.Normalize(dateTime); |
||||
|
} |
||||
|
|
||||
|
try |
||||
|
{ |
||||
|
var timezoneInfo = TimezoneProvider.GetTimeZoneInfo(CurrentTimezoneProvider.TimeZone); |
||||
|
dateTime = new DateTimeOffset(dateTime, timezoneInfo.GetUtcOffset(dateTime)).UtcDateTime; |
||||
|
} |
||||
|
catch |
||||
|
{ |
||||
|
Logger.LogWarning("Could not convert DateTime with unspecified Kind using timezone '{TimeZone}'.", CurrentTimezoneProvider.TimeZone); |
||||
|
} |
||||
|
|
||||
|
return IsSkipDateTimeNormalization ? dateTime : Clock.Normalize(dateTime); |
||||
|
} |
||||
|
} |
||||
@ -1,45 +1,61 @@ |
|||||
<div class="abp-lookup-container position-relative"> |
<div class="abp-lookup-container position-relative"> |
||||
@if (label()) { |
@if (label()) { |
||||
<label class="form-label">{{ label() | abpLocalization }}</label> |
<label class="form-label">{{ label() | abpLocalization }}</label> |
||||
} |
} |
||||
|
|
||||
<div class="input-group"> |
<div class="input-group"> |
||||
<input type="text" class="form-control" [placeholder]="placeholder() | abpLocalization" [ngModel]="displayValue()" |
<input |
||||
(ngModelChange)="onSearchInput($event)" (focus)="onSearchFocus()" (blur)="onSearchBlur($event)" |
type="text" |
||||
[disabled]="disabled()" /> |
class="form-control" |
||||
|
[placeholder]="placeholder() | abpLocalization" |
||||
|
[ngModel]="displayValue()" |
||||
|
(ngModelChange)="onSearchInput($event)" |
||||
|
(focus)="onSearchFocus()" |
||||
|
(blur)="onSearchBlur($event)" |
||||
|
[disabled]="disabled()" |
||||
|
/> |
||||
@if (displayValue() && !disabled()) { |
@if (displayValue() && !disabled()) { |
||||
<button type="button" class="btn btn-outline-secondary" (mousedown)="clearSelection()" tabindex="-1"> |
<button |
||||
<i class="fa fa-times"></i> |
type="button" |
||||
</button> |
class="btn btn-outline-secondary" |
||||
|
(mousedown)="clearSelection()" |
||||
|
tabindex="-1" |
||||
|
> |
||||
|
<i class="fa fa-times"></i> |
||||
|
</button> |
||||
} |
} |
||||
</div> |
</div> |
||||
|
|
||||
@if (showDropdown() && !disabled()) { |
@if (showDropdown() && !disabled()) { |
||||
<div class="abp-lookup-dropdown list-group position-absolute w-100 shadow"> |
<div class="abp-lookup-dropdown list-group position-absolute w-100"> |
||||
@if (isLoading()) { |
@if (isLoading()) { |
||||
<div class="list-group-item text-center py-3"> |
<div class="list-group-item text-center py-3"> |
||||
<i class="fa fa-spinner fa-spin me-2"></i> |
<i class="fa fa-spinner fa-spin me-2"></i> |
||||
{{ 'AbpUi::Loading' | abpLocalization }} |
{{ 'AbpUi::Loading' | abpLocalization }} |
||||
</div> |
</div> |
||||
} @else if (searchResults().length > 0) { |
} @else if (searchResults().length > 0) { |
||||
@for (item of searchResults(); track item.key) { |
@for (item of searchResults(); track item.key) { |
||||
<button type="button" class="list-group-item list-group-item-action" (mousedown)="selectItem(item)"> |
<button |
||||
@if (itemTemplate()) { |
type="button" |
||||
<ng-container *ngTemplateOutlet="itemTemplate()!; context: { $implicit: item }" /> |
class="list-group-item list-group-item-action" |
||||
} @else { |
(mousedown)="selectItem(item)" |
||||
{{ getDisplayValue(item) }} |
> |
||||
|
@if (itemTemplate()) { |
||||
|
<ng-container *ngTemplateOutlet="itemTemplate()!; context: { $implicit: item }" /> |
||||
|
} @else { |
||||
|
{{ getDisplayValue(item) }} |
||||
|
} |
||||
|
</button> |
||||
|
} |
||||
|
} @else if (displayValue()) { |
||||
|
@if (noResultsTemplate()) { |
||||
|
<ng-container *ngTemplateOutlet="noResultsTemplate()!" /> |
||||
|
} @else { |
||||
|
<div class="list-group-item text-muted"> |
||||
|
{{ 'AbpUi::NoDataAvailableInDatatable' | abpLocalization }} |
||||
|
</div> |
||||
|
} |
||||
} |
} |
||||
</button> |
|
||||
} |
|
||||
} @else if (displayValue()) { |
|
||||
@if (noResultsTemplate()) { |
|
||||
<ng-container *ngTemplateOutlet="noResultsTemplate()!" /> |
|
||||
} @else { |
|
||||
<div class="list-group-item text-muted"> |
|
||||
{{ 'AbpUi::NoRecordsFound' | abpLocalization }} |
|
||||
</div> |
</div> |
||||
} |
|
||||
} |
|
||||
</div> |
|
||||
} |
} |
||||
</div> |
</div> |
||||
|
|||||
@ -1,5 +1,8 @@ |
|||||
.abp-lookup-dropdown { |
.abp-lookup-dropdown { |
||||
z-index: 1050; |
z-index: 1060; |
||||
max-height: 200px; |
max-height: 200px; |
||||
overflow-y: auto; |
overflow-y: auto; |
||||
|
top: 100%; |
||||
|
margin-top: 0.25rem; |
||||
|
background-color: var(--lpx-content-bg); |
||||
} |
} |
||||
|
|||||
@ -1,25 +1,33 @@ |
|||||
<div class="mb-3"> |
<div class="mb-3"> |
||||
@if (showTitle()) { |
@if (showTitle()) { |
||||
<h5>{{ title() | abpLocalization }}</h5> |
<h5>{{ title() | abpLocalization }}</h5> |
||||
} |
} |
||||
<div class="form-check form-switch mb-2"> |
<div class="form-check form-switch mb-2"> |
||||
<input class="form-check-input" type="checkbox" id="grantAll-{{ idPrefix() }}" |
<input |
||||
[checked]="state.allPermissionsSelected()" |
class="form-check-input" |
||||
(change)="state.toggleAllPermissions(!state.allPermissionsSelected())" /> |
type="checkbox" |
||||
<label class="form-check-label" for="grantAll-{{ idPrefix() }}"> |
id="grantAll-{{ idPrefix() }}" |
||||
{{ 'AbpPermissionManagement::GrantAllResourcePermissions' | abpLocalization }} |
[checked]="state.allPermissionsSelected()" |
||||
|
(change)="state.toggleAllPermissions(!state.allPermissionsSelected())" |
||||
|
/> |
||||
|
<label class="form-check-label" for="grantAll-{{ idPrefix() }}"> |
||||
|
{{ 'AbpPermissionManagement::GrantAllResourcePermissions' | abpLocalization }} |
||||
|
</label> |
||||
|
</div> |
||||
|
<div class="abp-permission-list-container border rounded p-3"> |
||||
|
@for (perm of permissions(); track perm.name) { |
||||
|
<div class="form-check"> |
||||
|
<input |
||||
|
class="form-check-input" |
||||
|
type="checkbox" |
||||
|
id="perm-{{ idPrefix() }}-{{ perm.name }}" |
||||
|
[checked]="state.isPermissionSelected(perm.name || '')" |
||||
|
(change)="state.togglePermission(perm.name || '')" |
||||
|
/> |
||||
|
<label class="form-check-label" for="perm-{{ idPrefix() }}-{{ perm.name }}"> |
||||
|
{{ perm.displayName }} |
||||
</label> |
</label> |
||||
</div> |
</div> |
||||
<div class="abp-permission-list-container border rounded p-3"> |
} |
||||
@for (perm of permissions(); track perm.name) { |
</div> |
||||
<div class="form-check"> |
</div> |
||||
<input class="form-check-input" type="checkbox" id="perm-{{ idPrefix() }}-{{ perm.name }}" |
|
||||
[checked]="state.isPermissionSelected(perm.name || '')" |
|
||||
(change)="state.togglePermission(perm.name || '')" /> |
|
||||
<label class="form-check-label" for="perm-{{ idPrefix() }}-{{ perm.name }}"> |
|
||||
{{ perm.displayName }} |
|
||||
</label> |
|
||||
</div> |
|
||||
} |
|
||||
</div> |
|
||||
</div> |
|
||||
|
|||||
@ -1,4 +1,10 @@ |
|||||
<abp-lookup-search label="AbpPermissionManagement::SearchProviderKey" |
<abp-lookup-search |
||||
placeholder="AbpPermissionManagement::SearchProviderKey" [searchFn]="searchFn" [displayValue]="state.searchFilter()" |
label="AbpPermissionManagement::SearchProviderKey" |
||||
(displayValueChange)="state.searchFilter.set($event)" [selectedValue]="state.selectedProviderKey()" |
placeholder="AbpPermissionManagement::SearchProviderKey" |
||||
(selectedValueChange)="state.selectedProviderKey.set($event)" (itemSelected)="onItemSelected($event)" /> |
[searchFn]="searchFn" |
||||
|
[displayValue]="state.searchFilter()" |
||||
|
(displayValueChange)="state.searchFilter.set($event)" |
||||
|
[selectedValue]="state.selectedProviderKey()" |
||||
|
(selectedValueChange)="state.selectedProviderKey.set($event)" |
||||
|
(itemSelected)="onItemSelected($event)" |
||||
|
/> |
||||
|
|||||
@ -1,28 +1,37 @@ |
|||||
@if (mode() === eResourcePermissionViewModes.Add) { |
@if (mode() === eResourcePermissionViewModes.Add) { |
||||
<div class="mb-3"> |
<div class="mb-3"> |
||||
<label class="form-label fw-bold"> |
<label class="form-label fw-bold"> |
||||
{{ 'AbpPermissionManagement::SelectProvider' | abpLocalization }} |
{{ 'AbpPermissionManagement::SelectProvider' | abpLocalization }} |
||||
</label> |
</label> |
||||
<div class="mb-2"> |
<div class="mb-2"> |
||||
@for (provider of state.providers(); track provider.name; let i = $index) { |
@for (provider of state.providers(); track provider.name; let i = $index) { |
||||
<div class="form-check form-check-inline"> |
<div class="form-check form-check-inline"> |
||||
<input class="form-check-input" type="radio" [id]="'provider-' + i" [value]="provider.name" |
<input |
||||
[checked]="state.selectedProviderName() === provider.name" |
class="form-check-input" |
||||
(change)="state.onProviderChange(provider.name || '')" /> |
type="radio" |
||||
<label class="form-check-label" [for]="'provider-' + i"> |
[id]="'provider-' + i" |
||||
{{ provider.displayName }} |
[value]="provider.name" |
||||
</label> |
[checked]="state.selectedProviderName() === provider.name" |
||||
|
(change)="state.onProviderChange(provider.name || '')" |
||||
|
/> |
||||
|
<label class="form-check-label" [for]="'provider-' + i"> |
||||
|
{{ provider.displayName }} |
||||
|
</label> |
||||
</div> |
</div> |
||||
} |
} |
||||
</div> |
</div> |
||||
|
|
||||
<abp-provider-key-search [resourceName]="resourceName()" /> |
<abp-provider-key-search [resourceName]="resourceName()" /> |
||||
</div> |
</div> |
||||
|
|
||||
<abp-permission-checkbox-list [permissions]="state.permissionDefinitions()" idPrefix="add" /> |
<abp-permission-checkbox-list [permissions]="state.permissionDefinitions()" idPrefix="add" /> |
||||
} @else { |
} @else { |
||||
<div class="mb-3" id="permissionList"> |
<div class="mb-3" id="permissionList"> |
||||
<h4>{{ 'AbpPermissionManagement::Permissions' | abpLocalization }}</h4> |
<h4>{{ 'AbpPermissionManagement::Permissions' | abpLocalization }}</h4> |
||||
<abp-permission-checkbox-list [permissions]="state.permissionsWithProvider()" idPrefix="edit" [showTitle]="false" /> |
<abp-permission-checkbox-list |
||||
</div> |
[permissions]="state.permissionsWithProvider()" |
||||
} |
idPrefix="edit" |
||||
|
[showTitle]="false" |
||||
|
/> |
||||
|
</div> |
||||
|
} |
||||
|
|||||
@ -1,60 +1,67 @@ |
|||||
<abp-modal [(visible)]="visible" [busy]="state.modalBusy()" [options]="{ size: 'xl', scrollable: false }"> |
<abp-modal |
||||
<ng-template #abpHeader> |
[(visible)]="visible" |
||||
<h5 class="modal-title"> |
[busy]="state.modalBusy()" |
||||
@switch (state.viewMode()) { |
[options]="{ size: 'xl', scrollable: false }" |
||||
@case (eResourcePermissionViewModes.Edit) { |
> |
||||
{{ 'AbpPermissionManagement::UpdatePermission' | abpLocalization }} |
<ng-template #abpHeader> |
||||
} |
<h5 class="modal-title"> |
||||
@case (eResourcePermissionViewModes.Add) { |
@switch (state.viewMode()) { |
||||
{{ 'AbpPermissionManagement::AddResourcePermission' | abpLocalization }} |
@case (eResourcePermissionViewModes.Edit) { |
||||
} |
{{ 'AbpPermissionManagement::UpdatePermission' | abpLocalization }} |
||||
@default { |
} |
||||
{{ 'AbpPermissionManagement::ResourcePermissions' | abpLocalization }} |
@case (eResourcePermissionViewModes.Add) { |
||||
@if (resourceDisplayName()) { |
{{ 'AbpPermissionManagement::AddResourcePermission' | abpLocalization }} |
||||
|
} |
||||
|
@default { |
||||
|
{{ 'AbpPermissionManagement::ResourcePermissions' | abpLocalization }} |
||||
|
@if (resourceDisplayName()) { |
||||
- {{ resourceDisplayName() }} |
- {{ resourceDisplayName() }} |
||||
} |
} |
||||
} |
} |
||||
} |
} |
||||
</h5> |
</h5> |
||||
</ng-template> |
</ng-template> |
||||
|
|
||||
<ng-template #abpBody> |
<ng-template #abpBody> |
||||
@if (!state.hasResourcePermission() || !state.hasProviderKeyLookupService()) { |
@if (!state.hasResourcePermission() || !state.hasProviderKeyLookupService()) { |
||||
<div class="alert alert-warning" role="alert"> |
<div class="alert alert-warning" role="alert"> |
||||
@if (!state.hasResourcePermission()) { |
@if (!state.hasResourcePermission()) { |
||||
{{ 'AbpPermissionManagement::NoResourcePermissionFound' | abpLocalization }} |
{{ 'AbpPermissionManagement::NoResourcePermissionFound' | abpLocalization }} |
||||
} @else { |
|
||||
{{ 'AbpPermissionManagement::NoResourceProviderKeyLookupServiceFound' | abpLocalization }} |
|
||||
} |
|
||||
</div> |
|
||||
} @else { |
} @else { |
||||
@switch (state.viewMode()) { |
{{ 'AbpPermissionManagement::NoResourceProviderKeyLookupServiceFound' | abpLocalization }} |
||||
|
} |
||||
|
</div> |
||||
|
} @else { |
||||
|
@switch (state.viewMode()) { |
||||
@case (eResourcePermissionViewModes.List) { |
@case (eResourcePermissionViewModes.List) { |
||||
<abp-resource-permission-list (addClicked)="onAddClicked()" (editClicked)="onEditClicked($event)" |
<abp-resource-permission-list |
||||
(deleteClicked)="onDeleteClicked($event)" /> |
(addClicked)="onAddClicked()" |
||||
|
(editClicked)="onEditClicked($event)" |
||||
|
(deleteClicked)="onDeleteClicked($event)" |
||||
|
/> |
||||
} |
} |
||||
@case (eResourcePermissionViewModes.Add) { |
@case (eResourcePermissionViewModes.Add) { |
||||
<abp-resource-permission-form mode="add" [resourceName]="resourceName()" /> |
<abp-resource-permission-form mode="add" [resourceName]="resourceName()" /> |
||||
} |
} |
||||
@case (eResourcePermissionViewModes.Edit) { |
@case (eResourcePermissionViewModes.Edit) { |
||||
<abp-resource-permission-form mode="edit" [resourceName]="resourceName()" /> |
<abp-resource-permission-form mode="edit" [resourceName]="resourceName()" /> |
||||
} |
|
||||
} |
|
||||
} |
} |
||||
</ng-template> |
} |
||||
|
} |
||||
|
</ng-template> |
||||
|
|
||||
<ng-template #abpFooter> |
<ng-template #abpFooter> |
||||
@if (state.isListMode()) { |
@if (state.isListMode()) { |
||||
<button type="button" class="btn btn-outline-primary" abpClose> |
<button type="button" class="btn btn-outline-primary" abpClose> |
||||
{{ 'AbpUi::Close' | abpLocalization }} |
{{ 'AbpUi::Close' | abpLocalization }} |
||||
</button> |
</button> |
||||
} @else { |
} @else { |
||||
<button type="button" class="btn btn-outline-secondary" (click)="state.goToListMode()"> |
<button type="button" class="btn btn-outline-secondary" (click)="state.goToListMode()"> |
||||
{{ 'AbpUi::Cancel' | abpLocalization }} |
{{ 'AbpUi::Cancel' | abpLocalization }} |
||||
</button> |
</button> |
||||
<abp-button iconClass="fa fa-check" (click)="savePermission()"> |
<abp-button iconClass="fa fa-check" (click)="savePermission()"> |
||||
{{ 'AbpUi::Save' | abpLocalization }} |
{{ 'AbpUi::Save' | abpLocalization }} |
||||
</abp-button> |
</abp-button> |
||||
} |
} |
||||
</ng-template> |
</ng-template> |
||||
</abp-modal> |
</abp-modal> |
||||
|
|||||
@ -1,32 +0,0 @@ |
|||||
using System.Collections.Generic; |
|
||||
using System.Threading.Tasks; |
|
||||
using Volo.Abp.DependencyInjection; |
|
||||
using Volo.Abp.EventBus; |
|
||||
using Volo.Abp.StaticDefinitions; |
|
||||
using Volo.Abp.TextTemplating; |
|
||||
using Volo.Abp.Threading; |
|
||||
|
|
||||
namespace Volo.Abp.TextTemplateManagement; |
|
||||
|
|
||||
public class StaticTemplateDefinitionChangedEventHandler : ILocalEventHandler<StaticTemplateDefinitionChangedEvent>, ITransientDependency |
|
||||
{ |
|
||||
protected IStaticDefinitionCache<TemplateDefinition, Dictionary<string, TemplateDefinition>> DefinitionCache { get; } |
|
||||
protected TextTemplateDynamicInitializer TextTemplateDynamicInitializer { get; } |
|
||||
protected ICancellationTokenProvider CancellationTokenProvider { get; } |
|
||||
|
|
||||
public StaticTemplateDefinitionChangedEventHandler( |
|
||||
IStaticDefinitionCache<TemplateDefinition, Dictionary<string, TemplateDefinition>> definitionCache, |
|
||||
TextTemplateDynamicInitializer textTemplateDynamicInitializer, |
|
||||
ICancellationTokenProvider cancellationTokenProvider) |
|
||||
{ |
|
||||
DefinitionCache = definitionCache; |
|
||||
TextTemplateDynamicInitializer = textTemplateDynamicInitializer; |
|
||||
CancellationTokenProvider = cancellationTokenProvider; |
|
||||
} |
|
||||
|
|
||||
public virtual async Task HandleEventAsync(StaticTemplateDefinitionChangedEvent eventData) |
|
||||
{ |
|
||||
await DefinitionCache.ClearAsync(); |
|
||||
await TextTemplateDynamicInitializer.InitializeAsync(false, CancellationTokenProvider.Token); |
|
||||
} |
|
||||
} |
|
||||