using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using System.Text.Json; using System.Threading.Tasks; using Microsoft.AspNetCore.Authorization; using Sozsoft.Platform.Entities; using Sozsoft.Platform.ListForms; using Volo.Abp; using Volo.Abp.Application.Dtos; using Volo.Abp.Application.Services; using Volo.Abp.AuditLogging; using Volo.Abp.Domain.Repositories; using Volo.Abp.Uow; using static Sozsoft.Platform.Data.Seeds.SeedConsts; namespace Sozsoft.Platform.AuditLogs; public interface IAuditLogAppService : ICrudAppService { } [Authorize(AppCodes.IdentityManagement.AuditLogs)] public class AuditLogAppService : CrudAppService< AuditLog, AuditLogDto, Guid, AuditLogListRequestDto>, IAuditLogAppService { private readonly IRepository _listFormRepository; public AuditLogAppService( IAuditLogRepository auditLogRepository, IRepository listFormRepository ) : base(auditLogRepository) { _listFormRepository = listFormRepository; } public override async Task GetAsync(Guid id) { var entity = await Repository.GetAsync(id, includeDetails: true); return await MapToGetOutputDtoAsync(entity); } [UnitOfWork] public override async Task> GetListAsync(AuditLogListRequestDto input) { var query = await Repository.WithDetailsAsync(); if (!input.ListFormCode.IsNullOrWhiteSpace()) { var filterRules = await GetListFormFilterRulesAsync(input.ListFormCode); query = ApplyAuditLogActionParametersFilter(query, filterRules, input.EntityId); } else if (!input.EntityId.IsNullOrWhiteSpace()) { query = query.Where(a => a.Actions.Any(action => action.Parameters.Contains(input.EntityId))); } var totalCount = await AsyncExecuter.CountAsync(query); query = ApplySorting(query, input); query = ApplyPaging(query, input); var auditLogsWithDetails = await AsyncExecuter.ToListAsync(query); // Mapping tek seferde yap var entityDtos = ObjectMapper.Map, List>(auditLogsWithDetails); // EntityChangeCount'u doldur (artık EntityChanges yüklü) foreach (var dto in entityDtos) { var auditLog = auditLogsWithDetails.FirstOrDefault(a => a.Id == dto.Id); dto.EntityChangeCount = auditLog?.EntityChanges?.Count ?? 0; } return new PagedResultDto( totalCount, entityDtos ); } private async Task> GetListFormFilterRulesAsync(string listFormCode) { var rules = new List { new(listFormCode, null) }; var listForm = await _listFormRepository.FirstOrDefaultAsync(a => a.ListFormCode == listFormCode); if (listForm?.SubFormsJson.IsNullOrWhiteSpace() != false) { return rules; } try { var subForms = JsonSerializer.Deserialize>(listForm.SubFormsJson) ?? []; foreach (var subForm in subForms.Where(a => !a.Code.IsNullOrWhiteSpace())) { var childFieldNames = subForm.Relation? .Select(a => a.ChildFieldName) .Where(a => !a.IsNullOrWhiteSpace()) .Distinct(StringComparer.OrdinalIgnoreCase) .ToList() ?? []; rules.AddRange(childFieldNames.Select(childFieldName => new AuditLogListFormFilterRule(subForm.Code, childFieldName))); } } catch (JsonException) { // Invalid subform JSON should not block audit log listing for the main form. } return rules .DistinctBy(a => $"{a.ListFormCode}|{a.ChildFieldName}".ToLowerInvariant()) .ToList(); } private static IQueryable ApplyAuditLogActionParametersFilter( IQueryable query, List rules, string entityId) { var validRules = rules .Where(rule => !rule.ListFormCode.IsNullOrWhiteSpace()) .ToList(); if (validRules.Count == 0) { return query; } var auditLog = Expression.Parameter(typeof(AuditLog), "auditLog"); var action = Expression.Parameter(typeof(AuditLogAction), "action"); var parameters = Expression.Property(action, nameof(AuditLogAction.Parameters)); Expression actionBody = Expression.Constant(false); foreach (var rule in validRules) { Expression ruleBody = Contains(parameters, rule.ListFormCode); if (!entityId.IsNullOrWhiteSpace()) { ruleBody = Expression.AndAlso(ruleBody, Contains(parameters, entityId)); } if (!rule.ChildFieldName.IsNullOrWhiteSpace()) { ruleBody = Expression.AndAlso(ruleBody, Contains(parameters, rule.ChildFieldName)); } actionBody = Expression.OrElse(actionBody, ruleBody); } var actions = Expression.Property(auditLog, nameof(AuditLog.Actions)); var actionPredicate = Expression.Lambda>(actionBody, action); var anyCall = Expression.Call( typeof(Enumerable), nameof(Enumerable.Any), [typeof(AuditLogAction)], actions, actionPredicate); var auditLogPredicate = Expression.Lambda>(anyCall, auditLog); return query.Where(auditLogPredicate); } private static MethodCallExpression Contains(MemberExpression source, string value) { return Expression.Call( source, nameof(string.Contains), Type.EmptyTypes, Expression.Constant(value)); } private sealed record AuditLogListFormFilterRule(string ListFormCode, string? ChildFieldName); // Audit Log kayitlarini gormek istiyoruz fakat degistirmek istemiyoruz [RemoteService(IsEnabled = false)] public override Task CreateAsync(AuditLogDto input) { return null; } [RemoteService(IsEnabled = false)] public override Task UpdateAsync(Guid id, AuditLogDto input) { return null; } [RemoteService(IsEnabled = false)] public override Task DeleteAsync(Guid id) { return null; } }