Skip to content

Commit

Permalink
improvement: refactoring and various improvements (#848)
Browse files Browse the repository at this point in the history
Co-authored-by: kjetilhau <[email protected]>
  • Loading branch information
kjetilhau and kjetilhau authored Nov 5, 2024
1 parent d814023 commit dad524f
Show file tree
Hide file tree
Showing 25 changed files with 128 additions and 96 deletions.
3 changes: 3 additions & 0 deletions .changeset/pr-848-2155869305.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@

---
---
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,7 @@ namespace Equinor.ProjectExecutionPortal.Application.Cache;

public class CacheManager : ICacheManager
{
private readonly IMemoryCache _cache;

public CacheManager() => _cache = new MemoryCache(new MemoryCacheOptions
private readonly IMemoryCache _cache = new MemoryCache(new MemoryCacheOptions
{
Clock = new CacheClock()
});
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace Equinor.ProjectExecutionPortal.Application.Cache;

public class CacheOptions
{
public int FusionAppsCacheMinutes { get; init; }
}
Original file line number Diff line number Diff line change
@@ -1,39 +1,40 @@
using Fusion.Integration.Apps.Abstractions.Abstractions;
using Fusion.Integration.Apps.Abstractions.Models;
using Microsoft.Extensions.Options;

namespace Equinor.ProjectExecutionPortal.Application.Cache;

public class FusionAppsCache : IFusionAppsCache
{
private readonly ICacheManager _cacheManager;
private readonly IAppsClient _fusionAppsClient;
private readonly IOptions<CacheOptions> _cacheOptions;

public FusionAppsCache(ICacheManager cacheManager, IAppsClient fusionAppsClient)
private const string FusionAppCacheKey = "FUSION_APP";

public FusionAppsCache(ICacheManager cacheManager, IAppsClient fusionAppsClient, IOptions<CacheOptions> cacheOptions)
{
_cacheManager = cacheManager;
_fusionAppsClient = fusionAppsClient;
_cacheOptions = cacheOptions;
}

// TODO: Move cache duration to app settings

public async Task<List<App>> GetFusionApps()
{
return await _cacheManager.GetOrCreateAsync("FUSION_APP",
return await _cacheManager.GetOrCreateAsync(FusionAppCacheKey,
async () =>
{
var fusionApps = await _fusionAppsClient.GetAppsAsync();

return fusionApps.ToList();
},
CacheDuration.Minutes,
60);
CacheDuration.Minutes, _cacheOptions.Value.FusionAppsCacheMinutes);
}

public async Task<App?> GetFusionApp(string appKey)
{
return await _cacheManager.GetOrCreateAsync("FUSION_APP",
return await _cacheManager.GetOrCreateAsync(FusionAppCacheKey,
async () => await _fusionAppsClient.GetAppAsync(appKey),
CacheDuration.Minutes,
60);
CacheDuration.Minutes, _cacheOptions.Value.FusionAppsCacheMinutes);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ private void ApplyMappingsFromAssembly(Assembly assembly)
var methodInfo = type.GetMethod("Mapping")
?? type.GetInterface("IMapFrom`1")!.GetMethod("Mapping");

methodInfo?.Invoke(instance, new object[] { this });
methodInfo?.Invoke(instance, [this]);

}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@ public abstract class EntityBase
{
private List<INotification>? _domainEvents;

public IReadOnlyCollection<INotification> DomainEvents => _domainEvents?.AsReadOnly() ?? (_domainEvents = new List<INotification>()).AsReadOnly();
public IReadOnlyCollection<INotification> DomainEvents => _domainEvents?.AsReadOnly() ?? (_domainEvents = []).AsReadOnly();

public virtual Guid Id { get; protected set; }

public void AddDomainEvent(INotification eventItem)
{
_domainEvents ??= new List<INotification>();
_domainEvents ??= [];
_domainEvents.Add(eventItem);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,5 @@

namespace Equinor.ProjectExecutionPortal.Domain.Infrastructure
{
public abstract class QueryBase<T> : IRequest<T>
{
}
public abstract class QueryBase<T> : IRequest<T>;
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;

namespace Equinor.ProjectExecutionPortal.Infrastructure;

Expand All @@ -8,6 +7,4 @@ public interface IReadWriteContext : IDisposable
DbSet<TEntity> Set<TEntity>() where TEntity : class;

Task<int> SaveChangesAsync(CancellationToken cancellationToken);

DatabaseFacade Database { get; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ namespace Equinor.ProjectExecutionPortal.Infrastructure;

public static class InfrastructureModule
{
public static IServiceCollection AddInfrastructureModules(this IServiceCollection services, IConfiguration configuration)
public static void AddInfrastructureModules(this IServiceCollection services, IConfiguration configuration)
{
var connectionString = configuration.GetConnectionString("ProjectPortalContext");

Expand All @@ -15,7 +15,5 @@ public static IServiceCollection AddInfrastructureModules(this IServiceCollectio
b => b.MigrationsAssembly(typeof(ProjectExecutionPortalContext).Assembly.FullName)
)
);

return services;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,16 +33,16 @@ protected override void OnModelCreating(ModelBuilder modelBuilder)

public static DateTimeKindConverter DateTimeKindConverter { get; } = new();

public DbSet<Portal> Portals { get; set; }
public DbSet<PortalApp> PortalApps { get; set; }
public DbSet<OnboardedApp> OnboardedApps { get; set; }
public DbSet<OnboardedContext> OnboardedContexts { get; set; }
public DbSet<ContextType> ContextTypes { get; set; }
public DbSet<Portal> Portals { get; init; }
public DbSet<PortalApp> PortalApps { get; init; }
public DbSet<OnboardedApp> OnboardedApps { get; init; }
public DbSet<OnboardedContext> OnboardedContexts { get; init; }
public DbSet<ContextType> ContextTypes { get; init; }

public override async Task<int> SaveChangesAsync(CancellationToken cancellationToken = default)
{
await DispatchEventsAsync(cancellationToken);
await SetAuditDataAsync();
SetAuditData();

try
{
Expand All @@ -63,12 +63,13 @@ private async Task DispatchEventsAsync(CancellationToken cancellationToken = def
await _eventDispatcher.DispatchAsync(entities, cancellationToken);
}

private async Task SetAuditDataAsync()
private void SetAuditData()
{
var addedEntries = ChangeTracker
.Entries<ICreationAuditable>()
.Where(x => x.State == EntityState.Added)
.ToList();

var modifiedEntries = ChangeTracker
.Entries<IModificationAuditable>()
.Where(x => x.State == EntityState.Modified)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System.Reflection;
using Equinor.ProjectExecutionPortal.Application;
using Equinor.ProjectExecutionPortal.Application.Cache;
using Equinor.ProjectExecutionPortal.Application.Events.Common;
using Equinor.ProjectExecutionPortal.Domain.Common.Events.Common;
using Equinor.ProjectExecutionPortal.Domain.Common.Time;
Expand All @@ -11,7 +12,6 @@
using FluentValidation;
using MediatR;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.Identity.Client;

namespace Equinor.ProjectExecutionPortal.WebApi.DiModules;

Expand All @@ -23,7 +23,7 @@ public static void AddApplicationModules(this IServiceCollection services, IConf

var applicationAssembly = typeof(IApplicationMarker).GetTypeInfo().Assembly;

services.Configure<CacheOptions>(configuration.GetSection("CacheOptions"));
services.Configure<CacheOptions>(configuration.GetSection("Cache"));

services.AddAuthorization(options =>
{
Expand Down
19 changes: 9 additions & 10 deletions backend/src/Equinor.ProjectExecutionPortal.WebApi/Program.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System.Text.Json.Serialization;
using Equinor.ProjectExecutionPortal.WebApi.DiModules;
using Equinor.ProjectExecutionPortal.WebApi.Middleware;
using FluentValidation;
using FluentValidation.AspNetCore;
using Fusion.Integration.Apps.Configuration;
using Microsoft.AspNetCore.Authentication.JwtBearer;
Expand Down Expand Up @@ -44,13 +45,14 @@
// Add fusion integration
builder.Services.AddFusionIntegration(f =>
{
var environment = builder.Configuration.GetValue<string>("Fusion:Environment" ?? "ci");
var environment = builder.Configuration.GetValue<string>("Fusion:Environment")!;

f.UseServiceInformation("Fusion.Project.Portal", environment);
f.UseDefaultEndpointResolver(environment);
f.AddAppsClient();
f.UseDefaultTokenProvider(opts =>
{
opts.ClientId = builder.Configuration.GetValue<string>("AzureAd:ClientId");
opts.ClientId = builder.Configuration.GetValue<string>("AzureAd:ClientId")!;
opts.ClientSecret = builder.Configuration.GetValue<string>("AzureAd:ClientSecret");
});
f.DisableClaimsTransformation();
Expand All @@ -65,10 +67,8 @@
})
.AddJsonOptions(options => options.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter()));

builder.Services.AddFluentValidation(c =>
{
c.RegisterValidatorsFromAssemblyContaining<Program>();
});
builder.Services.AddFluentValidationAutoValidation();
builder.Services.AddValidatorsFromAssemblyContaining<Program>();

builder.Services.AddEndpointsApiExplorer();

Expand All @@ -89,8 +89,8 @@
{
Implicit = new OpenApiOAuthFlow
{
AuthorizationUrl = new Uri(builder.Configuration["Swagger:AuthorizationUrl"]),
TokenUrl = new Uri(builder.Configuration["Swagger:TokenUrl"]),
AuthorizationUrl = new Uri(builder.Configuration["Swagger:AuthorizationUrl"]!),
TokenUrl = new Uri(builder.Configuration["Swagger:TokenUrl"]!),
Scopes = scopes
}
}
Expand Down Expand Up @@ -148,5 +148,4 @@
app.Run();

// Used for tests
public partial class Program
{ }
public abstract partial class Program;
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
"Scope": "access_as_user"
},
"Fusion": {
"Environment": "ci"
"Environment": "ci"
},
"AzureAd": {
"ClientId": "guid", // This app's AppReg key
Expand All @@ -25,6 +25,9 @@
"ApplicationInsights": {
"ConnectionString": ""
},
"Cache": {
"FusionAppsCacheMinutes": 60
},
"Logging": {
"LogLevel": {
"Default": "Information",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,24 @@

namespace Equinor.ProjectExecutionPortal.Tests.WebApi.Data
{
internal class ContextTypeData
internal static class ContextTypeData
{
public class InitialDbSeedData
public static class InitialDbSeedData
{
public static ContextType ContextType1 = new(ValidContextTypes.ProjectMasterContextTypeKey);
public static ContextType ContextType2 = new(ValidContextTypes.FacilityContextTypeKey);
public static readonly ContextType ContextType1 = new(ValidContextTypes.ProjectMasterContextTypeKey);
public static readonly ContextType ContextType2 = new(ValidContextTypes.FacilityContextTypeKey);
}

public class ValidContextTypes
public static class ValidContextTypes
{
public static string ProjectMasterContextTypeKey = "ProjectMaster";
public static string FacilityContextTypeKey = "Facility";
public static string ContractContextTypeKey = "Contract";
public const string ProjectMasterContextTypeKey = "ProjectMaster";
public const string FacilityContextTypeKey = "Facility";
public const string ContractContextTypeKey = "Contract";
}

public class InvalidContextTypes
public static class InvalidContextTypes
{
public static string InvalidContextTypeKey = "SuperContext";
public const string InvalidContextTypeKey = "SuperContext";
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

namespace Equinor.ProjectExecutionPortal.Tests.WebApi.Data
{
internal class FusionAppApiData
internal static class FusionAppApiData
{
public static App MeetingsFusion => new()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@

namespace Equinor.ProjectExecutionPortal.Tests.WebApi.Data
{
internal class FusionContextApiData
internal static class FusionContextApiData
{
public static string JcaContextExternalId = "fc5ffcbc-392f-4d7e-bb14-79a006579337";
public const string JcaContextExternalId = "fc5ffcbc-392f-4d7e-bb14-79a006579337";
public static Guid JcaContextId = new("94dd5f4d-17f1-4312-bf75-ad75f4d9572c");
public static string OgpContextExternalId = "91dd6653-a364-40c7-af26-7af516d66c42";
public const string OgpContextExternalId = "91dd6653-a364-40c7-af26-7af516d66c42";
public static Guid OgpContextId = new("ce31b83a-b6cd-4267-89f3-db308edf721e");
public static string MongstadContextExternalId = "09206ca3-02ac-4c65-adbf-caa7b66364ea";
public const string MongstadContextExternalId = "09206ca3-02ac-4c65-adbf-caa7b66364ea";
public static Guid MongstadContextId = new("4CB78175-46CF-41A3-58DB-08DC74C80D40");
public static string InvalidContextExternalId = "11111111-1111-1111-1111-111111111111";
public const string InvalidContextExternalId = "11111111-1111-1111-1111-111111111111";
public static Guid InvalidContextId = new("11111111-1111-1111-1111-111111111111");

public static FusionContext JcaFusionContext => new()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,16 @@

namespace Equinor.ProjectExecutionPortal.Tests.WebApi.Data
{
internal class OnboardedAppData
internal static class OnboardedAppData
{
public class InitialDbSeedData
public static class InitialDbSeedData
{
public static OnboardedApp MeetingsApp = new("meetings");
public static OnboardedApp ReviewsApp = new("reviews");
public static OnboardedApp TasksApp = new("tasks");
public static OnboardedApp OrgChartApp = new("one-equinor");
public static OnboardedApp HandoverGardenApp = new("handover-garden");
public static OnboardedApp WorkOrderGardenApp = new("workorder-garden");
public static readonly OnboardedApp MeetingsApp = new("meetings");
public static readonly OnboardedApp ReviewsApp = new("reviews");
public static readonly OnboardedApp TasksApp = new("tasks");
public static readonly OnboardedApp OrgChartApp = new("one-equinor");
public static readonly OnboardedApp HandoverGardenApp = new("handover-garden");
public static readonly OnboardedApp WorkOrderGardenApp = new("workorder-garden");
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@

namespace Equinor.ProjectExecutionPortal.Tests.WebApi.Data
{
internal class OnboardedContextData
internal static class OnboardedContextData
{
public class InitialDbSeedData
public static class InitialDbSeedData
{
public static OnboardedContext JcaContext = new(FusionContextApiData.JcaContextExternalId, ContextTypeData.ValidContextTypes.ProjectMasterContextTypeKey, "desc");
public static OnboardedContext OgpContext = new(FusionContextApiData.OgpContextExternalId, ContextTypeData.ValidContextTypes.ProjectMasterContextTypeKey, "desc");
public static readonly OnboardedContext JcaContext = new(FusionContextApiData.JcaContextExternalId, ContextTypeData.ValidContextTypes.ProjectMasterContextTypeKey, "desc");
public static readonly OnboardedContext OgpContext = new(FusionContextApiData.OgpContextExternalId, ContextTypeData.ValidContextTypes.ProjectMasterContextTypeKey, "desc");
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@

namespace Equinor.ProjectExecutionPortal.Tests.WebApi.Data
{
internal class PortalConfigurationData
internal static class PortalConfigurationData
{
public class InitialDbSeedData
public static class InitialDbSeedData
{
public static PortalConfiguration GenericPortalConfiguration = new(
public static readonly PortalConfiguration GenericPortalConfiguration = new(
"routerConfig",
"extensionConfig",
"environmentConfig"
Expand Down
Loading

0 comments on commit dad524f

Please sign in to comment.