Skip to content
Merged

Dev #2379

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ public override void Define(IPermissionDefinitionContext context)

var analysisParent = aiPermissionsGroup.AddPermission(
AIPermissions.Analysis.AnalysisDefault,
L("Permission:AI.Analysis"));
L("Permission:AI.Analysis"))
.RequireFeatures("Unity.AI.Analysis");

var viewApplicationAnalysis = analysisParent.AddChild(
AIPermissions.Analysis.ViewApplicationAnalysis,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Unity.TenantManagement.Abstractions;
Expand All @@ -26,6 +27,10 @@ public class TenantAppService(
IUnitOfWorkManager unitOfWorkManager,
ITenantConnectionStringBuilder tenantConnectionStringBuilder) : TenantManagementAppServiceBase, ITenantAppService
{
private const string ExtraPropDivision = "Division";
private const string ExtraPropBranch = "Branch";
private const string ExtraPropDescription = "Description";
private const string ExtraPropCasClientCode = "CasClientCode";

public virtual async Task<TenantDto> GetAsync(Guid id)
{
Expand All @@ -41,20 +46,91 @@ public virtual async Task<PagedResultDto<TenantDto>> GetListAsync(GetTenantsInpu
input.Sorting = nameof(Tenant.Name);
}

var count = await tenantRepository.GetCountAsync(input.Filter);
var list = await tenantRepository.GetListAsync(
input.Sorting,
input.MaxResultCount,
input.SkipCount,
input.Filter
);
var sortParts = input.Sorting.Trim().Split(' ');
var sortField = sortParts[0].Trim();
var sortDescending = sortParts.Length > 1 && sortParts[1].Trim().Equals("DESC", StringComparison.OrdinalIgnoreCase);

var extraPropertySortFields = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
{
ExtraPropDivision, ExtraPropBranch, ExtraPropDescription, ExtraPropCasClientCode
};

var dbSortFields = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
{
nameof(Tenant.Id),
nameof(Tenant.Name),
nameof(Tenant.NormalizedName),
nameof(Tenant.CreationTime),
nameof(Tenant.LastModificationTime)
};

bool sortInMemory = extraPropertySortFields.Contains(sortField);
bool hasFilter = !input.Filter.IsNullOrWhiteSpace();

// Use fast DB path when sorting and filtering on native fields only
if (!sortInMemory && !hasFilter)
{
var count = await tenantRepository.GetCountAsync(input.Filter);
var list = await tenantRepository.GetListAsync(
input.Sorting,
input.MaxResultCount,
input.SkipCount,
input.Filter
);
return new PagedResultDto<TenantDto>(
count,
ObjectMapper.Map<List<Tenant>, List<TenantDto>>(list)
);
}

// In-memory path: needed when filtering on ExtraProperties or sorting on ExtraProperties
var dbSorting = dbSortFields.Contains(sortField) ? input.Sorting : nameof(Tenant.Name);
var allTenants = await tenantRepository.GetListAsync(dbSorting, int.MaxValue, 0, null);

IEnumerable<Tenant> result = allTenants;

// Apply ExtraProperties filter
if (hasFilter)
{
var filter = input.Filter.Trim();
result = result.Where(t =>
(t.Name != null && t.Name.Contains(filter, StringComparison.OrdinalIgnoreCase)) ||
MatchesExtraProperty(t, ExtraPropDivision, filter) ||
MatchesExtraProperty(t, ExtraPropBranch, filter) ||
MatchesExtraProperty(t, ExtraPropDescription, filter) ||
MatchesExtraProperty(t, ExtraPropCasClientCode, filter));
}

// Apply ExtraProperties sort
if (sortInMemory)
{
result = sortDescending
? result.OrderByDescending(t => GetExtraPropertyValue(t, sortField))
: result.OrderBy(t => GetExtraPropertyValue(t, sortField));
}

var resultList = result.ToList();
var paged = resultList.Skip(input.SkipCount).Take(input.MaxResultCount).ToList();

return new PagedResultDto<TenantDto>(
count,
ObjectMapper.Map<List<Tenant>, List<TenantDto>>(list)
resultList.Count,
ObjectMapper.Map<List<Tenant>, List<TenantDto>>(paged)
);
}

private static bool MatchesExtraProperty(Tenant tenant, string key, string filter)
{
return tenant.ExtraProperties.TryGetValue(key, out var value)
&& value?.ToString()?.Contains(filter, StringComparison.OrdinalIgnoreCase) == true;
}

private static string GetExtraPropertyValue(Tenant tenant, string key)
{
var entry = tenant.ExtraProperties
.FirstOrDefault(kv => kv.Key.Equals(key, StringComparison.OrdinalIgnoreCase));
return entry.Value?.ToString() ?? string.Empty;
}

[Authorize(TenantManagementPermissions.Tenants.Create)]
public virtual async Task<TenantDto> CreateAsync(TenantCreateDto input)
{
Expand All @@ -70,10 +146,10 @@ public virtual async Task<TenantDto> CreateAsync(TenantCreateDto input)
tenantConnectionStringBuilder.Build(tenant.Name)));

// Set ExtraProperties from input
tenant.ExtraProperties["Division"] = input.Division ?? string.Empty;
tenant.ExtraProperties["Branch"] = input.Branch ?? string.Empty;
tenant.ExtraProperties["Description"] = input.Description ?? string.Empty;
tenant.ExtraProperties["CasClientCode"] = input.CasClientCode ?? string.Empty;
tenant.ExtraProperties[ExtraPropDivision] = input.Division ?? string.Empty;
tenant.ExtraProperties[ExtraPropBranch] = input.Branch ?? string.Empty;
tenant.ExtraProperties[ExtraPropDescription] = input.Description ?? string.Empty;
tenant.ExtraProperties[ExtraPropCasClientCode] = input.CasClientCode ?? string.Empty;

await tenantRepository.InsertAsync(tenant);

Expand Down Expand Up @@ -106,10 +182,10 @@ public virtual async Task<TenantDto> UpdateAsync(Guid id, TenantUpdateDto input)
tenant.SetConcurrencyStampIfNotNull(input.ConcurrencyStamp);

// Update ExtraProperties from input
tenant.ExtraProperties["Division"] = input.Division ?? string.Empty;
tenant.ExtraProperties["Branch"] = input.Branch ?? string.Empty;
tenant.ExtraProperties["Description"] = input.Description ?? string.Empty;
tenant.ExtraProperties["CasClientCode"] = input.CasClientCode ?? string.Empty;
tenant.ExtraProperties[ExtraPropDivision] = input.Division ?? string.Empty;
tenant.ExtraProperties[ExtraPropBranch] = input.Branch ?? string.Empty;
tenant.ExtraProperties[ExtraPropDescription] = input.Description ?? string.Empty;
tenant.ExtraProperties[ExtraPropCasClientCode] = input.CasClientCode ?? string.Empty;

await tenantRepository.UpdateAsync(tenant);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@
[
{
title: l("Actions"),
orderable: false,
rowAction: {
items: abp.ui.extensions.entityActions.get('tenantManagement.tenant').actions.toArray()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,25 +39,31 @@ public override void Define(IFeatureDefinitionContext context)
.Create<GrantManagerResource>("Reporting"),
valueType: new ToggleStringValueType());

myGroup.AddFeature("Unity.AI.AttachmentSummaries",
myGroup.AddFeature("Unity.AIReporting",
defaultValue: defaultValue,
displayName: LocalizableString
.Create<GrantManagerResource>("AI Attachment Summaries"),
.Create<GrantManagerResource>("AI Reporting"),
valueType: new ToggleStringValueType());

myGroup.AddFeature("Unity.AI.ApplicationAnalysis",
var aiAnalysisFeature = myGroup.AddFeature("Unity.AI.Analysis",
defaultValue: defaultValue,
displayName: LocalizableString
.Create<GrantManagerResource>("AI Application Analysis"),
.Create<GrantManagerResource>("AI Analysis"),
valueType: new ToggleStringValueType());

myGroup.AddFeature("Unity.AIReporting",
aiAnalysisFeature.CreateChild("Unity.AI.AttachmentSummaries",
defaultValue: defaultValue,
displayName: LocalizableString
.Create<GrantManagerResource>("AI Reporting"),
.Create<GrantManagerResource>("AI Attachment Summaries"),
valueType: new ToggleStringValueType());

aiAnalysisFeature.CreateChild("Unity.AI.ApplicationAnalysis",
defaultValue: defaultValue,
displayName: LocalizableString
.Create<GrantManagerResource>("AI Application Analysis"),
valueType: new ToggleStringValueType());

myGroup.AddFeature("Unity.AI.Scoring",
aiAnalysisFeature.CreateChild("Unity.AI.Scoring",
defaultValue: defaultValue,
displayName: LocalizableString
.Create<GrantManagerResource>("AI Scoring"),
Expand Down
Loading
Loading