Skip to content

Commit d2496bd

Browse files
FrostyApeOneFrostyApeOne
authored andcommitted
Fixed tempalte caching issue and issue where already created applications weren't using their own template version
1 parent ca548a7 commit d2496bd

5 files changed

Lines changed: 361 additions & 24 deletions

File tree

src/DfE.ExternalApplications.Infrastructure/DfE.ExternalApplications.Infrastructure.csproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@
88

99
<ItemGroup>
1010
<PackageReference Include="DfE.CoreLibs.Caching" Version="1.0.10" />
11-
<PackageReference Include="DfE.CoreLibs.Contracts" Version="1.0.26" />
12-
<PackageReference Include="GovUK.Dfe.ExternalApplications.Api.Client" Version="0.1.6" />
11+
<PackageReference Include="DfE.CoreLibs.Contracts" Version="1.0.27" />
12+
<PackageReference Include="GovUK.Dfe.ExternalApplications.Api.Client" Version="0.1.7" />
1313
<PackageReference Include="Microsoft.AspNetCore.Http.Extensions" Version="2.3.0" />
1414
</ItemGroup>
1515

src/DfE.ExternalApplications.Web/DfE.ExternalApplications.Web.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
<ItemGroup>
1111
<PackageReference Include="DfE.CoreLibs.Caching" Version="1.0.10" />
12-
<PackageReference Include="GovUK.Dfe.ExternalApplications.Api.Client" Version="0.1.6" />
12+
<PackageReference Include="GovUK.Dfe.ExternalApplications.Api.Client" Version="0.1.7" />
1313
<PackageReference Include="GovUk.Frontend.AspNetCore" Version="2.8.1" />
1414
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
1515
<PackageReference Include="DfE.CoreLibs.Security" Version="1.1.13" />

src/DfE.ExternalApplications.Web/Pages/ApplicationPreview.cshtml.cs

Lines changed: 118 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,19 +24,27 @@ public class ApplicationPreviewModel : PageModel
2424

2525
private readonly IFieldRendererService _renderer;
2626
private readonly IFormTemplateProvider _templateProvider;
27+
private readonly IFormTemplateParser _templateParser;
2728
private readonly IApplicationResponseService _applicationResponseService;
2829
private readonly IApplicationsClient _applicationsClient;
2930
private readonly ILogger<ApplicationPreviewModel> _logger;
3031

32+
/// <summary>
33+
/// Stores the current application data to access template schema for existing applications
34+
/// </summary>
35+
private ApplicationDto? _currentApplication;
36+
3137
public ApplicationPreviewModel(
3238
IFieldRendererService renderer,
3339
IFormTemplateProvider templateProvider,
40+
IFormTemplateParser templateParser,
3441
IApplicationResponseService applicationResponseService,
3542
IApplicationsClient applicationsClient,
3643
ILogger<ApplicationPreviewModel> logger)
3744
{
3845
_renderer = renderer;
3946
_templateProvider = templateProvider;
47+
_templateParser = templateParser;
4048
_applicationResponseService = applicationResponseService;
4149
_applicationsClient = applicationsClient;
4250
_logger = logger;
@@ -145,9 +153,56 @@ public bool IsApplicationEditable()
145153
return ApplicationStatus.Equals("InProgress", StringComparison.OrdinalIgnoreCase);
146154
}
147155

156+
/// <summary>
157+
/// Loads the appropriate template schema based on whether this is a new or existing application.
158+
/// For new applications, loads the latest template schema.
159+
/// For existing applications, loads the template schema version that was used when the application was created.
160+
/// </summary>
148161
private async Task LoadTemplateAsync()
149162
{
150-
Template = await _templateProvider.GetTemplateAsync(TemplateId);
163+
try
164+
{
165+
// If we have an existing application with template schema, use that version
166+
if (_currentApplication?.TemplateSchema != null)
167+
{
168+
_logger.LogDebug("Using template schema from existing application {ApplicationId} with template version {TemplateVersionId}",
169+
_currentApplication.ApplicationId, _currentApplication.TemplateVersionId);
170+
171+
Template = await LoadTemplateFromSchemaAsync(_currentApplication.TemplateSchema.JsonSchema);
172+
}
173+
else
174+
{
175+
// For new applications or when template schema is not available, use the latest template
176+
_logger.LogDebug("Loading latest template schema for template {TemplateId}", TemplateId);
177+
Template = await _templateProvider.GetTemplateAsync(TemplateId);
178+
}
179+
}
180+
catch (Exception ex)
181+
{
182+
_logger.LogError(ex, "Failed to load template {TemplateId}", TemplateId);
183+
throw;
184+
}
185+
}
186+
187+
/// <summary>
188+
/// Converts a TemplateSchemaDto to a FormTemplate using the template parser.
189+
/// This ensures consistent parsing logic regardless of the template source.
190+
/// </summary>
191+
private async Task<FormTemplate> LoadTemplateFromSchemaAsync(string templateSchema)
192+
{
193+
try
194+
{
195+
// Convert to stream for parser
196+
using var stream = new MemoryStream(System.Text.Encoding.UTF8.GetBytes(templateSchema));
197+
198+
// Use the same parser that's used for API templates to ensure consistency
199+
return await _templateParser.ParseAsync(stream);
200+
}
201+
catch (Exception ex)
202+
{
203+
_logger.LogError(ex, "Failed to parse template schema from application");
204+
throw new InvalidOperationException("Failed to parse template schema from application", ex);
205+
}
151206
}
152207

153208
public string GetFieldValue(string fieldId)
@@ -483,9 +538,18 @@ public bool AreAllTasksCompleted()
483538
return result;
484539
}
485540

486-
private async Task EnsureApplicationIdAsync()
541+
private async Task EnsureApplicationIdAsync()
487542
{
488-
// First try to get ApplicationId from session (for newly created applications)
543+
// First check if we have template schema stored in session for this reference
544+
var templateSchemaKey = $"TemplateSchema_{ReferenceNumber}";
545+
var templateVersionIdKey = $"TemplateVersionId_{ReferenceNumber}";
546+
var templateVersionNoKey = $"TemplateVersionNo_{ReferenceNumber}";
547+
var storedTemplateSchema = HttpContext.Session.GetString(templateSchemaKey);
548+
var storedTemplateVersionId = HttpContext.Session.GetString(templateVersionIdKey);
549+
var storedTemplateId = HttpContext.Session.GetString("TemplateId");
550+
var storedTemplateVersionNo = HttpContext.Session.GetString(templateVersionNoKey);
551+
552+
// Check if we have basic application data in session
489553
var applicationIdString = HttpContext.Session.GetString("ApplicationId");
490554
var sessionReference = HttpContext.Session.GetString("ApplicationReference");
491555

@@ -496,22 +560,62 @@ private async Task EnsureApplicationIdAsync()
496560
if (Guid.TryParse(applicationIdString, out var sessionAppId))
497561
{
498562
ApplicationId = sessionAppId;
499-
return;
563+
564+
// If we have template schema in session, create a minimal ApplicationDto
565+
if (!string.IsNullOrEmpty(storedTemplateSchema) && !string.IsNullOrEmpty(storedTemplateVersionId))
566+
{
567+
_currentApplication = new ApplicationDto
568+
{
569+
ApplicationId = sessionAppId,
570+
ApplicationReference = sessionReference,
571+
TemplateVersionId = Guid.Parse(storedTemplateVersionId),
572+
TemplateSchema = new TemplateSchemaDto
573+
{
574+
JsonSchema = storedTemplateSchema,
575+
TemplateVersionId = new Guid(storedTemplateVersionId),
576+
TemplateId = new Guid(storedTemplateId),
577+
VersionNumber = storedTemplateVersionNo ?? String.Empty
578+
579+
}
580+
};
581+
582+
_logger.LogDebug("Using cached template schema for application {ApplicationId} with template version {TemplateVersionId}",
583+
sessionAppId, storedTemplateVersionId);
584+
return;
585+
}
586+
else
587+
{
588+
// For newly created applications, we don't have template schema
589+
_logger.LogDebug("Using session-based application {ApplicationId} (no template schema available)", sessionAppId);
590+
return;
591+
}
500592
}
501593
}
502594

503-
// If not in session or different reference, try to get from API
595+
// If not in session or incomplete data, fetch from API
504596
try
505597
{
506598
var application = await _applicationsClient.GetApplicationByReferenceAsync(ReferenceNumber);
507599

508600
if (application != null)
509601
{
510602
ApplicationId = application.ApplicationId;
511-
// Store in session for future use
603+
_currentApplication = application; // Store for template loading
604+
605+
// Store application data in session for future use
512606
HttpContext.Session.SetString("ApplicationId", application.ApplicationId.ToString());
513607
HttpContext.Session.SetString("ApplicationReference", application.ApplicationReference);
514-
608+
609+
// Store template schema in session for future use
610+
if (application.TemplateSchema?.JsonSchema != null)
611+
{
612+
HttpContext.Session.SetString(templateSchemaKey, application.TemplateSchema.JsonSchema);
613+
HttpContext.Session.SetString(templateVersionIdKey, application.TemplateVersionId.ToString());
614+
615+
_logger.LogDebug("Cached template schema for reference {ReferenceNumber} with template version {TemplateVersionId}",
616+
ReferenceNumber, application.TemplateVersionId);
617+
}
618+
515619
// Store application status in session
516620
if (application.Status != null)
517621
{
@@ -521,6 +625,10 @@ private async Task EnsureApplicationIdAsync()
521625

522626
// Load existing response data into session for existing applications
523627
await LoadResponseDataIntoSessionAsync(application);
628+
629+
_logger.LogDebug("Loaded application {ApplicationId} from API with template version {TemplateVersionId}",
630+
application.ApplicationId, application.TemplateVersionId);
631+
return;
524632
}
525633
else
526634
{
@@ -529,8 +637,10 @@ private async Task EnsureApplicationIdAsync()
529637
}
530638
catch (Exception ex)
531639
{
532-
_logger.LogError(ex, "Failed to retrieve application information for reference {ReferenceNumber}", ReferenceNumber);
640+
_logger.LogError(ex, "Failed to retrieve application information from API for reference {ReferenceNumber}", ReferenceNumber);
533641
}
642+
643+
_logger.LogWarning("Could not determine ApplicationId for reference {ReferenceNumber}", ReferenceNumber);
534644
}
535645

536646
private async Task LoadResponseDataIntoSessionAsync(ApplicationDto application)

0 commit comments

Comments
 (0)