Skip to content

Commit

Permalink
Merge pull request #66 from Worth-NL/Fix/DecisionScenario_Personaliza…
Browse files Browse the repository at this point in the history
…tion_ReplaceProperties

Fix/decision scenario personalization replace properties
  • Loading branch information
Thomas-M-Krystyan authored Sep 13, 2024
2 parents 25e66d4 + 718d6f9 commit b6b9d75
Show file tree
Hide file tree
Showing 24 changed files with 644 additions and 362 deletions.
14 changes: 14 additions & 0 deletions EventsHandler/Api/EventsHandler/Extensions/StringExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -85,5 +85,19 @@ internal static TData ChangeType<TData>(this string originalTextValue)
// Retrieve as TData => int, ushort, bool
return (TData)Convert.ChangeType(originalTextValue, typeof(TData));
}

private const string CommaSeparator = ", ";

/// <summary>
/// Joins the specified collection into a comma-separated <see langword="string"/>.
/// </summary>
/// <param name="collection">The collection to be parsed.</param>
/// <returns>
/// A comma-separated string
/// </returns>
internal static string Join(this IEnumerable<string> collection)
{
return string.Join(CommaSeparator, collection);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,22 +38,13 @@ public struct DecisionType : IJsonSerializable
[JsonPropertyOrder(2)]
public string Category { get; internal set; } = string.Empty;

/// <summary>
/// The deadline date to respond for this <see cref="DecisionType"/>.
/// </summary>
[JsonRequired]
[JsonInclude]
[JsonPropertyName("reactietermijn")]
[JsonPropertyOrder(3)]
public DateOnly ResponseDeadline { get; internal set; }

/// <summary>
/// The indication of the publication.
/// </summary>
[JsonRequired]
[JsonInclude]
[JsonPropertyName("publicatieIndicatie")]
[JsonPropertyOrder(4)]
[JsonPropertyOrder(3)]
public bool PublicationIndicator { get; internal set; }

/// <summary>
Expand All @@ -62,25 +53,16 @@ public struct DecisionType : IJsonSerializable
[JsonRequired]
[JsonInclude]
[JsonPropertyName("publicatietekst")]
[JsonPropertyOrder(5)]
[JsonPropertyOrder(4)]
public string PublicationText { get; internal set; } = string.Empty;

/// <summary>
/// The deadline date of the publication.
/// </summary>
[JsonRequired]
[JsonInclude]
[JsonPropertyName("publicatietermijn")]
[JsonPropertyOrder(6)]
public DateOnly PublicationDeadline { get; internal set; }

/// <summary>
/// The explanation of the <see cref="DecisionType"/>.
/// </summary>
[JsonRequired]
[JsonInclude]
[JsonPropertyName("toelichting")]
[JsonPropertyOrder(7)]
[JsonPropertyOrder(5)]
public string Explanation { get; internal set; } = string.Empty;

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,9 @@ public struct Documents : IJsonSerializable
/// The collection of:
/// <inheritdoc cref="Document"/>
/// </summary>
[JsonRequired]
[JsonInclude]
// This property is unnamed in the resulting JSON
[JsonPropertyName("results")] // This JSON property is not present in the payload and needs to be handled by custom Documents JSON converter
[JsonPropertyOrder(0)]
public List<Document> Results { get; internal set; } = new();

Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion EventsHandler/Api/EventsHandler/Properties/Resources.resx
Original file line number Diff line number Diff line change
Expand Up @@ -393,7 +393,7 @@
<value>HTTP Request: The main object could not be retrieved from OpenZaak Web API service.</value>
</data>
<data name="Processing_ABORT_DoNotSendNotification_CaseTypeIdWhitelist" xml:space="preserve">
<value>The notification can not be sent because the case type with identification {0} is not included in the {1}.</value>
<value>The notification can not be sent because the case type with identification '{0}' is not included in the {1}.</value>
<comment>{0} = Case Type ID, {1} = Name of the environment variable holding this value</comment>
</data>
<data name="Configuration_ERROR_VersionObjectenUnknown" xml:space="preserve">
Expand Down
14 changes: 7 additions & 7 deletions EventsHandler/Api/EventsHandler/Properties/launchSettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -61,24 +61,24 @@
"USER_TEMPLATEIDS_EMAIL_ZAAKUPDATE": "c71bb006-f131-465c-bac2-fb44c398c4cd",
"USER_TEMPLATEIDS_EMAIL_ZAAKCLOSE": "f1c5af4f-9145-4049-836e-09edff8eb01d",
"USER_TEMPLATEIDS_EMAIL_TASKASSIGNED": "50ed4ca5-8638-4ad3-b774-884d0944c382",
// NOTE: "DecisionMade" scenario is not sending notifications; it doesn't have a dedicatged template IDs
"USER_TEMPLATEIDS_EMAIL_DECISIONMADE": "3d1b5c2e-f6f0-4de7-ade8-1b21d49a74c1",
"USER_TEMPLATEIDS_EMAIL_MESSAGERECEIVED": "0354a750-d1b1-4bff-b359-1b22a698b3f6",

"USER_TEMPLATEIDS_SMS_ZAAKCREATE": "46c8fe56-e1cd-467c-b762-29af892237f6",
"USER_TEMPLATEIDS_SMS_ZAAKUPDATE": "5af94a07-2bff-4546-9439-aa2018b7a4d3",
"USER_TEMPLATEIDS_SMS_ZAAKCLOSE": "771e7561-a059-4888-acc3-3a3fbcd5c6e3",
"USER_TEMPLATEIDS_SMS_TASKASSIGNED": "6354b855-83c7-4cda-aa33-9a6a8f52eebe",
// NOTE: "DecisionMade" scenario is not sending notifications; it doesn't have a dedicatged template IDs
"USER_TEMPLATEIDS_SMS_DECISIONMADE": "f00700c2-8c7a-4deb-b716-bb035ad2e3d0",
"USER_TEMPLATEIDS_SMS_MESSAGERECEIVED": "b5963a58-6f99-43ef-a2cd-148e9c6b9a54",

"USER_WHITELIST_ZAAKCREATE_IDS": "",
"USER_WHITELIST_ZAAKUPDATE_IDS": "",
"USER_WHITELIST_ZAAKCLOSE_IDS": "",
"USER_WHITELIST_TASKASSIGNED_IDS": "",
"USER_WHITELIST_DECISIONMADE_IDS": "",
"USER_WHITELIST_DECISIONMADE_IDS": "whitelisted",
"USER_WHITELIST_MESSAGE_ALLOWED": "false",
"USER_WHITELIST_TASKOBJECTTYPE_UUID": "0236e468-2ad8-43d6-a723-219cb22acb37",
"USER_WHITELIST_MESSAGEOBJECTTYPE_UUIDS": "38327774-7023-4f25-9386-acb0c6f10636, 6468cfd4-d827-473a-8f24-114af046ce7f",
"USER_WHITELIST_MESSAGEOBJECTTYPE_UUIDS": "f482b7a3-22b7-40e2-a187-52f737d4ef44",

"SENTRY_DSN": "https://1db70f552fb2bdcab8571661a3db6d70@o4507152178741248.ingest.de.sentry.io/4507152289431632",
"SENTRY_ENVIRONMENT": "Worth Production | Workflow v1"
Expand Down Expand Up @@ -117,22 +117,22 @@

"USER_DOMAIN_OPENNOTIFICATIES": "opennotificaties.test.notifynl.nl",
"USER_DOMAIN_OPENZAAK": "openzaak.test.notifynl.nl",
"USER_DOMAIN_OPENKLANT": "localhost:8000", // NOTE: Requires running OpenKlant 2.0 container in Docker
"USER_DOMAIN_OPENKLANT": "openklantv2.test.notifynl.nl",
"USER_DOMAIN_OBJECTEN": "objecten.test.notifynl.nl",
"USER_DOMAIN_OBJECTTYPEN": "objecttypen.test.notifynl.nl",

"USER_TEMPLATEIDS_EMAIL_ZAAKCREATE": "3b58f871-93cb-49e0-bb98-acc9ab1a4876",
"USER_TEMPLATEIDS_EMAIL_ZAAKUPDATE": "c71bb006-f131-465c-bac2-fb44c398c4cd",
"USER_TEMPLATEIDS_EMAIL_ZAAKCLOSE": "f1c5af4f-9145-4049-836e-09edff8eb01d",
"USER_TEMPLATEIDS_EMAIL_TASKASSIGNED": "50ed4ca5-8638-4ad3-b774-884d0944c382",
// NOTE: "DecisionMade" scenario is not sending notifications; it doesn't have a dedicatged template IDs
"USER_TEMPLATEIDS_EMAIL_DECISIONMADE": "3d1b5c2e-f6f0-4de7-ade8-1b21d49a74c1",
"USER_TEMPLATEIDS_EMAIL_MESSAGERECEIVED": "0354a750-d1b1-4bff-b359-1b22a698b3f6",

"USER_TEMPLATEIDS_SMS_ZAAKCREATE": "46c8fe56-e1cd-467c-b762-29af892237f6",
"USER_TEMPLATEIDS_SMS_ZAAKUPDATE": "5af94a07-2bff-4546-9439-aa2018b7a4d3",
"USER_TEMPLATEIDS_SMS_ZAAKCLOSE": "771e7561-a059-4888-acc3-3a3fbcd5c6e3",
"USER_TEMPLATEIDS_SMS_TASKASSIGNED": "6354b855-83c7-4cda-aa33-9a6a8f52eebe",
// NOTE: "DecisionMade" scenario is not sending notifications; it doesn't have a dedicatged template IDs
"USER_TEMPLATEIDS_SMS_DECISIONMADE": "f00700c2-8c7a-4deb-b716-bb035ad2e3d0",
"USER_TEMPLATEIDS_SMS_MESSAGERECEIVED": "b5963a58-6f99-43ef-a2cd-148e9c6b9a54",

"USER_WHITELIST_ZAAKCREATE_IDS": "",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
using EventsHandler.Services.DataSending.Responses;
using EventsHandler.Services.Settings.Configuration;
using System.Text.Json;
using System.Text.RegularExpressions;
using Resources = EventsHandler.Properties.Resources;

namespace EventsHandler.Services.DataProcessing.Strategy.Implementations
Expand All @@ -27,10 +28,11 @@ namespace EventsHandler.Services.DataProcessing.Strategy.Implementations
/// The strategy for "Decision made" scenario.
/// </summary>
/// <seealso cref="BaseScenario"/>
internal sealed class DecisionMadeScenario : BaseScenario
internal sealed partial class DecisionMadeScenario : BaseScenario // The keyword "partial" added to allow using [GeneratedRegex] attribute
{
private IQueryContext _queryContext = null!;
private DecisionResource _decisionResource;
private Guid _messageObjectTypeGuid;
private Decision _decision;
private CaseType _caseType;
private string _bsnNumber = string.Empty;
Expand All @@ -57,7 +59,8 @@ protected override async Task<CommonPartyData> PrepareDataAsync(NotificationEven
InfoObject infoObject = await this._queryContext.GetInfoObjectAsync(this._decisionResource);

// Validation #1: The message needs to be of a specific type
if (!this.Configuration.User.Whitelist.MessageObjectType_Uuids().Contains(infoObject.TypeUri.GetGuid()))
if (!this.Configuration.User.Whitelist.MessageObjectType_Uuids()
.Contains(this._messageObjectTypeGuid = infoObject.TypeUri.GetGuid()))
{
throw new AbortedNotifyingException(
string.Format(Resources.Processing_ABORT_DoNotSendNotification_MessageType,
Expand All @@ -71,7 +74,7 @@ protected override async Task<CommonPartyData> PrepareDataAsync(NotificationEven
}

// Validation #3: Confidentiality needs to be acceptable
if (infoObject.Confidentiality != PrivacyNotices.NonConfidential) // TODO: First version would only check confidential status (why array?)
if (infoObject.Confidentiality != PrivacyNotices.NonConfidential)
{
throw new AbortedNotifyingException(
string.Format(Resources.Processing_ABORT_DoNotSendNotification_DecisionConfidentiality,
Expand Down Expand Up @@ -102,7 +105,7 @@ await this._queryContext.GetCaseStatusesAsync( // 2. Case statuses
#region Polymorphic (Email logic: template + personalization)
/// <inheritdoc cref="BaseScenario.GetEmailTemplateId()"/>
protected override Guid GetEmailTemplateId()
=> Guid.Empty; // NOTE: This scenario is not sending notifications
=> this.Configuration.User.TemplateIds.Email.DecisionMade();

private static readonly object s_padlock = new();
private static readonly Dictionary<string, object> s_emailPersonalization = new(); // Cached dictionary no need to be initialized every time
Expand Down Expand Up @@ -131,20 +134,18 @@ protected override async Task<Dictionary<string, object>> GetEmailPersonalizatio
s_emailPersonalization["besluit.uiterlijkereactiedatum"] = $"{this._decision.ResponseDate}";

s_emailPersonalization["besluittype.omschrijving"] = decisionType.Name;
s_emailPersonalization["besluittype.omschrijvinggeneriek"] = decisionType.Description;
s_emailPersonalization["besluittype.omschrijvingGeneriek"] = decisionType.Description;
s_emailPersonalization["besluittype.besluitcategorie"] = decisionType.Category;
s_emailPersonalization["besluittype.reactietermijn"] = $"{decisionType.ResponseDeadline}";
s_emailPersonalization["besluittype.publicatieindicatie"] = decisionType.PublicationIndicator;
s_emailPersonalization["besluittype.publicatietekst"] = decisionType.PublicationText;
s_emailPersonalization["besluittype.publicatietermijn"] = $"{decisionType.PublicationDeadline}";
s_emailPersonalization["besluittype.toelichting"] = decisionType.Explanation;

s_emailPersonalization["zaak.identificatie"] = @case.Identification;
s_emailPersonalization["zaak.omschrijving"] = @case.Name;
s_emailPersonalization["zaak.registratiedatum"] = $"{@case.RegistrationDate}";

s_emailPersonalization["zaaktype.omschrijving"] = this._caseType.Name;
s_emailPersonalization["zaaktype.omschrijvinggeneriek"] = this._caseType.Description;
s_emailPersonalization["zaaktype.omschrijvingGeneriek"] = this._caseType.Description;

return s_emailPersonalization;
}
Expand All @@ -154,7 +155,7 @@ protected override async Task<Dictionary<string, object>> GetEmailPersonalizatio
#region Polymorphic (SMS logic: template + personalization)
/// <inheritdoc cref="BaseScenario.GetSmsTemplateId()"/>
protected override Guid GetSmsTemplateId()
=> Guid.Empty; // NOTE: This scenario is not sending notifications
=> this.Configuration.User.TemplateIds.Sms.DecisionMade();

/// <inheritdoc cref="BaseScenario.GetSmsPersonalizationAsync(CommonPartyData)"/>
protected override async Task<Dictionary<string, object>> GetSmsPersonalizationAsync(CommonPartyData partyData)
Expand All @@ -164,6 +165,11 @@ protected override async Task<Dictionary<string, object>> GetSmsPersonalizationA
#endregion

#region Polymorphic (ProcessDataAsync)
[GeneratedRegex("(\\n\\n)|(\\n)", RegexOptions.Compiled)]
private static partial Regex NewlinesCharsRegexPattern();

private const string LogiusNewlines = "\\r\\n";

/// <inheritdoc cref="BaseScenario.ProcessDataAsync(NotificationEvent, IReadOnlyCollection{NotifyData})"/>
protected override async Task<ProcessingDataResponse> ProcessDataAsync(NotificationEvent notification, IReadOnlyCollection<NotifyData> notifyData)
{
Expand All @@ -182,7 +188,7 @@ protected override async Task<ProcessingDataResponse> ProcessDataAsync(Notificat
}

// Adjusting the body for Logius system
string modifiedResponseBody = templateResponse.Body.Replace("\n\n", "\r\n");
string modifiedResponseBody = NewlinesCharsRegexPattern().Replace(templateResponse.Body, LogiusNewlines);

// Prepare HTTP Request Body
this._queryContext = this.DataQuery.From(notification);
Expand All @@ -193,9 +199,9 @@ protected override async Task<ProcessingDataResponse> ProcessDataAsync(Notificat
return ProcessingDataResponse.Failure(Resources.Processing_ERROR_Scenario_MissingInfoObjectsURIs);
}

string objectDataJson = PrepareObjectData(templateResponse.Subject, modifiedResponseBody, commaSeparatedUris);

RequestResponse requestResponse = await this._queryContext.CreateMessageObjectAsync(objectDataJson);
RequestResponse requestResponse = await this._queryContext.CreateMessageObjectAsync(
this._messageObjectTypeGuid,
dataJson: PrepareObjectData(templateResponse.Subject, modifiedResponseBody, commaSeparatedUris));

return requestResponse.IsFailure
? ProcessingDataResponse.Failure(requestResponse.JsonResponse)
Expand Down Expand Up @@ -228,8 +234,8 @@ private async Task<string> GetValidInfoObjectUrisAsync(IQueryContext queryContex
InfoObject infoObject = await queryContext.GetInfoObjectAsync(document);

// Filter out info objects not meeting the specified criteria
if (infoObject.Status != MessageStatus.Definitive &&
infoObject.Confidentiality != PrivacyNotices.NonConfidential) // TODO: First version would only check confidential status (why array?)
if (infoObject.Confidentiality != PrivacyNotices.NonConfidential &&
infoObject.Status != MessageStatus.Definitive)
{
continue;
}
Expand All @@ -238,7 +244,7 @@ private async Task<string> GetValidInfoObjectUrisAsync(IQueryContext queryContex
validInfoObjectsUris.Add($"\"{document.InfoObjectUri}\"");
}

return string.Join(", ", validInfoObjectsUris);
return validInfoObjectsUris.Join();
}

/// <summary>
Expand All @@ -248,20 +254,18 @@ private async Task<string> GetValidInfoObjectUrisAsync(IQueryContext queryContex
private string PrepareObjectData(string subject, string body, string commaSeparatedUris)
{
return $"{{" +
$" \"onderwerp\": \"{subject}\"," +
$" \"berichttekst\": \"{body}\"," +
$" \"publicatiedatum\": \"{this._decision.PublicationDate}\"," +
$" \"referentie\": \"{this._decisionResource.DecisionUri}\"," +
$" \"handelingsperspectief\": \"{string.Empty}\"," + // TODO: To be filled
$" \"geopend\": false," +
$" \"berichttype\": \"{this.Configuration.AppSettings.Variables.Objecten.MessageObjectType_Name()}\"," +
$" \"identificatie\": {{" +
$" \"type\": \"bsn\"," +
$" \"value\": \"{this._bsnNumber}\"" +
$" }}," +
$" \"bijlages\": [" +
$" {commaSeparatedUris}" +
$" ]" +
$"\"onderwerp\":\"{subject}\"," +
$"\"berichttekst\":\"{body}\"," +
$"\"publicatiedatum\":\"{this._decision.PublicationDate}\"," +
$"\"referentie\":\"{this._decisionResource.DecisionUri}\"," +
$"\"handelingsperspectief\":\"{string.Empty}\"," + // TODO: To be filled
$"\"geopend\":false," +
$"\"berichttype\":\"{this.Configuration.AppSettings.Variables.Objecten.MessageObjectType_Name()}\"," +
$"\"identificatie\":{{" +
$"\"type\":\"bsn\"," +
$"\"value\":\"{this._bsnNumber}\"" +
$"}}," +
$"\"bijlages\":[{commaSeparatedUris}]" +
$"}}";
}
#endregion
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -158,11 +158,9 @@ internal interface IQueryContext

/// <inheritdoc cref="IQueryObjecten.GetMessageAsync(IQueryBase)"/>
internal Task<MessageObject> GetMessageAsync();
#endregion

#region IObjectTypen
/// <inheritdoc cref="IQueryObjectTypen.CreateMessageObjectAsync(IHttpNetworkService, string)"/>
internal Task<RequestResponse> CreateMessageObjectAsync(string objectDataJson);
/// <inheritdoc cref="IQueryObjecten.CreateMessageObjectAsync(IHttpNetworkService, Guid, string)"/>
internal Task<RequestResponse> CreateMessageObjectAsync(Guid messageObjectTypeGuid, string dataJson);
#endregion
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -151,12 +151,10 @@ Task<TaskObject> IQueryContext.GetTaskAsync()
/// <inheritdoc cref="IQueryContext.GetMessageAsync()"/>
Task<MessageObject> IQueryContext.GetMessageAsync()
=> this._queryObjecten.GetMessageAsync(this._queryBase);
#endregion

#region IObjectTypen
/// <inheritdoc cref="IQueryContext.CreateMessageObjectAsync(string)"/>
async Task<RequestResponse> IQueryContext.CreateMessageObjectAsync(string objectDataJson)
=> await this._queryObjectTypen.CreateMessageObjectAsync(this._networkService, objectDataJson);
/// <inheritdoc cref="IQueryContext.CreateMessageObjectAsync(Guid, string)"/>
async Task<RequestResponse> IQueryContext.CreateMessageObjectAsync(Guid messageObjectTypeGuid, string dataJson)
=> await this._queryObjecten.CreateMessageObjectAsync(this._networkService, messageObjectTypeGuid, dataJson);
#endregion
}
}
Loading

0 comments on commit b6b9d75

Please sign in to comment.