Skip to content

Commit

Permalink
Merge branch 'main' into feature/ignore-audit-trail-attribute
Browse files Browse the repository at this point in the history
  • Loading branch information
iammukeshm authored Nov 22, 2024
2 parents a647010 + df50461 commit 602aeda
Show file tree
Hide file tree
Showing 59 changed files with 1,778 additions and 199 deletions.
8 changes: 8 additions & 0 deletions src/Shared/Authorization/FshPermissions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,14 @@ public static class FshPermissions
new("Delete Products", FshActions.Delete, FshResources.Products),
new("Export Products", FshActions.Export, FshResources.Products),

//brands
new("View Brands", FshActions.View, FshResources.Brands, IsBasic: true),
new("Search Brands", FshActions.Search, FshResources.Brands, IsBasic: true),
new("Create Brands", FshActions.Create, FshResources.Brands),
new("Update Brands", FshActions.Update, FshResources.Brands),
new("Delete Brands", FshActions.Delete, FshResources.Brands),
new("Export Brands", FshActions.Export, FshResources.Brands),

//todos
new("View Todos", FshActions.View, FshResources.Todos, IsBasic: true),
new("Search Todos", FshActions.Search, FshResources.Todos, IsBasic: true),
Expand Down
2 changes: 2 additions & 0 deletions src/api/framework/Core/Domain/AuditableEntity.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ public class AuditableEntity<TId> : BaseEntity<TId>, IAuditable, ISoftDeletable
public DateTimeOffset LastModified { get; set; }
[IgnoreAuditTrail]
public Guid? LastModifiedBy { get; set; }
public DateTimeOffset? Deleted { get; set; }
public Guid? DeletedBy { get; set; }
}

public abstract class AuditableEntity : AuditableEntity<Guid>
Expand Down
3 changes: 2 additions & 1 deletion src/api/framework/Core/Domain/Contracts/ISoftDeletable.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@

public interface ISoftDeletable
{

DateTimeOffset? Deleted { get; set; }
Guid? DeletedBy { get; set; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Tokens;
using IdentityConstants = FSH.Starter.Shared.Authorization.IdentityConstants;

namespace FSH.Framework.Infrastructure.Identity.Tokens;
public sealed class TokenService : ITokenService
Expand Down Expand Up @@ -134,14 +133,15 @@ private string GenerateEncryptedToken(SigningCredentials signingCredentials, IEn
private List<Claim> GetClaims(FshUser user, string ipAddress) =>
new List<Claim>
{
new(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
new(ClaimTypes.NameIdentifier, user.Id),
new(ClaimTypes.Email, user.Email!),
new(FshClaims.Fullname, $"{user.FirstName} {user.LastName}"),
new(ClaimTypes.Name, user.FirstName ?? string.Empty),
new(ClaimTypes.MobilePhone, user.PhoneNumber ?? string.Empty),
new(FshClaims.Fullname, $"{user.FirstName} {user.LastName}"),
new(ClaimTypes.Surname, user.LastName ?? string.Empty),
new(FshClaims.IpAddress, ipAddress),
new(FshClaims.Tenant, _multiTenantContextAccessor!.MultiTenantContext.TenantInfo!.Id),
new(ClaimTypes.MobilePhone, user.PhoneNumber ?? string.Empty),
new(FshClaims.ImageUrl, user.ImageUrl == null ? string.Empty : user.ImageUrl.ToString())
};
private static string GenerateRefreshToken()
Expand Down
2 changes: 1 addition & 1 deletion src/api/framework/Infrastructure/OpenApi/Extensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ public static WebApplication UseOpenApi(this WebApplication app)
var swaggerEndpoints = app.DescribeApiVersions()
.Select(desc => new
{
Url = $"/swagger/{desc.GroupName}/swagger.json",
Url = $"../swagger/{desc.GroupName}/swagger.json",
Name = desc.GroupName.ToUpperInvariant()
});
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
using System.Linq.Expressions;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Query;

namespace FSH.Framework.Infrastructure.Persistence;

internal static class ModelBuilderExtensions
{
public static ModelBuilder AppendGlobalQueryFilter<TInterface>(this ModelBuilder modelBuilder, Expression<Func<TInterface, bool>> filter)
{
// get a list of entities without a baseType that implement the interface TInterface
var entities = modelBuilder.Model.GetEntityTypes()
.Where(e => e.BaseType is null && e.ClrType.GetInterface(typeof(TInterface).Name) is not null)
.Select(e => e.ClrType);

foreach (var entity in entities)
{
var parameterType = Expression.Parameter(modelBuilder.Entity(entity).Metadata.ClrType);
var filterBody = ReplacingExpressionVisitor.Replace(filter.Parameters.Single(), parameterType, filter.Body);

// get the existing query filter
if (modelBuilder.Entity(entity).Metadata.GetQueryFilter() is { } existingFilter)
{
var existingFilterBody = ReplacingExpressionVisitor.Replace(existingFilter.Parameters.Single(), parameterType, existingFilter.Body);

// combine the existing query filter with the new query filter
filterBody = Expression.AndAlso(existingFilterBody, filterBody);
}

// apply the new query filter
modelBuilder.Entity(entity).HasQueryFilter(Expression.Lambda(filterBody, parameterType));
}

return modelBuilder;
}
}
6 changes: 6 additions & 0 deletions src/api/framework/Infrastructure/Persistence/FshDbContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,12 @@ public class FshDbContext(IMultiTenantContextAccessor<FshTenantInfo> multiTenant
private readonly IPublisher _publisher = publisher;
private readonly DatabaseOptions _settings = settings.Value;

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
// QueryFilters need to be applied before base.OnModelCreating
modelBuilder.AppendGlobalQueryFilter<ISoftDeletable>(s => s.Deleted == null);
base.OnModelCreating(modelBuilder);
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.EnableSensitiveDataLogging();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,12 @@ private async Task PublishAuditTrailsAsync(DbContextEventData eventData)
var utcNow = timeProvider.GetUtcNow();
foreach (var entry in eventData.Context.ChangeTracker.Entries<IAuditable>().Where(x => x.State is EntityState.Added or EntityState.Deleted or EntityState.Modified && x.Entity.GetType().GetCustomAttributes(typeof(IgnoreAuditTrailAttribute), false).Length == 0).ToList())
{
var userId = currentUser.GetUserId();
var trail = new TrailDto()
{
Id = Guid.NewGuid(),
TableName = entry.Entity.GetType().Name,
UserId = currentUser.GetUserId(),
UserId = userId,
DateTime = utcNow
};

Expand Down Expand Up @@ -72,19 +73,26 @@ private async Task PublishAuditTrailsAsync(DbContextEventData eventData)
break;

case EntityState.Modified:
if (property.IsModified && property.OriginalValue == null && property.CurrentValue != null)
if (property.IsModified)
{
trail.ModifiedProperties.Add(propertyName);
trail.Type = TrailType.Delete;
trail.OldValues[propertyName] = property.OriginalValue;
trail.NewValues[propertyName] = property.CurrentValue;
}
else if (property.IsModified && property.OriginalValue?.Equals(property.CurrentValue) == false)
{
trail.ModifiedProperties.Add(propertyName);
trail.Type = TrailType.Update;
trail.OldValues[propertyName] = property.OriginalValue;
trail.NewValues[propertyName] = property.CurrentValue;
if (entry.Entity is ISoftDeletable && property.OriginalValue == null && property.CurrentValue != null)
{
trail.ModifiedProperties.Add(propertyName);
trail.Type = TrailType.Delete;
trail.OldValues[propertyName] = property.OriginalValue;
trail.NewValues[propertyName] = property.CurrentValue;
}
else if (property.OriginalValue?.Equals(property.CurrentValue) == false)
{
trail.ModifiedProperties.Add(propertyName);
trail.Type = TrailType.Update;
trail.OldValues[propertyName] = property.OriginalValue;
trail.NewValues[propertyName] = property.CurrentValue;
}
else
{
property.IsModified = false;
}
}
break;
}
Expand All @@ -106,9 +114,9 @@ public void UpdateEntities(DbContext? context)
if (context == null) return;
foreach (var entry in context.ChangeTracker.Entries<AuditableEntity>())
{
var utcNow = timeProvider.GetUtcNow();
if (entry.State is EntityState.Added or EntityState.Modified || entry.HasChangedOwnedEntities())
{
var utcNow = timeProvider.GetUtcNow();
if (entry.State == EntityState.Added)
{
entry.Entity.CreatedBy = currentUser.GetUserId();
Expand All @@ -117,6 +125,12 @@ public void UpdateEntities(DbContext? context)
entry.Entity.LastModifiedBy = currentUser.GetUserId();
entry.Entity.LastModified = utcNow;
}
if(entry.State is EntityState.Deleted && entry.Entity is ISoftDeletable softDelete)
{
softDelete.DeletedBy = currentUser.GetUserId();
softDelete.Deleted = utcNow;
entry.State = EntityState.Modified;
}
}
}
}
Expand Down

This file was deleted.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 602aeda

Please sign in to comment.