Skip to content
This repository was archived by the owner on Jul 28, 2025. It is now read-only.

Commit f57c6f7

Browse files
feat: adding discovery function (#6)
Signed-off-by: Tyrrellion <[email protected]> Co-authored-by: alex-clayton-1 <[email protected]>
1 parent 3a89da9 commit f57c6f7

20 files changed

+699
-43
lines changed

.github/workflows/stage-2-test.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ jobs:
9191
- name: "Checkout code"
9292
uses: actions/checkout@v4
9393
with:
94+
submodules: 'true'
9495
fetch-depth: 0 # Full history is needed to improving relevancy of reporting
9596
- name: "Perform static analysis"
9697
uses: ./.github/actions/perform-static-analysis

.gitmodules

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
[submodule "src/dotnet-mesh-client"]
2+
# path = src/Shared/dotnet-mesh-client
3+
path = src/dotnet-mesh-client
4+
url = https://github.com/NHSDigital/dotnet-mesh-client.git
5+
branch = main

.vscode/extensions.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
{
22
"recommendations": [
3+
"ms-azuretools.vscode-azurefunctions",
4+
"ms-dotnettools.csharp",
35
"alefragnani.bookmarks",
46
"davidanson.vscode-markdownlint",
57
"dbaeumer.vscode-eslint",
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
using Microsoft.EntityFrameworkCore;
2+
using Microsoft.EntityFrameworkCore.Design;
3+
using ServiceLayer.Mesh.Data;
4+
5+
namespace ParticipantManager.API.Data;
6+
7+
public class DesignTimeDbContextFactory : IDesignTimeDbContextFactory<ServiceLayerDbContext>
8+
{
9+
public ServiceLayerDbContext CreateDbContext(string[] args)
10+
{
11+
var connectionString = Environment.GetEnvironmentVariable("DatabaseConnectionString");
12+
if (string.IsNullOrEmpty(connectionString))
13+
{
14+
throw new InvalidOperationException("Connection string 'DatabaseConnectionString' is not configured.");
15+
}
16+
17+
var optionsBuilder = new DbContextOptionsBuilder<ServiceLayerDbContext>();
18+
optionsBuilder.UseSqlServer(connectionString);
19+
20+
return new ServiceLayerDbContext(optionsBuilder.Options);
21+
}
22+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
using Microsoft.EntityFrameworkCore;
2+
using ServiceLayer.Mesh.Models;
3+
4+
namespace ServiceLayer.Mesh.Data;
5+
6+
public class ServiceLayerDbContext(DbContextOptions<ServiceLayerDbContext> options) : DbContext(options)
7+
{
8+
public DbSet<MeshFile> MeshFiles { get; set; }
9+
10+
protected override void OnModelCreating(ModelBuilder modelBuilder)
11+
{
12+
// Configure relationships, keys, etc.
13+
modelBuilder.Entity<MeshFile>().HasKey(p => p.FileId);
14+
modelBuilder.Entity<MeshFile>().Property(e => e.Status).HasConversion<string>();
15+
modelBuilder.Entity<MeshFile>().Property(e => e.FileType).HasConversion<string>();
16+
}
17+
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
using Azure.Storage.Queues;
2+
using Microsoft.Azure.Functions.Worker;
3+
using Microsoft.EntityFrameworkCore;
4+
using Microsoft.Extensions.Logging;
5+
using NHS.MESH.Client.Contracts.Services;
6+
using ServiceLayer.Mesh.Data;
7+
using ServiceLayer.Mesh.Models;
8+
9+
namespace ServiceLayer.Mesh.Functions
10+
{
11+
public class DiscoveryFunction
12+
{
13+
private readonly ILogger _logger;
14+
private readonly IMeshInboxService _meshInboxService;
15+
private readonly ServiceLayerDbContext _serviceLayerDbContext;
16+
private readonly QueueClient _queueClient;
17+
18+
public DiscoveryFunction(ILogger<DiscoveryFunction> logger, IMeshInboxService meshInboxService, ServiceLayerDbContext serviceLayerDbContext, QueueClient queueClient)
19+
{
20+
_logger = logger;
21+
_meshInboxService = meshInboxService;
22+
_serviceLayerDbContext = serviceLayerDbContext;
23+
_queueClient = queueClient;
24+
}
25+
26+
[Function("DiscoveryFunction")]
27+
public async Task Run([TimerTrigger("%DiscoveryTimerExpression%")] TimerInfo myTimer)
28+
{
29+
_logger.LogInformation($"DiscoveryFunction started at: {DateTime.Now}");
30+
31+
var mailboxId = Environment.GetEnvironmentVariable("BSSMailBox")
32+
?? throw new InvalidOperationException($"Environment variable 'BSSMailBox' is not set or is empty.");
33+
34+
var response = await _meshInboxService.GetMessagesAsync(mailboxId);
35+
36+
_queueClient.CreateIfNotExists();
37+
38+
foreach (var messageId in response.Response.Messages)
39+
{
40+
using var transaction = await _serviceLayerDbContext.Database.BeginTransactionAsync();
41+
42+
var existing = await _serviceLayerDbContext.MeshFiles
43+
.AnyAsync(f => f.FileId == messageId);
44+
45+
if (!existing)
46+
{
47+
_serviceLayerDbContext.MeshFiles.Add(new MeshFile
48+
{
49+
FileId = messageId,
50+
FileType = MeshFileType.NbssAppointmentEvents,
51+
MailboxId = mailboxId,
52+
Status = MeshFileStatus.Discovered,
53+
FirstSeenUtc = DateTime.UtcNow,
54+
LastUpdatedUtc = DateTime.UtcNow
55+
});
56+
57+
await _serviceLayerDbContext.SaveChangesAsync();
58+
await transaction.CommitAsync();
59+
60+
_queueClient.SendMessage(messageId);
61+
}
62+
else
63+
{
64+
await transaction.RollbackAsync();
65+
}
66+
}
67+
}
68+
}
69+
}

src/ServiceLayer.Mesh/Migrations/20250512113115_InitialCreate.Designer.cs

Lines changed: 66 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
using System;
2+
using Microsoft.EntityFrameworkCore.Migrations;
3+
4+
#nullable disable
5+
6+
namespace ServiceLayer.Mesh.Migrations
7+
{
8+
/// <inheritdoc />
9+
public partial class InitialCreate : Migration
10+
{
11+
/// <inheritdoc />
12+
protected override void Up(MigrationBuilder migrationBuilder)
13+
{
14+
migrationBuilder.CreateTable(
15+
name: "MeshFiles",
16+
columns: table => new
17+
{
18+
FileId = table.Column<string>(type: "nvarchar(255)", maxLength: 255, nullable: false),
19+
FileType = table.Column<string>(type: "nvarchar(50)", maxLength: 50, nullable: false),
20+
MailboxId = table.Column<string>(type: "nvarchar(50)", maxLength: 50, nullable: false),
21+
Status = table.Column<string>(type: "nvarchar(20)", maxLength: 20, nullable: false),
22+
BlobPath = table.Column<string>(type: "nvarchar(1024)", maxLength: 1024, nullable: true),
23+
FirstSeenUtc = table.Column<DateTime>(type: "datetime2", nullable: false),
24+
LastUpdatedUtc = table.Column<DateTime>(type: "datetime2", nullable: false)
25+
},
26+
constraints: table =>
27+
{
28+
table.PrimaryKey("PK_MeshFiles", x => x.FileId);
29+
});
30+
}
31+
32+
/// <inheritdoc />
33+
protected override void Down(MigrationBuilder migrationBuilder)
34+
{
35+
migrationBuilder.DropTable(
36+
name: "MeshFiles");
37+
}
38+
}
39+
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
// <auto-generated />
2+
using System;
3+
using Microsoft.EntityFrameworkCore;
4+
using Microsoft.EntityFrameworkCore.Infrastructure;
5+
using Microsoft.EntityFrameworkCore.Metadata;
6+
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
7+
using ServiceLayer.Mesh.Data;
8+
9+
#nullable disable
10+
11+
namespace ServiceLayer.Mesh.Migrations
12+
{
13+
[DbContext(typeof(ServiceLayerDbContext))]
14+
partial class ServiceLayerDbContextModelSnapshot : ModelSnapshot
15+
{
16+
protected override void BuildModel(ModelBuilder modelBuilder)
17+
{
18+
#pragma warning disable 612, 618
19+
modelBuilder
20+
.HasAnnotation("ProductVersion", "9.0.1")
21+
.HasAnnotation("Relational:MaxIdentifierLength", 128);
22+
23+
SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder);
24+
25+
modelBuilder.Entity("ServiceLayer.Mesh.Models.MeshFile", b =>
26+
{
27+
b.Property<string>("FileId")
28+
.HasMaxLength(255)
29+
.HasColumnType("nvarchar(255)");
30+
31+
b.Property<string>("BlobPath")
32+
.HasMaxLength(1024)
33+
.HasColumnType("nvarchar(1024)");
34+
35+
b.Property<string>("FileType")
36+
.IsRequired()
37+
.HasMaxLength(50)
38+
.HasColumnType("nvarchar(50)");
39+
40+
b.Property<DateTime>("FirstSeenUtc")
41+
.HasColumnType("datetime2");
42+
43+
b.Property<DateTime>("LastUpdatedUtc")
44+
.HasColumnType("datetime2");
45+
46+
b.Property<string>("MailboxId")
47+
.IsRequired()
48+
.HasMaxLength(50)
49+
.HasColumnType("nvarchar(50)");
50+
51+
b.Property<string>("Status")
52+
.IsRequired()
53+
.HasMaxLength(20)
54+
.HasColumnType("nvarchar(20)");
55+
56+
b.HasKey("FileId");
57+
58+
b.ToTable("MeshFiles");
59+
});
60+
#pragma warning restore 612, 618
61+
}
62+
}
63+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
using System.ComponentModel.DataAnnotations;
2+
using Microsoft.EntityFrameworkCore.Metadata.Internal;
3+
4+
namespace ServiceLayer.Mesh.Models;
5+
6+
public class MeshFile
7+
{
8+
[MaxLength(255)]
9+
public required string FileId { get; set; }
10+
[MaxLength(50)]
11+
public required MeshFileType FileType { get; set; }
12+
[MaxLength(50)]
13+
public required string MailboxId { get; set; }
14+
[MaxLength(20)]
15+
public required MeshFileStatus Status { get; set; }
16+
[MaxLength(1024)]
17+
public string? BlobPath { get; set; }
18+
public DateTime FirstSeenUtc { get; set; }
19+
public DateTime LastUpdatedUtc { get; set; }
20+
}

0 commit comments

Comments
 (0)