Skip to content

Commit

Permalink
Add new DynamicsPdfFormatter (#173)
Browse files Browse the repository at this point in the history
  • Loading branch information
ivarne authored Feb 22, 2023
1 parent 17e601c commit 63f95da
Show file tree
Hide file tree
Showing 4 changed files with 99 additions and 25 deletions.
27 changes: 13 additions & 14 deletions src/Altinn.App.Api/Controllers/PdfController.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
using System;
using System.Linq;
#nullable enable

using System.Text.Json;
using System.Threading.Tasks;
using Altinn.App.Core.Features;
using Altinn.App.Core.Interface;
using Altinn.App.Core.Internal.AppModel;
Expand Down Expand Up @@ -66,13 +65,13 @@ public async Task<ActionResult> GetPdfFormat(
return NotFound("Did not find instance");
}

string taskId = instance.Process?.CurrentTask?.ElementId;
string? taskId = instance.Process?.CurrentTask?.ElementId;
if (taskId == null)
{
return Conflict("Instance does not have a valid currentTask");
}

DataElement dataElement = instance.Data.FirstOrDefault(d => d.Id == dataGuid.ToString());
DataElement? dataElement = instance.Data.FirstOrDefault(d => d.Id == dataGuid.ToString());
if (dataElement == null)
{
return NotFound("Did not find data element");
Expand All @@ -84,20 +83,20 @@ public async Task<ActionResult> GetPdfFormat(
JsonSerializerOptions options = new() { PropertyNamingPolicy = JsonNamingPolicy.CamelCase };

string layoutSetsString = _resources.GetLayoutSets();
LayoutSets layoutSets = null;
LayoutSet layoutSet = null;
LayoutSets? layoutSets = null;
LayoutSet? layoutSet = null;
if (!string.IsNullOrEmpty(layoutSetsString))
{
layoutSets = JsonSerializer.Deserialize<LayoutSets>(layoutSetsString, options);
layoutSets = JsonSerializer.Deserialize<LayoutSets>(layoutSetsString, options)!;
layoutSet = layoutSets.Sets?.FirstOrDefault(t => t.DataType.Equals(dataElement.DataType) && t.Tasks.Contains(taskId));
}

string layoutSettingsFileContent = layoutSet == null ? _resources.GetLayoutSettingsString() : _resources.GetLayoutSettingsStringForSet(layoutSet.Id);
string? layoutSettingsFileContent = layoutSet == null ? _resources.GetLayoutSettingsString() : _resources.GetLayoutSettingsStringForSet(layoutSet.Id);

LayoutSettings layoutSettings = null;
LayoutSettings? layoutSettings = null;
if (!string.IsNullOrEmpty(layoutSettingsFileContent))
{
layoutSettings = JsonSerializer.Deserialize<LayoutSettings>(layoutSettingsFileContent, options);
layoutSettings = JsonSerializer.Deserialize<LayoutSettings>(layoutSettingsFileContent, options)!;
}

// Ensure layoutsettings are initialized in FormatPdf
Expand All @@ -109,12 +108,12 @@ public async Task<ActionResult> GetPdfFormat(

object data = await _dataClient.GetFormData(instanceGuid, dataType, org, app, instanceOwnerPartyId, new Guid(dataElement.Id));

layoutSettings = await _pdfFormatter.FormatPdf(layoutSettings, data);
layoutSettings = await _pdfFormatter.FormatPdf(layoutSettings, data, instance, layoutSet);

var result = new
{
ExcludedPages = layoutSettings.Pages.ExcludeFromPdf,
ExcludedComponents = layoutSettings.Components.ExcludeFromPdf,
ExcludedPages = layoutSettings?.Pages?.ExcludeFromPdf ?? new List<string>(),
ExcludedComponents = layoutSettings?.Components?.ExcludeFromPdf ?? new List<string>(),
};
return Ok(result);
}
Expand Down
29 changes: 22 additions & 7 deletions src/Altinn.App.Core/Features/IPdfFormatter.cs
Original file line number Diff line number Diff line change
@@ -1,15 +1,30 @@
using Altinn.App.Core.Models;
using Altinn.Platform.Storage.Interface.Models;

namespace Altinn.App.Core.Features
namespace Altinn.App.Core.Features;

/// <summary>
/// Interface to customize PDF formatting.
/// </summary>
/// <remarks>
/// This interface has been changed and both methods now has default implementation for backwards compatibility.
/// All users will call the method with the Instance parameter, and a user only needs to implement one
/// </remarks>
public interface IPdfFormatter
{
/// <summary>
/// Interface to customize PDF formatting.
/// Old method to format the PDF dynamically (without Instance)
/// </summary>
Task<LayoutSettings> FormatPdf(LayoutSettings layoutSettings, object data)
{
throw new NotImplementedException();
}

/// <summary>
/// Method to format the PDF dynamically (new version with the instance)
/// </summary>
public interface IPdfFormatter
async Task<LayoutSettings> FormatPdf(LayoutSettings layoutSettings, object data, Instance instance, LayoutSet? layoutSet)
{
/// <summary>
/// Method to format the PDF dynamically
/// </summary>
Task<LayoutSettings> FormatPdf(LayoutSettings layoutSettings, object data);
return await FormatPdf(layoutSettings, data);
}
}
60 changes: 60 additions & 0 deletions src/Altinn.App.Core/Features/Pdf/DynamicsPdfFormatter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
using Altinn.App.Core.Internal.Expressions;
using Altinn.App.Core.Models;
using Altinn.Platform.Storage.Interface.Models;

namespace Altinn.App.Core.Features.Pdf;

/// <summary>
/// Custom formatter that reads the `hidden` properties of components and pages
/// to determine if they should be hidden in PDF as well.
/// </summary>
/// <remarks>
/// Add this to dependency injection in order to run dynamics for hiding pages and comonents.
/// <code>
/// services.AddTrancient&lt;IPdfFormatter, DynamicsPdfFormatter&gt;();
/// </code>
/// </remarks>
public class DynamicsPdfFormatter : IPdfFormatter
{
private readonly LayoutEvaluatorStateInitializer _layoutStateInit;

/// <summary>
/// Constructor for <see cref="DynamicsPdfFormatter" />
/// </summary>
public DynamicsPdfFormatter(LayoutEvaluatorStateInitializer layoutStateInit)
{
_layoutStateInit = layoutStateInit;
}

/// <inheritdoc />
public async Task<LayoutSettings> FormatPdf(LayoutSettings layoutSettings, object data, Instance instance, LayoutSet? layoutSet)
{
layoutSettings.Pages ??= new();
layoutSettings.Pages.ExcludeFromPdf ??= new();
layoutSettings.Components ??= new();
layoutSettings.Components.ExcludeFromPdf ??= new();

var state = await _layoutStateInit.Init(instance, data, layoutSetId: layoutSet?.Id);
foreach (var pageContext in state.GetComponentContexts())
{
var pageHidden = ExpressionEvaluator.EvaluateBooleanExpression(state, pageContext, "hidden", false);
if (pageHidden)
{
layoutSettings.Pages.ExcludeFromPdf.Add(pageContext.Component.Id);
}
else
{
//TODO: figure out how pdf reacts to groups one level down.
foreach (var componentContext in pageContext.ChildContexts)
{
var componentHidden = ExpressionEvaluator.EvaluateBooleanExpression(state, componentContext, "hidden", false);
if (componentHidden)
{
layoutSettings.Components.ExcludeFromPdf.Add(componentContext.Component.Id);
}
}
}
}
return layoutSettings;
}
}
8 changes: 4 additions & 4 deletions src/Altinn.App.Core/Internal/Pdf/PdfService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ IOptions<GeneralSettings> generalSettings
_dataClient = dataClient;
_httpContextAccessor = httpContextAccessor;
_profileClient = profileClient;
_registerClient= registerClient;
_registerClient = registerClient;
_pdfFormatter = pdfFormatter;
_pdfGeneratorClient = pdfGeneratorClient;
_pdfGeneratorSettings = pdfGeneratorSettings.Value;
Expand Down Expand Up @@ -140,7 +140,7 @@ public async Task GenerateAndStoreReceiptPDF(Instance instance, string taskId, D

object data = await _dataClient.GetFormData(instanceGuid, dataElementModelType, org, app, instanceOwnerId, new Guid(dataElement.Id));

layoutSettings = await _pdfFormatter.FormatPdf(layoutSettings, data);
layoutSettings = await _pdfFormatter.FormatPdf(layoutSettings, data, instance, layoutSet);
XmlSerializer serializer = new XmlSerializer(dataElementModelType);
using MemoryStream stream = new MemoryStream();

Expand Down Expand Up @@ -216,7 +216,7 @@ private async Task<DataElement> StorePDF(Stream pdfStream, Instance instance, Te
textResource.Resources.Find(textResourceElement => textResourceElement.Id.Equals("ServiceName"));

fileName = (titleText != null && !string.IsNullOrEmpty(titleText.Value)) ? $"{titleText.Value}.pdf" : $"{app}.pdf";

fileName = GetValidFileName(fileName);

return await _dataClient.InsertBinaryData(
Expand Down Expand Up @@ -280,7 +280,7 @@ private static string GetFileName(Instance instance, TextResource textResource)
{
fileName = titleText.Value + ".pdf";
}

return GetValidFileName(fileName);
}

Expand Down

0 comments on commit 63f95da

Please sign in to comment.