Skip to content

Commit

Permalink
A2 migration changes 4 (#476)
Browse files Browse the repository at this point in the history
- Added support for form summary
- Added stylesheet for html generation
- Added lastchanged as new parameter to MigrationController.CreateDataElement
- Support for migrating text in languages not defined in a2 app
- Removed playwright
- Removed System.Drawing
- Added altinn 2 instance event types
  • Loading branch information
HenningNormann authored Aug 26, 2024
1 parent d16eef8 commit f9b9acf
Show file tree
Hide file tree
Showing 11 changed files with 121 additions and 52 deletions.
42 changes: 41 additions & 1 deletion src/Storage.Interface/Enums/InstanceEventType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,46 @@ public enum InstanceEventType
/// <summary>
/// Instance sent to sign event.
/// </summary>
SentToSign
SentToSign,

/// <summary>
/// Instance sent to payment event.
/// </summary>
SentToPayment,

/// <summary>
/// Instance sent to send in event.
/// </summary>
SentToSendIn,

/// <summary>
/// Instance sent to form filling event.
/// </summary>
SentToFormFill,

/// <summary>
/// Instance forwarded event.
/// </summary>
InstanceForwarded,

/// <summary>
/// Instance right revoked event.
/// </summary>
InstanceRightRevoked,

/// <summary>
/// Notification sent event.
/// </summary>
NotificationSentSms,

/// <summary>
/// Message archived event.
/// </summary>
MessageArchived,

/// <summary>
/// Message read event.
/// </summary>
MessageRead
}
}
3 changes: 0 additions & 3 deletions src/Storage/Altinn.Platform.Storage.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@

<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.22.0" />

<PackageReference Include="Microsoft.Playwright" Version="1.46.0" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.7.1" />
<PackageReference Include="Swashbuckle.AspNetCore.Newtonsoft" Version="6.7.1" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
Expand All @@ -34,8 +33,6 @@
<PackageReference Include="Npgsql.DependencyInjection" Version="8.0.3" />
<PackageReference Include="Yuniql.AspNetCore" Version="1.2.25" />
<PackageReference Include="Yuniql.PostgreSql" Version="1.3.15" />

<PackageReference Include="System.Drawing.Common" Version="8.0.8" />
</ItemGroup>

<ItemGroup Condition="'$(Configuration)'=='Debug'">
Expand Down
27 changes: 22 additions & 5 deletions src/Storage/Controllers/ContentOnDemandController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,13 @@
using System.Threading.Tasks;
using Altinn.Platform.Storage.Clients;
using Altinn.Platform.Storage.Configuration;
using Altinn.Platform.Storage.Helpers;
using Altinn.Platform.Storage.Interface.Models;
using Altinn.Platform.Storage.Repository;
using Altinn.Platform.Storage.Services;

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Microsoft.Playwright;

namespace Altinn.Platform.Storage.Controllers
{
Expand Down Expand Up @@ -135,18 +132,38 @@ public async Task<Stream> GetFormdataAsPdf([FromRoute] string org, [FromRoute] s
/// <returns>The formatted content</returns>
[HttpGet("formdatahtml")]
public async Task<Stream> GetFormdataAsHtml([FromRoute]string org, [FromRoute] string app, [FromRoute] Guid instanceGuid, [FromRoute] Guid dataGuid, [FromRoute] string language)
{
return await GetFormdataAsHtmlInternal(org, app, instanceGuid, dataGuid, language, 3);
}

/// <summary>
/// Gets the formatted content
/// </summary>
/// <param name="org">org</param>
/// <param name="app">app</param>
/// <param name="instanceGuid">instanceGuid</param>
/// <param name="dataGuid">dataGuid</param>
/// <param name="language">language</param>
/// <returns>The formatted content</returns>
[HttpGet("formsummaryhtml")]
public async Task<Stream> GetFormSummaryAsHtml([FromRoute] string org, [FromRoute] string app, [FromRoute] Guid instanceGuid, [FromRoute] Guid dataGuid, [FromRoute] string language)
{
return await GetFormdataAsHtmlInternal(org, app, instanceGuid, dataGuid, language, 2);
}

private async Task<Stream> GetFormdataAsHtmlInternal(string org, string app, Guid instanceGuid, Guid dataGuid, string language, int viewType)
{
(Instance instance, _) = await _instanceRepository.GetOne(instanceGuid, true);
DataElement htmlElement = instance.Data.First(d => d.Id == dataGuid.ToString());
string htmlFormId = htmlElement.Metadata.First(m => m.Key == "formid").Value;
DataElement xmlElement = instance.Data.First(d => d.Metadata.First(m => m.Key == "formid").Value == htmlFormId && d.Id != htmlElement.Id);
string? visiblePagesString = xmlElement.Metadata.FirstOrDefault(m => m.Key == "A2VisiblePages")?.Value;
string visiblePagesString = xmlElement.Metadata.FirstOrDefault(m => m.Key == "A2VisiblePages")?.Value;
List<int> visiblePages = !string.IsNullOrEmpty(visiblePagesString) ? visiblePagesString.Split(';').Select(int.Parse).ToList() : null;

PrintViewXslBEList xsls = [];
int lformid = int.Parse(xmlElement.Metadata.First(m => m.Key == "lformid").Value);
int pageNumber = 1;
foreach (var xsl in await _a2Repository.GetXsls(org, app, lformid, language))
foreach (var xsl in await _a2Repository.GetXsls(org, app, lformid, language, viewType))
{
if (visiblePages == null || visiblePages.Contains(pageNumber))
{
Expand Down
50 changes: 33 additions & 17 deletions src/Storage/Controllers/MigrationController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@

using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Microsoft.Extensions.Primitives;
using Microsoft.Net.Http.Headers;

namespace Altinn.Platform.Storage.Controllers
Expand Down Expand Up @@ -98,7 +97,7 @@ public async Task<ActionResult<Instance>> CreateInstance([FromBody] Instance ins
{
//// TODO Open issue: what about createdby and lastchangedby?

Instance storedInstance = null;
Instance storedInstance;
try
{
int a2ArchiveReference = int.Parse(instance.DataValues["A2ArchRef"]);
Expand All @@ -124,7 +123,8 @@ public async Task<ActionResult<Instance>> CreateInstance([FromBody] Instance ins
/// Inserts new data element
/// </summary>
/// <param name="instanceGuid">The instanceGuid.</param>
/// <param name="timestampTicks">Element timestamp ticks</param>
/// <param name="createdTicks">Element created timestamp ticks</param>
/// <param name="changedTicks">Element last changed timestamp ticks</param>
/// <param name="dataType">Element data type</param>
/// <param name="formid">A2 form id</param>
/// <param name="lformid">A2 logical form id</param>
Expand All @@ -141,14 +141,16 @@ public async Task<ActionResult<Instance>> CreateInstance([FromBody] Instance ins
[DisableRequestSizeLimit]
public async Task<ActionResult<DataElement>> CreateDataElement(
[FromRoute]Guid instanceGuid,
[FromQuery(Name = "timestampticks")]long timestampTicks,
[FromQuery(Name = "createdticks")]long createdTicks,
[FromQuery(Name = "changedticks")]long changedTicks,
[FromQuery(Name = "datatype")]string dataType,
[FromQuery(Name = "formid")]string formid,
[FromQuery(Name = "lformid")]string lformid,
[FromQuery(Name = "prestext")]string presenationText,
[FromQuery(Name = "vispages")]string visiblePages)
{
DateTime timestamp = new DateTime(timestampTicks, DateTimeKind.Utc).ToLocalTime();
DateTime created = new DateTime(createdTicks, DateTimeKind.Utc).ToLocalTime();
DateTime lastChanged = new DateTime(changedTicks, DateTimeKind.Utc).ToLocalTime();

// TODO Open issue: what about createdby and lastchangedby? Ref. instance

Check warning on line 155 in src/Storage/Controllers/MigrationController.cs

View workflow job for this annotation

GitHub Actions / Analyze (csharp)

Single-line comments should not be followed by blank line (https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1512.md)

Check warning on line 155 in src/Storage/Controllers/MigrationController.cs

View workflow job for this annotation

GitHub Actions / Analyze (csharp)

Single-line comments should not be followed by blank line (https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1512.md)

Expand All @@ -165,12 +167,12 @@ public async Task<ActionResult<DataElement>> CreateDataElement(
DataElement dataElement = new()
{
Id = dataElementId,
Created = timestamp,
Created = created,
CreatedBy = instance.CreatedBy,
DataType = dataType,
InstanceGuid = instanceGuid.ToString(),
IsRead = true,
LastChanged = timestamp,
LastChanged = lastChanged,
LastChangedBy = instance.LastChangedBy, // TODO: Find out what to populate here
BlobStoragePath = DataElementHelper.DataFileName(instance.AppId, instanceGuid.ToString(), dataElementId),
Metadata = formid == null ? null : new()
Expand Down Expand Up @@ -203,6 +205,7 @@ public async Task<ActionResult<DataElement>> CreateDataElement(
"signature-presentation" => "ondemand/signature",
"ref-data-as-pdf" => "ondemand/formdatapdf",
"ref-data-as-html" => "ondemand/formdatahtml",
"ref-summary-data-as-html" => "ondemand/formsummaryhtml",
"payment-presentation" => "ondemand/payment",
_ => throw new ArgumentException(dataElement.DataType),
};
Expand Down Expand Up @@ -303,20 +306,32 @@ public async Task<ActionResult<Instance>> CreateText([FromRoute] string org, [Fr
{
try
{
// There is allways an existing text from the app migration
TextResource textResource = await _textRepository.Get(org, app, language);
using var reader = new StreamReader(Request.Body);
var resource = textResource.Resources.Find(resource => resource.Id == key);
if (resource == null)
if (textResource == null)
{
textResource.Resources.Add(new() { Id = key, Value = await reader.ReadToEndAsync() });
textResource = await _textRepository.Create(org, app, new TextResource()
{
Id = (await _applicationRepository.FindOne($"{org}/{app}", org)).Id,
Language = language,
Org = org,
Resources = [new TextResourceElement() { Id = key, Value = await reader.ReadToEndAsync() }]
});
}
else
{
resource.Value = await reader.ReadToEndAsync();
}
var resource = textResource.Resources.Find(resource => resource.Id == key);
if (resource == null)
{
textResource.Resources.Add(new() { Id = key, Value = await reader.ReadToEndAsync() });
}
else
{
resource.Value = await reader.ReadToEndAsync();
}

textResource = await _textRepository.Update(org, app, textResource);
textResource = await _textRepository.Update(org, app, textResource);
}

return Created((string)null, textResource);
}
Expand Down Expand Up @@ -396,16 +411,17 @@ public async Task<ActionResult> CreateImage()
/// <param name="lformid">A2 logical form id</param>
/// <param name="pagenumber">Page number</param>
/// <param name="language">Language</param>
/// <param name="xsltype">Xsl type</param>
/// <returns>Ok</returns>
[AllowAnonymous]
[HttpPost("xsl/{org}/{app}/{lformid}/{pagenumber}/{language}")]
[HttpPost("xsl/{org}/{app}/{lformid}/{pagenumber}/{language}/{xsltype}")]
[DisableFormValueModelBinding]
[ProducesResponseType(StatusCodes.Status201Created)]
[Produces("application/json")]
public async Task<ActionResult> CreateXsl([FromRoute] string org, [FromRoute] string app, [FromRoute] int lformid, [FromRoute] int pagenumber, [FromRoute] string language)
public async Task<ActionResult> CreateXsl([FromRoute] string org, [FromRoute] string app, [FromRoute] int lformid, [FromRoute] int pagenumber, [FromRoute] string language, [FromRoute] int xsltype)
{
using var reader = new StreamReader(Request.Body);
await _a2Repository.CreateXsl(org, app, lformid, language, pagenumber, await reader.ReadToEndAsync());
await _a2Repository.CreateXsl(org, app, lformid, language, pagenumber, await reader.ReadToEndAsync(), xsltype);
return Created();
}

Expand Down
16 changes: 8 additions & 8 deletions src/Storage/Migration/FunctionsAndProcedures/inserta2xsl.sql
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
CREATE OR REPLACE PROCEDURE storage.inserta2xsl (_org TEXT, _app TEXT, _lformid INT, _language TEXT, _pagenumber INT, _xsl TEXT)
CREATE OR REPLACE PROCEDURE storage.inserta2xsl (_org TEXT, _app TEXT, _lformid INT, _language TEXT, _pagenumber INT, _xsl TEXT, _xsltype INT)
LANGUAGE 'plpgsql'
AS $BODY$
DECLARE
Expand All @@ -7,16 +7,16 @@ DECLARE
_applicationinternalid INTEGER;
BEGIN
SELECT id into _applicationinternalid FROM storage.applications WHERE org = _org AND app = _app;
SELECT id into _parentId FROM storage.a2xsls WHERE org = _org AND app = _app AND xsl = _xsl;
SELECT id into _parentId FROM storage.a2xsls WHERE org = _org AND app = _app AND xsl = _xsl AND xsltype = _xsltype;
SELECT id into _appId FROM storage.applications WHERE org = _org AND app = _app;
IF _parentId IS NOT NULL THEN
INSERT INTO storage.a2xsls (org, app, applicationinternalid, parentid, lformid, language, pagenumber, xsl) VALUES
(_org, _app, _applicationinternalid, _parentId, _lformid, _language, _pagenumber, NULL)
ON CONFLICT (app, org, lformid, pagenumber, language) DO NOTHING;
INSERT INTO storage.a2xsls (org, app, applicationinternalid, parentid, lformid, language, pagenumber, xsl, xsltype) VALUES
(_org, _app, _applicationinternalid, _parentId, _lformid, _language, _pagenumber, NULL, _xsltype)
ON CONFLICT (app, org, lformid, pagenumber, language, xsltype) DO NOTHING;
ELSE
INSERT INTO storage.a2xsls (org, app, applicationinternalid, parentid, lformid, language, pagenumber, xsl) VALUES
(_org, _app, _applicationinternalid, NULL, _lformid, _language, _pagenumber, _xsl)
ON CONFLICT (app, org, lformid, pagenumber, language) DO UPDATE SET xsl = _xsl;
INSERT INTO storage.a2xsls (org, app, applicationinternalid, parentid, lformid, language, pagenumber, xsl, xsltype) VALUES
(_org, _app, _applicationinternalid, NULL, _lformid, _language, _pagenumber, _xsl, _xsltype)
ON CONFLICT (app, org, lformid, pagenumber, language, xsltype) DO UPDATE SET xsl = _xsl;
END IF;
END;
$BODY$;
4 changes: 2 additions & 2 deletions src/Storage/Migration/FunctionsAndProcedures/reada2xsls.sql
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
CREATE OR REPLACE FUNCTION storage.reada2xsls(_org TEXT, _app TEXT, _lformid INT, _language TEXT)
CREATE OR REPLACE FUNCTION storage.reada2xsls(_org TEXT, _app TEXT, _lformid INT, _language TEXT, _xsltype INT)
RETURNS TABLE (xsl TEXT)
LANGUAGE 'plpgsql'

Expand All @@ -11,7 +11,7 @@ RETURN QUERY
ELSE (SELECT p.xsl FROM storage.a2xsls p WHERE p.id = x.parentid)
END
FROM storage.a2xsls x
WHERE x.org = _org and x.app = _app and x.lformid = _lformid and x.language = _language
WHERE x.org = _org and x.app = _app and x.lformid = _lformid and x.language = _language and x.xsltype = _xsltype
ORDER BY pagenumber;

END;
Expand Down
3 changes: 3 additions & 0 deletions src/Storage/Migration/v0.11/01-setup-tables.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
ALTER TABLE storage.a2xsls ADD COLUMN IF NOT EXISTS xsltype INT NOT NULL DEFAULT -1;
ALTER TABLE storage.a2xsls DROP CONSTRAINT a2xslsalternateid;
ALTER TABLE storage.a2xsls ADD CONSTRAINT a2xslsalternateid UNIQUE (app, org, lformid, pagenumber, language, xsltype);
7 changes: 2 additions & 5 deletions src/Storage/Repository/IA2Repository.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;

using Altinn.Platform.Storage.Interface.Models;

namespace Altinn.Platform.Storage.Repository
{
/// <summary>
Expand All @@ -15,12 +12,12 @@ public interface IA2Repository
/// Get the stylesheets for a data element (a2 sub/main form)
/// </summary>
/// <returns>A list of stylesheets</returns>
Task<List<string>> GetXsls(string org, string app, int lformId, string language);
Task<List<string>> GetXsls(string org, string app, int lformId, string language, int xslType);

/// <summary>
/// Insert a stylesheet for a data element (a2 sub/main form page)
/// </summary>
Task CreateXsl(string org, string app, int lformId, string language, int pageNumber, string xsl);
Task CreateXsl(string org, string app, int lformId, string language, int pageNumber, string xsl, int xslType);

/// <summary>
/// Insert an a2 codelist
Expand Down
10 changes: 6 additions & 4 deletions src/Storage/Repository/PgA2Repository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ namespace Altinn.Platform.Storage.Repository
/// </summary>
public class PgA2Repository : IA2Repository
{
private static readonly string _readXslSql = "select * from storage.reada2xsls (@_org, @_app, @_lformid, @_language)";
private static readonly string _insertXslSql = "call storage.inserta2xsl (@_org, @_app, @_lformid, @_language, @_pagenumber, @_xsl)";
private static readonly string _readXslSql = "select * from storage.reada2xsls (@_org, @_app, @_lformid, @_language, @_xsltype)";
private static readonly string _insertXslSql = "call storage.inserta2xsl (@_org, @_app, @_lformid, @_language, @_pagenumber, @_xsl, @_xsltype)";
private static readonly string _insertCodelistSql = "call storage.inserta2codelist (@_name, @_language, @_version, @_codelist)";
private static readonly string _insertImageSql = "call storage.inserta2image (@_name, @_image)";
private static readonly string _readCodelistSql = "select * from storage.reada2codelist (@_name, @_language)";
Expand Down Expand Up @@ -53,7 +53,7 @@ public PgA2Repository(
}

/// <inheritdoc/>
public async Task CreateXsl(string org, string app, int lformId, string language, int pageNumber, string xsl)
public async Task CreateXsl(string org, string app, int lformId, string language, int pageNumber, string xsl, int xslType)
{
await using NpgsqlCommand pgcom = _dataSource.CreateCommand(_insertXslSql);
pgcom.Parameters.AddWithValue("_org", NpgsqlDbType.Text, org);
Expand All @@ -62,6 +62,7 @@ public async Task CreateXsl(string org, string app, int lformId, string language
pgcom.Parameters.AddWithValue("_language", NpgsqlDbType.Text, language);
pgcom.Parameters.AddWithValue("_pagenumber", NpgsqlDbType.Integer, pageNumber);
pgcom.Parameters.AddWithValue("_xsl", NpgsqlDbType.Text, xsl);
pgcom.Parameters.AddWithValue("_xsltype", NpgsqlDbType.Integer, xslType);
using TelemetryTracker tracker = new(_telemetryClient, pgcom);

await pgcom.ExecuteNonQueryAsync();
Expand Down Expand Up @@ -98,7 +99,7 @@ public async Task CreateImage(string name, byte[] image)
}

/// <inheritdoc/>
public async Task<List<string>> GetXsls(string org, string app, int lformId, string language)
public async Task<List<string>> GetXsls(string org, string app, int lformId, string language, int xslType)
{
List<string> xsls = [];

Expand All @@ -107,6 +108,7 @@ public async Task<List<string>> GetXsls(string org, string app, int lformId, str
pgcom.Parameters.AddWithValue("_app", NpgsqlDbType.Text, app);
pgcom.Parameters.AddWithValue("_lformid", NpgsqlDbType.Integer, lformId);
pgcom.Parameters.AddWithValue("_language", NpgsqlDbType.Text, language);
pgcom.Parameters.AddWithValue("_xsltype", NpgsqlDbType.Integer, xslType);
using TelemetryTracker tracker = new(_telemetryClient, pgcom);

await using NpgsqlDataReader reader = await pgcom.ExecuteReaderAsync();
Expand Down
7 changes: 0 additions & 7 deletions src/Storage/Repository/PgApplicationRepository.cs
Original file line number Diff line number Diff line change
@@ -1,19 +1,12 @@
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using System.Drawing;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Altinn.Platform.Storage.Configuration;
using Altinn.Platform.Storage.Interface.Models;
using Microsoft.ApplicationInsights;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Npgsql;
using NpgsqlTypes;
Expand Down
Loading

0 comments on commit f9b9acf

Please sign in to comment.