Skip to content

Commit

Permalink
feature/4464-language-support-pdf (#4669)
Browse files Browse the repository at this point in the history
* Added language support for pdf generator

* Lang support

* Code smells

* Close readers on error

* Simplified try/finally to try/with

* Org name by lang

* Code review

* Name logic

* Updated nugets
  • Loading branch information
lorang92 authored Sep 1, 2020
1 parent 4c42ca4 commit 7e87224
Show file tree
Hide file tree
Showing 17 changed files with 198 additions and 41 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
<LangVersion>latest</LangVersion>
<Version>1.1.4-alpha</Version>
<Version>1.1.5-alpha</Version>
<Authors>Altinn</Authors>
<Company>Altinn</Company>
<Description>Package that contains API controllers for the standard API for a Altinn App.</Description>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
<LangVersion>latest</LangVersion>
<Version>1.1.4-alpha</Version>
<Version>1.1.5-alpha</Version>
<Authors>Altinn</Authors>
<Company>Altinn</Company>
<Description>Package with common functionality for Altinn Apps created in Altinn Studio</Description>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
<LangVersion>latest</LangVersion>
<Version>1.1.4-alpha</Version>
<Version>1.1.5-alpha</Version>
<Authors>Altinn</Authors>
<Company>Altinn</Company>
<Description>Common services with Altinn Platform functionality and Altinn Apps functionality</Description>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
using Altinn.App.Services.Configuration;
using Altinn.App.Services.Constants;
using Altinn.App.Services.Helpers;
using Altinn.Platform.Profile.Models;
using Altinn.App.Services.Interface;
using Altinn.App.Services.Models;
using Altinn.Platform.Storage.Interface.Models;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Microsoft.AspNetCore.Http;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Serialization;
Expand All @@ -26,9 +29,11 @@ public class PDFSI : IPDF
private readonly IRegister _registerService;
private readonly IAppResources _appResourcesService;
private readonly IText _textService;
private readonly IProfile _profileService;
private readonly UserHelper _userHelper;
private readonly JsonSerializer _camelCaseSerializer;
private readonly IHttpContextAccessor _httpContextAccessor;
private readonly string pdfElementType = "ref-data-as-pdf";
private readonly string defaultFileName = "kvittering.pdf";

/// <summary>
/// Creates a new instance of the <see cref="PDFSI"/> class
Expand All @@ -40,14 +45,19 @@ public class PDFSI : IPDF
/// <param name="registerService">The register service</param>
/// <param name="appResourcesService">The app resource service</param>
/// <param name="textService">The text service</param>
/// <param name="profileService">the profile service</param>
public PDFSI(IOptions<PlatformSettings> platformSettings,
IOptions<AppSettings> appSettings,
ILogger<PDFSI> logger,
HttpClient httpClient,
IData dataService,
IRegister registerService,
IAppResources appResourcesService,
IText textService)
IText textService,
IProfile profileService,
IOptions<GeneralSettings> settings,
IHttpContextAccessor httpContextAccessor
)
{
_logger = logger;
_dataService = dataService;
Expand All @@ -64,6 +74,9 @@ public PDFSI(IOptions<PlatformSettings> platformSettings,
httpClient.BaseAddress = new Uri(platformSettings.Value.ApiPdfEndpoint);
httpClient.DefaultRequestHeaders.Add(General.SubscriptionKeyHeaderName, platformSettings.Value.SubscriptionKey);
_pdfClient = httpClient;
_profileService = profileService;
_userHelper = new UserHelper(profileService, registerService, settings);
_httpContextAccessor = httpContextAccessor;
}

/// <inheritdoc/>
Expand All @@ -83,8 +96,11 @@ public async Task GenerateAndStoreReceiptPDF(Instance instance)
await dataStream.ReadAsync(dataAsBytes);
string encodedXml = System.Convert.ToBase64String(dataAsBytes);

UserContext userContext = await _userHelper.GetUserContext(_httpContextAccessor.HttpContext);
UserProfile userProfile = await _profileService.GetUserProfile(userContext.UserId);

byte[] formLayout = _appResourcesService.GetAppResource(org, app, _appSettings.FormLayoutJSONFileName);
TextResource textResource = await _textService.GetText(org, app, "nb");
TextResource textResource = await _textService.GetText(org, app, userProfile.ProfileSettingPreference.Language);

string formLayoutString = GetUTF8String(formLayout);
string textResourcesString = JsonConvert.SerializeObject(textResource);
Expand All @@ -95,7 +111,9 @@ public async Task GenerateAndStoreReceiptPDF(Instance instance)
FormLayout = JsonConvert.DeserializeObject(formLayoutString),
TextResources = JsonConvert.DeserializeObject(textResourcesString),
Party = await _registerService.GetParty(instanceOwnerId),
Instance = instance
Instance = instance,
UserProfile = userProfile,
UserParty = userProfile.Party
};

Stream pdfContent;
Expand All @@ -111,7 +129,7 @@ public async Task GenerateAndStoreReceiptPDF(Instance instance)

try
{
await StorePDF(pdfContent, instance, application);
await StorePDF(pdfContent, instance, application, userProfile.ProfileSettingPreference.Language);
}
catch (Exception exception)
{
Expand Down Expand Up @@ -152,28 +170,29 @@ private async Task<Stream> GeneratePDF(PDFContext pdfContext)
return pdfContent;
}

private async Task<DataElement> StorePDF(Stream pdfStream, Instance instance, Application appMetadata)
private async Task<DataElement> StorePDF(Stream pdfStream, Instance instance, Application appMetadata, string language)
{
string fileName = null;
string app = instance.AppId.Split("/")[1];

if (!string.IsNullOrEmpty(appMetadata.Title?["nb"]))
if (!string.IsNullOrEmpty(appMetadata.Title?[language]))
{
fileName = appMetadata.Title["nb"] + ".pdf";
fileName = appMetadata.Title[language] + ".pdf";
}
else
else if (!string.IsNullOrEmpty(appMetadata.Title?["nb"]))
{
fileName = app;
fileName = appMetadata.Title[language] + ".pdf";
} else {
fileName = app + ".pdf";
}

fileName = GetValidFileName(fileName);


return await _dataService.InsertBinaryData(
instance.Id,
pdfElementType,
"application/pdf",
fileName ?? defaultFileName,
fileName,
pdfStream);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Collections;
using Altinn.Platform.Profile.Models;
using Altinn.Platform.Register.Models;
using Altinn.Platform.Storage.Interface.Models;
using Newtonsoft.Json;
Expand Down Expand Up @@ -43,5 +44,11 @@ class PDFContext
/// </summary>
[JsonProperty(PropertyName = "party")]
public Party Party { get; set; }

/// <summary>
/// Gets or sets the user profile
/// </summary>
[JsonProperty(PropertyName = "userProfile")]
public UserProfile UserProfile {get; set; }
}
}
6 changes: 3 additions & 3 deletions src/Altinn.Apps/AppTemplates/AspNet/App/App.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Altinn.App.Api" Version="1.1.4-alpha" />
<PackageReference Include="Altinn.App.Common" Version="1.1.4-alpha" />
<PackageReference Include="Altinn.App.PlatformServices" Version="1.1.4-alpha" />
<PackageReference Include="Altinn.App.Api" Version="1.1.5-alpha" />
<PackageReference Include="Altinn.App.Common" Version="1.1.5-alpha" />
<PackageReference Include="Altinn.App.PlatformServices" Version="1.1.5-alpha" />
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="3.1.7" />
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="3.1.4" />
</ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import altinn.platform.pdf.health.HealthCheckTelemetryFilter;
import altinn.platform.pdf.services.BasicLogger;
import altinn.platform.pdf.utils.AltinnOrgUtils;
import altinn.platform.pdf.utils.TextUtils;
import com.azure.identity.ClientSecretCredential;
import com.azure.identity.ClientSecretCredentialBuilder;
import com.azure.security.keyvault.secrets.SecretClient;
Expand All @@ -30,6 +31,7 @@ public class App {
public static void main(String[] args) {
AltinnOrgUtils.initAltinnOrgsHarvesting();
try {
TextUtils.readLanguageFiles();
connectToKeyVaultAndSetApplicationInsight();
} catch (Exception e) {
BasicLogger.log(Level.SEVERE, e.getMessage());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ public class PdfContext {
@Nullable
private Party userParty;

@ApiModelProperty(notes = "The profile of the active user")
@Nullable
private UserProfile userProfile;

public Party getUserParty() { return userParty; }

public void setUserParty(Party userParty) { this.userParty = userParty; }
Expand All @@ -58,4 +62,14 @@ public class PdfContext {
public Instance getInstance() { return instance; }

public void setInstance(Instance instance) { this.instance = instance; }

@Nullable
public UserProfile getUserProfile() {
return userProfile;
}

public void setUserProfile(@Nullable UserProfile userProfile) {
this.userProfile = userProfile;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package altinn.platform.pdf.models;

public class ProfileSettingPreference {
private String language;

public String getLanguage() {
return language;
}

public void setLanguage(String language) {
this.language = language;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package altinn.platform.pdf.models;

import io.swagger.annotations.ApiModel;

@ApiModel(description = "The profile")
public class UserProfile {
private ProfileSettingPreference profileSettingPreference;

public ProfileSettingPreference getProfileSettingPreference() {
return profileSettingPreference;
}

public void setProfileSettingPreference(ProfileSettingPreference profileSettingPreference) {
this.profileSettingPreference = profileSettingPreference;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ public class PDFGenerator {
private FormLayout formLayout;
private Party party;
private Party userParty;
private UserProfile userProfile;
private PDPage currentPage;
private PDPageContentStream currentContent;
private PDDocumentOutline outline;
Expand All @@ -74,6 +75,7 @@ public PDFGenerator(PdfContext pdfContext) {
this.output = new ByteArrayOutputStream();
this.party = pdfContext.getParty();
this.userParty = pdfContext.getUserParty();
this.userProfile = pdfContext.getUserProfile();
try {
this.formData = FormDataUtils.parseXml(pdfContext.getData());
this.textResources.setResources(parseTextResources(this.textResources.getResources(), this.formData));
Expand All @@ -93,7 +95,7 @@ public ByteArrayOutputStream generatePDF() throws IOException {
info.setCreationDate(Calendar.getInstance());
info.setTitle(InstanceUtils.getInstanceName(instance));
document.setDocumentInformation(info);
pagesOutline.setTitle("Alle sider");
pagesOutline.setTitle(getLanguageString("all_pages"));
outline.addLast(pagesOutline);
PDDocumentCatalog catalog = document.getDocumentCatalog();
catalog.setDocumentOutline((outline));
Expand Down Expand Up @@ -206,7 +208,8 @@ private void renderHeader() throws IOException{
currentContent.beginText();
currentContent.newLineAtOffset(xPoint, yPoint);
currentContent.setFont(fontBold, headerFontSize);
currentContent.showText(AltinnOrgUtils.getOrgFullNameByShortName(instance.getOrg()) + " - " + InstanceUtils.getInstanceName(instance));
String language = (this.userProfile != null) ? userProfile.getProfileSettingPreference().getLanguage() : "nb";
currentContent.showText(AltinnOrgUtils.getOrgFullNameByShortName(instance.getOrg(), language) + " - " + InstanceUtils.getInstanceName(instance));
yPoint -= leading;
currentContent.endText();
yPoint -= textFieldMargin;
Expand All @@ -225,12 +228,13 @@ private void renderSubmittedBy() throws IOException {
currentContent.setFont(font, fontSize);
String submittedBy;
if (party.equals(userParty) || userParty == null) {
submittedBy = "Levert av " + party.getName();
submittedBy = getLanguageString("delivered_by") + " " + party.getName();
} else {
submittedBy = "Levert av " + userParty.getName() + " på vegne av " + party.getName();
submittedBy =
getLanguageString("delivered_by") + " " + userParty.getName() + " " + getLanguageString("on_behalf_of") + " " + party.getName();
}
List<String> lines = TextUtils.splitTextToLines(submittedBy, font, fontSize, width);
lines.add("Referansenummer: " + TextUtils.getInstanceGuid(instance.getId()).split("-")[4]);
lines.add(getLanguageString("") + TextUtils.getInstanceGuid(instance.getId()).split("-")[4]);
for(String line : lines) {
currentContent.showText(line);
currentContent.newLineAtOffset(0, -leading);
Expand All @@ -254,7 +258,7 @@ private void createNewPage() throws IOException {
dest.setPage(currentPage);
PDOutlineItem bookmark = new PDOutlineItem();
bookmark.setDestination(dest);
bookmark.setTitle("Side " + document.getPages().getCount());
bookmark.setTitle(getLanguageString("page") + " " + document.getPages().getCount());
pagesOutline.addLast(bookmark);
currentContent= new PDPageContentStream(document, currentPage);
}
Expand Down Expand Up @@ -321,27 +325,25 @@ private void renderFileUploadContent(FormLayoutElement element) throws IOExcepti
}

private void renderAddressComponent(FormLayoutElement element) throws IOException {
renderText("Gateadresse", font, fontSize, StandardStructureTypes.P);
renderText(getLanguageString("address"), font, fontSize, StandardStructureTypes.P);
renderContent(FormDataUtils.getFormDataByKey(element.getDataModelBindings().get("address"), this.formData));
yPoint -= componentMargin;


renderText("Postnr", font, fontSize, StandardStructureTypes.P);
renderText(getLanguageString("zip_code"), font, fontSize, StandardStructureTypes.P);
renderContent(FormDataUtils.getFormDataByKey(element.getDataModelBindings().get("zipCode"), this.formData));
yPoint -= componentMargin;

renderText("Poststed", font, fontSize, StandardStructureTypes.P);
renderText(getLanguageString("post_place"), font, fontSize, StandardStructureTypes.P);
renderContent(FormDataUtils.getFormDataByKey(element.getDataModelBindings().get("postPlace"), this.formData));
yPoint -= componentMargin;


if (!element.isSimplified()) {
renderText("C/O eller annen tilleggsadresse", font, fontSize, StandardStructureTypes.P);
renderText("Om addressen er felles for flere boenhenter må du oppgi bolignummer. Den består av en bokstav og fire tall og skal være ført opp ved/på inngangsdøren din.", font, fontSize, StandardStructureTypes.P);
renderText(getLanguageString("care_of"), font, fontSize, StandardStructureTypes.P);
renderText(getLanguageString("house_number_helper"), font, fontSize, StandardStructureTypes.P);
renderContent(FormDataUtils.getFormDataByKey(element.getDataModelBindings().get("careOf"), this.formData));
yPoint -= componentMargin;

renderText("Bolignummer", font, fontSize, StandardStructureTypes.P);
renderText(getLanguageString("house_number"), font, fontSize, StandardStructureTypes.P);
renderContent(FormDataUtils.getFormDataByKey(element.getDataModelBindings().get("houseNumber"), this.formData));
yPoint -= componentMargin;
}
Expand Down Expand Up @@ -401,6 +403,11 @@ private String replaceParameters(String nameString, List<String> params){

return nameString;
}

private String getLanguageString(String key) {
String languageCode = (this.userProfile != null) ? this.userProfile.getProfileSettingPreference().getLanguage() : "nb";
return TextUtils.getLanguageStringByKey(key, languageCode);
}
}


Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,10 @@ public class AltinnOrgUtils {
/**
* Gets the org full name by their short name
* @param shortName the short org name
* @param language the language to fetch
* @return the long org name
*/
public static String getOrgFullNameByShortName(String shortName) {
public static String getOrgFullNameByShortName(String shortName, String language) {
if (altinnOrgs == null || altinnOrgs.getOrgs() == null) {
return "";
}
Expand All @@ -32,8 +33,7 @@ public static String getOrgFullNameByShortName(String shortName) {
return "";
}

// TODO: Fetch language by user preference => post mvp
return org.getName().get("nb");
return org.getName().get(language);
}

/**
Expand Down
Loading

0 comments on commit 7e87224

Please sign in to comment.