Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feature: API: migrate from Fusion API to Fusion Apps API #811

Merged
merged 30 commits into from
Oct 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
b3bd581
Replace Fusion portal service api with Fusion integration
kjetilhau Oct 2, 2024
68f7973
Refactoring
kjetilhau Oct 2, 2024
a00bba6
Fixed some warnings
kjetilhau Oct 2, 2024
94500af
.
kjetilhau Oct 4, 2024
ae752f3
Remove FusionPortalApi client
kjetilhau Oct 4, 2024
2092890
Cleanup
kjetilhau Oct 4, 2024
f53180c
Updated tests
kjetilhau Oct 4, 2024
9595e37
Fixed some ignored tests and updated more
kjetilhau Oct 4, 2024
ecbd46a
Replace project dependecies with abstractions
kjetilhau Oct 4, 2024
9cf2032
More cleanup
kjetilhau Oct 4, 2024
0d14c2f
.
kjetilhau Oct 4, 2024
32137bd
chore: create pr-811-2107089113.md
kjetilhau Oct 4, 2024
fff5894
chore: update pr-811-2107089113.md
kjetilhau Oct 4, 2024
7e253b1
merge from main
kjetilhau Oct 8, 2024
8206f16
Merge branch 'feature/api-fusion-apps-migrate' of https://github.com/…
kjetilhau Oct 8, 2024
344feaa
chore: update pr-811-2107089113.md
kjetilhau Oct 8, 2024
28dbb60
Add Get AppKeys for portal and by context endpoints
kjetilhau Oct 8, 2024
894edeb
Merge branch 'feature/api-fusion-apps-migrate' of https://github.com/…
kjetilhau Oct 8, 2024
a9e0457
Fixed ignored tests
kjetilhau Oct 8, 2024
7fafeeb
Added tests for GetAppKeys
kjetilhau Oct 8, 2024
8a7c457
.
kjetilhau Oct 8, 2024
872c5f5
Minor cleanup. Remove todos, set guid types
kjetilhau Oct 10, 2024
0dfac6c
Minor refactoring and renaming of mock data
kjetilhau Oct 10, 2024
79426fd
Improved mock data
kjetilhau Oct 10, 2024
9f94adb
Tests: add portal config mock data
kjetilhau Oct 15, 2024
dba578f
merge from main
kjetilhau Oct 16, 2024
0217915
chore: update pr-811-2107089113.md
kjetilhau Oct 16, 2024
c2bbab0
Merge branch 'main' into feature/api-fusion-apps-migrate
kjetilhau Oct 22, 2024
183bdca
Renamed method
kjetilhau Oct 24, 2024
c9b4319
Merge branch 'main' into feature/api-fusion-apps-migrate
kjetilhau Oct 24, 2024
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
9 changes: 9 additions & 0 deletions .changeset/pr-811-2107089113.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@

---
"fusion-project-portal": major
---
- **BREAKING CHANGE**: Migrate from the deprecated Fusion Portal API (for apps) to the new and separate Fusion Apps API.
This results in breaking changes in the API contract. The reason for this is model changes in the new Fusion Apps API. And we prefer modelling 1-1 as best as possible instead of introducing remapping etc. on our end.
- **BREAKING CHANGE**: Removal of the Fusion Portal Proxy. We no longer provide endpoints for this on the API. All calls to get bundles and app information from Fusion shall go through the ClientBackend
- Fixed more tests
- Refactoring has been done in multiple locations
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ private static TimeSpan GetExpirationTime(CacheDuration duration, long expiratio
CacheDuration.Hours => TimeSpan.FromHours(expiration),
CacheDuration.Minutes => TimeSpan.FromMinutes(expiration),
CacheDuration.Seconds => TimeSpan.FromSeconds(expiration),
_ => throw new NotImplementedException($"Unknown {nameof(CacheDuration)}: {duration}"),
_ => throw new Exception($"Unknown {nameof(CacheDuration)}: {duration}"),
};

private class CacheClock : ISystemClock
Expand Down
Original file line number Diff line number Diff line change
@@ -1,36 +1,36 @@
using Equinor.ProjectExecutionPortal.FusionPortalApi.Apps;
using Equinor.ProjectExecutionPortal.FusionPortalApi.Apps.Models;
using Fusion.Integration.Apps.Abstractions.Abstractions;
using Fusion.Integration.Apps.Abstractions.Models;

namespace Equinor.ProjectExecutionPortal.Application.Cache;

public class FusionAppsCache : IFusionAppsCache
{
private readonly ICacheManager _cacheManager;
private readonly IFusionPortalApiService _fusionPortalApiService;
private readonly IAppsClient _fusionAppsClient;

public FusionAppsCache(ICacheManager cacheManager, IFusionPortalApiService fusionPortalApiService)
public FusionAppsCache(ICacheManager cacheManager, IAppsClient fusionAppsClient)
{
_cacheManager = cacheManager;
_fusionPortalApiService = fusionPortalApiService;
_fusionAppsClient = fusionAppsClient;
}

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

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

public async Task<FusionPortalAppInformation?> GetFusionApp(string appKey)
public async Task<App?> GetFusionApp(string appKey)
{
return await _cacheManager.GetOrCreateAsync("FUSION_APP",
async () => await _fusionPortalApiService.TryGetFusionPortalApp(appKey),
async () => await _fusionAppsClient.GetAppAsync(appKey),
CacheDuration.Minutes,
60);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
using Equinor.ProjectExecutionPortal.FusionPortalApi.Apps.Models;
using Fusion.Integration.Apps.Abstractions.Models;

namespace Equinor.ProjectExecutionPortal.Application.Cache;

public interface IFusionAppsCache
{
Task<List<FusionPortalAppInformation>> GetFusionApps();
Task<List<App>> GetFusionApps();

Task<FusionPortalAppInformation?> GetFusionApp(string appKey);
Task<App?> GetFusionApp(string appKey);
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ public async Task<Guid> Handle(AddContextTypeCommand command, CancellationToken
if (!FusionContextType.IsValid(command.ContextTypeKey))
{
throw new NotFoundException($"ContextType: {command.ContextTypeKey} is not a valid Context type");
};
}

var contextType = new ContextType(command.ContextTypeKey);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using System.Data;
using Equinor.ProjectExecutionPortal.Domain.Common.Exceptions;
using Equinor.ProjectExecutionPortal.Domain.Common.Exceptions;
using Equinor.ProjectExecutionPortal.Domain.Entities;
using Equinor.ProjectExecutionPortal.Infrastructure;
using MediatR;
Expand All @@ -15,7 +14,7 @@ public RemoveContextTypeCommand(string contextTypeKey)
}

public string ContextTypeKey { get; }

public class Handler : IRequestHandler<RemoveContextTypeCommand>
{
private readonly IReadWriteContext _readWriteContext;
Expand All @@ -27,19 +26,19 @@ public Handler(IReadWriteContext readWriteContext)

public async Task Handle(RemoveContextTypeCommand command, CancellationToken cancellationToken)
{
var entity = await _readWriteContext.Set<ContextType>()
var entity = await _readWriteContext.Set<ContextType>()
.Include(x => x.OnboardedApps)
.Include(x => x.Portals)
.FirstOrDefaultAsync(x => x.ContextTypeKey == command.ContextTypeKey, cancellationToken);

if (entity == null)
{
throw new NotFoundException(nameof(ContextType) ,command.ContextTypeKey);
throw new NotFoundException(nameof(ContextType), command.ContextTypeKey);
}

if (entity.Portals.Any())
{
throw new InvalidActionException("Cannot remove context type. Context type is used by portals");
throw new InvalidActionException("Cannot remove context type. Context type is used by portals");
}

if (entity.OnboardedApps.Any())
Expand All @@ -50,7 +49,6 @@ public async Task Handle(RemoveContextTypeCommand command, CancellationToken can
_readWriteContext.Set<ContextType>().Remove(entity);

await _readWriteContext.SaveChangesAsync(cancellationToken);

}
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
using Equinor.ProjectExecutionPortal.Application.Services.AppService;
using Equinor.ProjectExecutionPortal.Application.Services.ContextTypeService;
using Equinor.ProjectExecutionPortal.Application.Services.ContextTypeService;
using Equinor.ProjectExecutionPortal.Application.Services.FusionAppsService;
using Equinor.ProjectExecutionPortal.Domain.Common.Exceptions;
using Equinor.ProjectExecutionPortal.Domain.Entities;
using Equinor.ProjectExecutionPortal.Infrastructure;
Expand All @@ -22,19 +22,19 @@ public OnboardAppCommand(string appKey, IList<string>? contextTypes)
public class Handler : IRequestHandler<OnboardAppCommand, Guid>
{
private readonly IReadWriteContext _readWriteContext;
private readonly IAppService _appService;
private readonly IFusionAppsService _fusionAppsService;
private readonly IContextTypeService _contextTypeService;

public Handler(IReadWriteContext readWriteContext, IAppService appService, IContextTypeService contextTypeService)
public Handler(IReadWriteContext readWriteContext, IFusionAppsService fusionAppsService, IContextTypeService contextTypeService)
{
_readWriteContext = readWriteContext;
_appService = appService;
_fusionAppsService = fusionAppsService;
_contextTypeService = contextTypeService;
}

public async Task<Guid> Handle(OnboardAppCommand command, CancellationToken cancellationToken)
{
if (!await _appService.FusionAppExist(command.AppKey, cancellationToken))
if (!await _fusionAppsService.FusionAppExist(command.AppKey, cancellationToken))
{
throw new NotFoundException($"Could not locate app '{command.AppKey}' in Fusion.");
}
Expand All @@ -49,10 +49,10 @@ public async Task<Guid> Handle(OnboardAppCommand command, CancellationToken canc
}

var onboardedApp = new OnboardedApp(command.AppKey);

try
{
onboardedApp.AddContextTypes(await _contextTypeService.GetContextTypesByContextTypeKey(command.ContextTypes, cancellationToken));
onboardedApp.AddContextTypes(await _contextTypeService.GetAllowedContextTypesByKeys(command.ContextTypes, cancellationToken));
}
catch (InvalidActionException ex)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ public async Task<Guid> Handle(UpdateOnboardedAppCommand command, CancellationTo

try
{
entity.AddContextTypes(await _contextTypeService.GetContextTypesByContextTypeKey(command.ContextTypes, cancellationToken));
entity.AddContextTypes(await _contextTypeService.GetAllowedContextTypesByKeys(command.ContextTypes, cancellationToken));
}
catch (InvalidActionException ex)
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using Equinor.ProjectExecutionPortal.Application.Services.ContextTypeService;
using Equinor.ProjectExecutionPortal.Domain.Common.Exceptions;
using Equinor.ProjectExecutionPortal.Domain.Common.Exceptions;
using Equinor.ProjectExecutionPortal.Domain.Entities;
using Equinor.ProjectExecutionPortal.Infrastructure;
using MediatR;
Expand All @@ -22,12 +21,10 @@ public AddContextTypeToPortalCommand(Guid portalId, string type)
public class Handler : IRequestHandler<AddContextTypeToPortalCommand, Unit>
{
private readonly IReadWriteContext _readWriteContext;
private readonly IContextTypeService _contextTypeService;

public Handler(IReadWriteContext readWriteContext, IContextTypeService contextTypeService)
public Handler(IReadWriteContext readWriteContext)
{
_readWriteContext = readWriteContext;
_contextTypeService = contextTypeService;
}

public async Task<Unit> Handle(AddContextTypeToPortalCommand command, CancellationToken cancellationToken)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ public async Task<Guid> Handle(CreatePortalCommand command, CancellationToken ca

var portal = new Portal(slug, command.Name, command.ShortName, command.SubText, command.Description, command.Icon);

portal.AddContextTypes(await _contextTypeService.GetContextTypesByContextTypeKey(command.ContextTypes, cancellationToken));
portal.AddContextTypes(await _contextTypeService.GetAllowedContextTypesByKeys(command.ContextTypes, cancellationToken));

await _readWriteContext.Set<Portal>().AddAsync(portal, cancellationToken);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ public async Task<Guid> Handle(UpdatePortalCommand command, CancellationToken ca

entity.Update(slug, command.Name, command.ShortName, command.SubText, command.Description, command.Icon);

entity.AddContextTypes(await _contextTypeService.GetContextTypesByContextTypeKey(command.ContextTypes, cancellationToken));
entity.AddContextTypes(await _contextTypeService.GetAllowedContextTypesByKeys(command.ContextTypes, cancellationToken));

await _readWriteContext.SaveChangesAsync(cancellationToken);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@

<ItemGroup>
<PackageReference Include="AutoMapper" Version="13.0.1" />
<PackageReference Include="Fusion.Integration" Version="8.0.4" />
<PackageReference Include="Fusion.Integration.Abstractions" Version="8.0.7" />
<PackageReference Include="Fusion.Integration.Apps.Abstractions" Version="8.0.0" />
<PackageReference Include="MediatR" Version="12.2.0" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\Equinor.ProjectExecutionPortal.Domain\Equinor.ProjectExecutionPortal.Domain.csproj" />
<ProjectReference Include="..\Equinor.ProjectExecutionPortal.FusionPortalApi\Equinor.ProjectExecutionPortal.FusionPortalApi.csproj" />
<ProjectReference Include="..\Equinor.ProjectExecutionPortal.Infrastructure\Equinor.ProjectExecutionPortal.Infrastructure.csproj" />
</ItemGroup>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ public Handler(IReadWriteContext context, IMapper mapper, IAppService appService

var onboardedApp = _mapper.Map<OnboardedApp, OnboardedAppDto>(entity);

await _appService.EnrichAppWithFusionAppData(onboardedApp, cancellationToken);
await _appService.EnrichWithFusionAppData(onboardedApp, cancellationToken);

return onboardedApp;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public async Task<IList<OnboardedAppDto>> Handle(GetOnboardedAppsQuery request,

var onboardedApps = _mapper.Map<List<Domain.Entities.OnboardedApp>, List<OnboardedAppDto>>(entity);

await _appService.EnrichAppsWithFusionAppData(onboardedApps, cancellationToken);
await _appService.EnrichWithFusionAppData(onboardedApps, cancellationToken);

return onboardedApps;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,44 +1,22 @@
using Equinor.ProjectExecutionPortal.Application.Infrastructure.Mappings;
using Equinor.ProjectExecutionPortal.Application.Queries.ContextTypes;
using Equinor.ProjectExecutionPortal.FusionPortalApi.Apps.Models;
using Fusion.Integration.Apps.Abstractions.Models;

namespace Equinor.ProjectExecutionPortal.Application.Queries.OnboardedApps;

public enum FusionPortalAppInformationAmount
{
Minimal,
All
}

public class OnboardedAppDto : IMapFrom<Domain.Entities.OnboardedApp>
{
public Guid Id { get; set; }
public string AppKey { get; set; }
public FusionPortalAppInformation? AppInformation { get; set; }
public IList<ContextTypeDto> ContextTypes { get; set; }
public string? AppKey { get; set; }
public string? DisplayName { get; set; }
public string? Description { get; set; }
public App? AppInformation { get; set; }
public IList<ContextTypeDto> ContextTypes { get; set; } = new List<ContextTypeDto>();

public void SupplyWithFusionData(FusionPortalAppInformation appInformation, FusionPortalAppInformationAmount amount)
public void SupplyWithFusionData(App app)
{
switch (amount)
{
case FusionPortalAppInformationAmount.All:
AppInformation = appInformation;
break;

case FusionPortalAppInformationAmount.Minimal:
var appInfo = new FusionPortalAppInformation
{
Key = appInformation.Key,
Name = appInformation.Name,
Description = appInformation.Description
};

AppInformation = appInfo;

break;

default:
throw new ArgumentOutOfRangeException(nameof(amount), amount, null);
}
DisplayName = app.DisplayName;
Description = app.Description;
AppInformation = app;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ public GetOnboardedContextByExternalIdContextTypeQuery(string externalId, string
ContextType = contextType;
}

public string ExternalId { get; } = null!;
public string ContextType { get; } = null!;
public string ExternalId { get; }
public string ContextType { get; }

public class Handler : IRequestHandler<GetOnboardedContextByExternalIdContextTypeQuery, OnboardedContextDto?>
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
using Equinor.ProjectExecutionPortal.Application.Services.ContextService;
using Equinor.ProjectExecutionPortal.Domain.Common.Exceptions;
using Equinor.ProjectExecutionPortal.Domain.Entities;
using Equinor.ProjectExecutionPortal.Domain.Infrastructure;
using Equinor.ProjectExecutionPortal.Infrastructure;
using MediatR;
using Microsoft.EntityFrameworkCore;

namespace Equinor.ProjectExecutionPortal.Application.Queries.Portals.GetPortalAppKeys;

public class GetContextualAndGlobalAppKeysByPortalAndContextQuery : QueryBase<IList<string>>
{
public GetContextualAndGlobalAppKeysByPortalAndContextQuery(Guid portalId, Guid contextId)
{
PortalId = portalId;
ContextId = contextId;
}

public Guid PortalId { get; }
public Guid ContextId { get; }

public class Handler : IRequestHandler<GetContextualAndGlobalAppKeysByPortalAndContextQuery, IList<string>>
{
private readonly IReadWriteContext _readWriteContext;

private readonly IContextService _contextService;

public Handler(IReadWriteContext readWriteContext, IContextService contextService)
{
_readWriteContext = readWriteContext;

_contextService = contextService;
}

public async Task<IList<string>> Handle(GetContextualAndGlobalAppKeysByPortalAndContextQuery request, CancellationToken cancellationToken)
{
var fusionContext = await _contextService.GetFusionContext(request.ContextId, cancellationToken);

if (fusionContext == null)
{
throw new NotFoundException($"Invalid context-id: {request.ContextId}");
}

var portalWithContextualAndGlobalApps = await _readWriteContext.Set<Portal>()
.AsNoTracking()
.Include(portal => portal.Apps
.Where(app => app.OnboardedContext == null || (app.OnboardedContext.ExternalId == fusionContext.ExternalId && app.OnboardedContext.Type == fusionContext.Type.Name)))
.ThenInclude(app => app.OnboardedApp)
.ThenInclude(app => app.ContextTypes)
.FirstOrDefaultAsync(x => x.Id == request.PortalId, cancellationToken);

if (portalWithContextualAndGlobalApps == null)
{
throw new NotFoundException(nameof(Portal), request.PortalId);
}

var contextualAndGlobalPortalAppKeys = portalWithContextualAndGlobalApps.Apps
.Where(apps => apps.OnboardedApp.ContextTypes.Count == 0 || apps.OnboardedApp.ContextTypes.Any(m => m.ContextTypeKey == fusionContext.Type.Name))
.Select(app => app.OnboardedApp.AppKey)
.ToList();

return contextualAndGlobalPortalAppKeys;
}
}
}
Loading
Loading