Skip to content

Commit

Permalink
Merge pull request #195 from bcgov/BCPSDEMS-1174-hold-non-matching-VC…
Browse files Browse the repository at this point in the history
…-accounts

Bcpsdems 1174 hold non matching vc accounts
  • Loading branch information
leewrigh authored Aug 17, 2023
2 parents 588da7f + fa9726c commit b2d4b22
Show file tree
Hide file tree
Showing 194 changed files with 27,244 additions and 71 deletions.
20 changes: 20 additions & 0 deletions backend/ApprovalFlow/ApprovalFlow.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<Version>1.0.0</Version>
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\common\Common.csproj" />
</ItemGroup>

<ItemGroup>
<Folder Include="Data\Migrations\" />
</ItemGroup>


</Project>
93 changes: 93 additions & 0 deletions backend/ApprovalFlow/ApprovalFlowConfiguration.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
namespace ApprovalFlow;
using common.Constants.Auth;

public class ApprovalFlowConfiguration
{
public static bool IsProduction() => EnvironmentName == Environments.Production;
public static bool IsDevelopment() => EnvironmentName == Environments.Development;
private static readonly string? EnvironmentName = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT");

public ConnectionStringConfiguration ConnectionStrings { get; set; } = new();
public KafkaClusterConfiguration KafkaCluster { get; set; } = new();
public ApprovalConfiguration ApprovalConfig { get; set; } = new();
public KeycloakConfiguration Keycloak { get; set; } = new();

public SchemaRegistryConfiguration SchemaRegistry { get; set; } = new();
public TelemeteryConfiguration Telemetry { get; set; } = new TelemeteryConfiguration();
public SplunkConfiguration SplunkConfig { get; set; } = new SplunkConfiguration();


public class SplunkConfiguration
{
public string Host { get; set; } = string.Empty;
public string CollectorToken { get; set; } = string.Empty;
}

public class ApprovalConfiguration
{
public string NotifyEmail { get; set; } = string.Empty;
public string Subject { get; set; } = string.Empty;
}

// ------- Configuration Objects -------

public class TelemeteryConfiguration
{
public string CollectorUrl { get; set; } = string.Empty;
public string AzureConnectionString { get; set; } = string.Empty;
public bool LogToConsole { get; set; }

}


public class ConnectionStringConfiguration
{
public string ApprovalFlowDataStore { get; set; } = string.Empty;
}

public class KeycloakConfiguration
{
public string RealmUrl { get; set; } = string.Empty;
public string WellKnownConfig => KeycloakUrls.WellKnownConfig(this.RealmUrl);
public string TokenUrl => KeycloakUrls.Token(this.RealmUrl);
public string AdministrationUrl { get; set; } = string.Empty;
public string AdministrationClientId { get; set; } = string.Empty;
public string AdministrationClientSecret { get; set; } = string.Empty;
public string HcimClientId { get; set; } = string.Empty;
}



public class SchemaRegistryConfiguration
{
public string Url { get; set; } = string.Empty;
public string ClientId { get; set; } = string.Empty;
public string ClientSecret { get; set; } = string.Empty;

}


public class KafkaClusterConfiguration
{
public string Url { get; set; } = string.Empty;
public string BootstrapServers { get; set; } = string.Empty;
public string SaslOauthbearerTokenEndpointUrl { get; set; } = string.Empty;
public string IncomingApprovalCreationTopic { get; set; } = string.Empty;
public string ApprovalResponseTopic { get; set; } = string.Empty;
public string NotificationTopic { get;set; } = string.Empty;

public string SaslOauthbearerProducerClientId { get; set; } = string.Empty;
public string SaslOauthbearerProducerClientSecret { get; set; } = string.Empty;
public string SaslOauthbearerConsumerClientId { get; set; } = string.Empty;
public string SaslOauthbearerConsumerClientSecret { get; set; } = string.Empty;
public string SslCaLocation { get; set; } = string.Empty;
public string SslCertificateLocation { get; set; } = string.Empty;
public string SslKeyLocation { get; set; } = string.Empty;
public string Scope { get; set; } = "openid";
public string ConsumerGroupId { get; set; } = "approval-consumer-group";


}

}

21 changes: 21 additions & 0 deletions backend/ApprovalFlow/Data/Approval/ApprovalHistory.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
namespace ApprovalFlow.Data.Approval;

using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using Common.Models.Approval;
using DIAM.Common.Models;
using NodaTime;

[Table(nameof(ApprovalHistory))]
public class ApprovalHistory : BaseAuditable
{
[Key]
public int Id { get; set; }
public string DecisionNote { get; set; } = string.Empty;
public string Approver { get; set; } = string.Empty;
public int RequestId { get; set; }
public Request AccessRequest { get; set; }
public Instant? Deleted { get; set; }
public ApprovalStatus Status { get; set; } = ApprovalStatus.PENDING;

}
24 changes: 24 additions & 0 deletions backend/ApprovalFlow/Data/Approval/ApprovalRequest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
namespace ApprovalFlow.Data.Approval;

using NodaTime;
using System.ComponentModel.DataAnnotations.Schema;
using System.ComponentModel.DataAnnotations;
using DIAM.Common.Models;

[Table(nameof(ApprovalRequest))]
public class ApprovalRequest : BaseAuditable
{
[Key]
public int Id { get; set; }
public string Reason { get; set; } = string.Empty;
[Required]
public string MessageKey { get; set; } = string.Empty;
public string UserId { get; set; } = string.Empty;
public string IdentityProvider { get; set; } = string.Empty;
public int NoOfApprovalsRequired { get; set; }
public string RequiredAccess { get; set; } = string.Empty;
public Instant? Approved { get; set; }
public Instant? Completed { get; set; }
public ICollection<Request> Requests { get; set; } = new List<Request>();

}
15 changes: 15 additions & 0 deletions backend/ApprovalFlow/Data/Approval/MappingProfile.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
namespace ApprovalFlow.Data.Approval;

using AutoMapper;
using Common.Models.Approval;

public class MappingProfile : Profile
{
public MappingProfile()
{
this.CreateMap<ApprovalRequest, ApprovalModel>();
this.CreateMap<Request, RequestModel>();
this.CreateMap<ApprovalHistory, ApprovalHistoryModel>();

}
}
32 changes: 32 additions & 0 deletions backend/ApprovalFlow/Data/Approval/Request.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
namespace ApprovalFlow.Data.Approval;

using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using DIAM.Common.Models;

/// <summary>
/// An ApprovalRequest can contain one or more requests, this allows us to group requests for a user
/// together. E.g. a lawyer might be requesting to be a participant in core and user in disclosure.
/// Or in future a user may request to have access to something and also change their email address
/// </summary>
[Table(nameof(Request))]
public class Request : BaseAuditable
{
[Key]
public int Id { get; set; }
[Required]
public int ApprovalRequestId { get; set; }
public ApprovalRequest? ApprovalRequest { get; set; } // navigation property
public int RequestId { get; set; }

public ApprovalType ApprovalType { get; set; } = ApprovalType.AccessRequest;
public string RequestType { get; set; } = string.Empty;
public ICollection<ApprovalHistory> History { get; set; }

}

public enum ApprovalType
{
AccessRequest,
AccountChange
}
87 changes: 87 additions & 0 deletions backend/ApprovalFlow/Data/ApprovalFlowDataStoreDbContext.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
namespace ApprovalFlow.Data;

using ApprovalFlow.Data.Approval;
using ApprovalFlow.Models;
using DIAM.Common.Models;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using NodaTime;

public class ApprovalFlowDataStoreDbContext : DbContext
{
private readonly IClock clock;

public ApprovalFlowDataStoreDbContext(DbContextOptions<ApprovalFlowDataStoreDbContext> options, IClock clock) : base(options) => this.clock = clock;
public DbSet<IdempotentConsumer> IdempotentConsumers { get; set; } = default!;
public DbSet<ApprovalRequest> ApprovalRequests { get; set; } = default!;
public DbSet<Request> Requests { get; set; } = default!;
public DbSet<ApprovalHistory> ApprovalHistories { get; set; } = default!;



public override int SaveChanges()
{
this.ApplyAudits();

return base.SaveChanges();
}

public override async Task<int> SaveChangesAsync(CancellationToken cancellationToken = default)
{
this.ApplyAudits();

return await base.SaveChangesAsync(cancellationToken);
}

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.HasDefaultSchema("approvalflow");
base.OnModelCreating(modelBuilder);

modelBuilder
.Entity<Request>()
.Property(d => d.ApprovalType)
.HasConversion(new EnumToStringConverter<ApprovalType>());

modelBuilder.ApplyConfigurationsFromAssembly(typeof(ApprovalFlowDataStoreDbContext).Assembly);
}

private void ApplyAudits()
{
this.ChangeTracker.DetectChanges();
var updated = this.ChangeTracker.Entries()
.Where(x => x.Entity is BaseAuditable
&& (x.State == EntityState.Added || x.State == EntityState.Modified));

var currentInstant = this.clock.GetCurrentInstant();

foreach (var entry in updated)
{
entry.CurrentValues[nameof(BaseAuditable.Modified)] = currentInstant;

if (entry.State == EntityState.Added)
{
entry.CurrentValues[nameof(BaseAuditable.Created)] = currentInstant;
}
else
{
entry.Property(nameof(BaseAuditable.Created)).IsModified = false;
}
}
}

public async Task IdempotentConsumer(string messageId, string consumer, Instant consumeDate)
{
await this.IdempotentConsumers.AddAsync(new IdempotentConsumer
{
MessageId = messageId,
Consumer = consumer,
ConsumeDate = consumeDate
});
await this.SaveChangesAsync();
}

public async Task<bool> HasBeenProcessed(string messageId, string consumer) => await this.IdempotentConsumers.AnyAsync(x => x.MessageId == messageId && x.Consumer == consumer);


}
Loading

0 comments on commit b2d4b22

Please sign in to comment.