|
|
|
@ -0,0 +1,238 @@
|
|
|
|
|
using System.Net;
|
|
|
|
|
using NPin.Framework.AuditLogging.Domain.Entities;
|
|
|
|
|
using NPin.Framework.AuditLogging.Domain.Events;
|
|
|
|
|
using NPin.Framework.AuditLogging.Domain.Repositories;
|
|
|
|
|
using NPin.Framework.SqlSugarCore.Abstractions;
|
|
|
|
|
using NPin.Framework.SqlSugarCore.Repositories;
|
|
|
|
|
using SqlSugar;
|
|
|
|
|
using Volo.Abp.Auditing;
|
|
|
|
|
using Volo.Abp.Domain.Entities;
|
|
|
|
|
|
|
|
|
|
namespace NPin.Framework.AuditLogging.SqlSugarCore.Repositories;
|
|
|
|
|
|
|
|
|
|
public class AuditLogRepository : SqlSugarRepository<AuditLogAggregateRoot, Guid>, IAuditLogRepository
|
|
|
|
|
{
|
|
|
|
|
public AuditLogRepository(ISugarDbContextProvider<ISqlSugarDbContext> sugarDbContextProvider) : base(
|
|
|
|
|
sugarDbContextProvider)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 重写插入逻辑以支持关联关系(导航)
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="insertObj"></param>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
public override async Task<bool> InsertAsync(AuditLogAggregateRoot insertObj)
|
|
|
|
|
{
|
|
|
|
|
return await Db.InsertNav(insertObj)
|
|
|
|
|
.Include(z1 => z1.Actions)
|
|
|
|
|
// .Include(z1=>z1.EntityChanges)
|
|
|
|
|
// .ThenInclude(z2=>z2.PropertyChanges)
|
|
|
|
|
.ExecuteCommandAsync();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public async Task<Dictionary<DateTime, double>> GetAverageExecutionDurationPerDayAsync(DateTime startDate,
|
|
|
|
|
DateTime endDate,
|
|
|
|
|
CancellationToken cancellationToken = default)
|
|
|
|
|
{
|
|
|
|
|
// 分组排序查询
|
|
|
|
|
var result = await DbQueryable
|
|
|
|
|
.Where(a => a.ExecutionTime < endDate.AddDays(1) && a.ExecutionTime > startDate)
|
|
|
|
|
.OrderBy(t => t.ExecutionTime)
|
|
|
|
|
.GroupBy(g => new { g.ExecutionTime!.Value.Date })
|
|
|
|
|
.Select(s => new
|
|
|
|
|
{
|
|
|
|
|
Day = SqlFunc.AggregateMin(s.ExecutionTime),
|
|
|
|
|
avgExecutionTime = SqlFunc.AggregateAvg(s.ExecutionDuration)
|
|
|
|
|
})
|
|
|
|
|
.ToListAsync(cancellationToken);
|
|
|
|
|
|
|
|
|
|
// 散列为Dict
|
|
|
|
|
return result.ToDictionary(e => e.Day!.Value.ClearTime(), e => (double)e.avgExecutionTime!);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public async Task<List<AuditLogAggregateRoot>> GetListAsync(string sorting = null, int maxResultCount = 50,
|
|
|
|
|
int skipCount = 0, DateTime? startTime = null,
|
|
|
|
|
DateTime? endTime = null, string httpMethod = null, string url = null, Guid? userId = null,
|
|
|
|
|
string userName = null,
|
|
|
|
|
string applicationName = null, string clientIpAddress = null, string correlationId = null,
|
|
|
|
|
int? maxExecutionDuration = null, int? minExecutionDuration = null, bool? hasException = null,
|
|
|
|
|
HttpStatusCode? httpStatusCode = null, bool includeDetails = false)
|
|
|
|
|
{
|
|
|
|
|
var query = await GetListQueryAsync(
|
|
|
|
|
startTime,
|
|
|
|
|
endTime,
|
|
|
|
|
httpMethod,
|
|
|
|
|
url,
|
|
|
|
|
userId,
|
|
|
|
|
userName,
|
|
|
|
|
applicationName,
|
|
|
|
|
clientIpAddress,
|
|
|
|
|
correlationId,
|
|
|
|
|
maxExecutionDuration,
|
|
|
|
|
minExecutionDuration,
|
|
|
|
|
hasException,
|
|
|
|
|
httpStatusCode,
|
|
|
|
|
includeDetails
|
|
|
|
|
);
|
|
|
|
|
var auditLogs = await query
|
|
|
|
|
.OrderBy(sorting.IsNullOrWhiteSpace() ? $"{nameof(AuditLogAggregateRoot.ExecutionTime)} DESC" : sorting)
|
|
|
|
|
.ToPageListAsync(skipCount, maxResultCount);
|
|
|
|
|
return auditLogs;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public async Task<long> GetCountAsync(DateTime? startTime = null, DateTime? endTime = null,
|
|
|
|
|
string httpMethod = null,
|
|
|
|
|
string url = null,
|
|
|
|
|
Guid? userId = null, string userName = null, string applicationName = null, string clientIpAddress = null,
|
|
|
|
|
string correlationId = null, int? maxExecutionDuration = null, int? minExecutionDuration = null,
|
|
|
|
|
bool? hasException = null, HttpStatusCode? httpStatusCode = null, CancellationToken cancellationToken = default)
|
|
|
|
|
{
|
|
|
|
|
var query = await GetListQueryAsync(
|
|
|
|
|
startTime,
|
|
|
|
|
endTime,
|
|
|
|
|
httpMethod,
|
|
|
|
|
url,
|
|
|
|
|
userId,
|
|
|
|
|
userName,
|
|
|
|
|
applicationName,
|
|
|
|
|
clientIpAddress,
|
|
|
|
|
correlationId,
|
|
|
|
|
maxExecutionDuration,
|
|
|
|
|
minExecutionDuration,
|
|
|
|
|
hasException,
|
|
|
|
|
httpStatusCode
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
var totalCount = await query.CountAsync(cancellationToken);
|
|
|
|
|
|
|
|
|
|
return totalCount;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected virtual async Task<ISugarQueryable<AuditLogAggregateRoot>> GetListQueryAsync(
|
|
|
|
|
DateTime? startTime = null,
|
|
|
|
|
DateTime? endTime = null,
|
|
|
|
|
string httpMethod = null,
|
|
|
|
|
string url = null,
|
|
|
|
|
Guid? userId = null,
|
|
|
|
|
string userName = null,
|
|
|
|
|
string applicationName = null,
|
|
|
|
|
string clientIpAddress = null,
|
|
|
|
|
string correlationId = null,
|
|
|
|
|
int? maxExecutionDuration = null,
|
|
|
|
|
int? minExecutionDuration = null,
|
|
|
|
|
bool? hasException = null,
|
|
|
|
|
HttpStatusCode? httpStatusCode = null,
|
|
|
|
|
bool includeDetails = false)
|
|
|
|
|
{
|
|
|
|
|
var nHttpStatusCode = (int?)httpStatusCode;
|
|
|
|
|
return DbQueryable
|
|
|
|
|
.WhereIF(startTime.HasValue, auditLog => auditLog.ExecutionTime >= startTime)
|
|
|
|
|
.WhereIF(endTime.HasValue, auditLog => auditLog.ExecutionTime <= endTime)
|
|
|
|
|
.WhereIF(hasException.HasValue && hasException.Value,
|
|
|
|
|
auditLog => auditLog.Exceptions != null && auditLog.Exceptions != "")
|
|
|
|
|
.WhereIF(hasException.HasValue && !hasException.Value,
|
|
|
|
|
auditLog => auditLog.Exceptions == null || auditLog.Exceptions == "")
|
|
|
|
|
.WhereIF(httpMethod != null, auditLog => auditLog.HttpMethod == httpMethod)
|
|
|
|
|
.WhereIF(url != null, auditLog => auditLog.Url != null && auditLog.Url.Contains(url))
|
|
|
|
|
.WhereIF(userId != null, auditLog => auditLog.UserId == userId)
|
|
|
|
|
.WhereIF(userName != null, auditLog => auditLog.UserName == userName)
|
|
|
|
|
.WhereIF(applicationName != null, auditLog => auditLog.ApplicationName == applicationName)
|
|
|
|
|
.WhereIF(clientIpAddress != null,
|
|
|
|
|
auditLog => auditLog.ClientIpAddress != null && auditLog.ClientIpAddress == clientIpAddress)
|
|
|
|
|
.WhereIF(correlationId != null, auditLog => auditLog.CorrelationId == correlationId)
|
|
|
|
|
.WhereIF(httpStatusCode != null && httpStatusCode > 0,
|
|
|
|
|
auditLog => auditLog.HttpStatusCode == nHttpStatusCode)
|
|
|
|
|
.WhereIF(maxExecutionDuration != null && maxExecutionDuration.Value > 0,
|
|
|
|
|
auditLog => auditLog.ExecutionDuration <= maxExecutionDuration)
|
|
|
|
|
.WhereIF(minExecutionDuration != null && minExecutionDuration.Value > 0,
|
|
|
|
|
auditLog => auditLog.ExecutionDuration >= minExecutionDuration);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public async Task<EntityChangeEntity> GetEntityChange(Guid entityChangeId,
|
|
|
|
|
CancellationToken cancellationToken = default)
|
|
|
|
|
{
|
|
|
|
|
var entityChange = await (await GetDbContextAsync()).Queryable<EntityChangeEntity>()
|
|
|
|
|
.Where(x => x.Id == entityChangeId)
|
|
|
|
|
.OrderBy(x => x.Id)
|
|
|
|
|
.FirstAsync(cancellationToken);
|
|
|
|
|
if (entityChange == null)
|
|
|
|
|
{
|
|
|
|
|
throw new EntityNotFoundException(typeof(EntityChangeEntity));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return entityChange;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public async Task<long> GetEntityChangeCountAsync(Guid? auditLogId = null, DateTime? startTime = null,
|
|
|
|
|
DateTime? endTime = null,
|
|
|
|
|
EntityChangeType? changeType = null, string entityId = null, string entityTypeFullName = null,
|
|
|
|
|
CancellationToken cancellationToken = default)
|
|
|
|
|
{
|
|
|
|
|
var query = await GetEntityChangeListQueryAsync(auditLogId, startTime, endTime, changeType, entityId,
|
|
|
|
|
entityTypeFullName);
|
|
|
|
|
var totalCount = await query.CountAsync(cancellationToken);
|
|
|
|
|
return totalCount;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public async Task<List<EntityChangeEntity>> GetEntityChangeListAsync(string sorting = null, int maxResultCount = 50,
|
|
|
|
|
int skipCount = 0,
|
|
|
|
|
Guid? auditLogId = null, DateTime? startTime = null, DateTime? endTime = null,
|
|
|
|
|
EntityChangeType? changeType = null,
|
|
|
|
|
string entityId = null, string entityTypeFullName = null, bool includeDetails = false,
|
|
|
|
|
CancellationToken cancellationToken = default)
|
|
|
|
|
{
|
|
|
|
|
var query = await GetEntityChangeListQueryAsync(auditLogId, startTime, endTime, changeType, entityId,
|
|
|
|
|
entityTypeFullName, includeDetails);
|
|
|
|
|
return await query
|
|
|
|
|
.OrderBy(sorting.IsNullOrWhiteSpace() ? $"{nameof(EntityChangeEntity.ChangeTime)} DESC" : sorting)
|
|
|
|
|
.ToPageListAsync(skipCount, maxResultCount, cancellationToken);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected virtual async Task<ISugarQueryable<EntityChangeEntity>> GetEntityChangeListQueryAsync(
|
|
|
|
|
Guid? auditLogId = null,
|
|
|
|
|
DateTime? startTime = null,
|
|
|
|
|
DateTime? endTime = null,
|
|
|
|
|
EntityChangeType? changeType = null,
|
|
|
|
|
string entityId = null,
|
|
|
|
|
string entityTypeFullName = null,
|
|
|
|
|
bool includeDetails = false)
|
|
|
|
|
{
|
|
|
|
|
return (await GetDbContextAsync())
|
|
|
|
|
.Queryable<EntityChangeEntity>()
|
|
|
|
|
.WhereIF(auditLogId.HasValue, e => e.AuditLogId == auditLogId)
|
|
|
|
|
.WhereIF(startTime.HasValue, e => e.ChangeTime >= startTime)
|
|
|
|
|
.WhereIF(endTime.HasValue, e => e.ChangeTime <= endTime)
|
|
|
|
|
.WhereIF(changeType.HasValue, e => e.ChangeType == changeType)
|
|
|
|
|
.WhereIF(!string.IsNullOrWhiteSpace(entityId), e => e.EntityId == entityId)
|
|
|
|
|
.WhereIF(!string.IsNullOrWhiteSpace(entityTypeFullName),
|
|
|
|
|
e => e.EntityTypeFullName.Contains(entityTypeFullName));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public async Task<List<EntityChangeWithUsername>> GetEntityChangesWithUsernameAsync(string entityId,
|
|
|
|
|
string entityTypeFullName,
|
|
|
|
|
CancellationToken cancellationToken = default)
|
|
|
|
|
{
|
|
|
|
|
var query = (await GetDbContextAsync()).Queryable<EntityChangeEntity>()
|
|
|
|
|
.Where(x => x.EntityId == entityId && x.EntityTypeFullName == entityTypeFullName);
|
|
|
|
|
|
|
|
|
|
var result = await query.LeftJoin<AuditLogAggregateRoot>((x, audit) => x.AuditLogId == audit.Id)
|
|
|
|
|
.Select((x, audit) => new EntityChangeWithUsername { EntityChange = x, Username = audit.UserName! })
|
|
|
|
|
.OrderByDescending(x => x.EntityChange.ChangeTime)
|
|
|
|
|
.ToListAsync(cancellationToken);
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public async Task<EntityChangeWithUsername> GetEntityChangeWithUsernameAsync(Guid entityChangeId)
|
|
|
|
|
{
|
|
|
|
|
var auditLog = await DbQueryable
|
|
|
|
|
.Where(x => x.EntityChanges.Any(y => y.Id == entityChangeId))
|
|
|
|
|
.FirstAsync();
|
|
|
|
|
return new EntityChangeWithUsername
|
|
|
|
|
{
|
|
|
|
|
EntityChange = auditLog.EntityChanges.First(x => x.Id == entityChangeId),
|
|
|
|
|
Username = auditLog.UserName!
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
}
|