Skip to content
This repository has been archived by the owner on Apr 26, 2024. It is now read-only.

Commit

Permalink
Transfer project
Browse files Browse the repository at this point in the history
  • Loading branch information
Yannick Börner committed Mar 24, 2021
1 parent 63929b5 commit 8cdbe23
Show file tree
Hide file tree
Showing 13 changed files with 1,045 additions and 1 deletion.
25 changes: 25 additions & 0 deletions .github/workflows/dotnet.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
name: .NET

on:
push:
branches: [ develop ]
pull_request:
branches: [ develop ]

jobs:
build:

runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v2
- name: Setup .NET
uses: actions/setup-dotnet@v1
with:
dotnet-version: 5.0.x
- name: Restore dependencies
run: dotnet restore
- name: Build
run: dotnet build --no-restore
- name: Test
run: dotnet test --no-build --verbosity normal
73 changes: 73 additions & 0 deletions Healex.HL7v2Anonymizer.Tests/AnonymizerTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
using HL7.Dotnetcore;
using Microsoft.Extensions.Configuration;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.IO;
using static Healex.HL7v2Anonymizer.ReplacementOptions;

namespace Healex.HL7v2Anonymizer.Tests
{
[TestClass]
public class AnonymizerTests
{
[TestMethod]
[DeploymentItem("Healex.HL7v2Anonymizer.Tests/TestData", "TestData")]
public void AnonymizerTestAdt()
{
TestAnonymization(File.ReadAllText(@"./TestData/TestAdt1.hl7"));
}

[TestMethod]
[DeploymentItem("Healex.HL7v2Anonymizer.Tests/TestData", "TestData")]
public void AnonymizerTestOru()
{
TestAnonymization(File.ReadAllText(@"./TestData/TestOru1.hl7"));
}

public void TestAnonymization(string messageContent)
{
var message = new Message(messageContent);

// Setup
var replacementOptions = getReplacementOptions();
message.ParseMessage();

// Method under test
var anonymizer = new Anonymizer(replacementOptions);
anonymizer.Anonymize(message);

// Assert
foreach (SegmentReplacement segment in replacementOptions.Segments)
{
foreach (Replacement replacement in segment.Replacements)
{
try
{
Assert.AreEqual(message.GetValue(replacement.Path), replacement.Value);
}
catch (HL7Exception)
{
// Throws if segment is not present
continue;
}
}
}

// Output for manual inspection
var messageAsString = message.SerializeMessage(true);
Console.WriteLine(messageAsString);
}

private static ReplacementOptions getReplacementOptions()
{
var builder = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json", optional: false);

IConfiguration config = builder.Build();

var replacementOptions = config.GetSection("ReplacementOptions").Get<ReplacementOptions>();
return replacementOptions;
}
}
}
35 changes: 35 additions & 0 deletions Healex.HL7v2Anonymizer.Tests/Healex.HL7v2Anonymizer.Tests.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>

<IsPackable>false</IsPackable>
</PropertyGroup>

<ItemGroup>
<Content Include="..\Healex.HL7v2Anonymizer\appsettings.json" Link="appsettings.json" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Configuration" Version="5.0.0" />
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="5.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.7.1" />
<PackageReference Include="MSTest.TestAdapter" Version="2.1.1" />
<PackageReference Include="MSTest.TestFramework" Version="2.1.1" />
<PackageReference Include="coverlet.collector" Version="1.3.0" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\Healex.HL7v2Anonymizer\Healex.HL7v2Anonymizer.csproj" />
</ItemGroup>

<ItemGroup>
<None Update="TestData\TestAdt1.hl7">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="TestData\TestOru1.hl7">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>

</Project>
8 changes: 8 additions & 0 deletions Healex.HL7v2Anonymizer.Tests/TestData/TestAdt1.hl7
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
MSH|^~\&|NES|NINTENDO|TESTSYSTEM|TESTFACILITY|20010101000000||ADT^A04|Q123456789T123456789X123456|P|2.3
EVN|A04|20010101000000|||^KOOPA^BOWSER^^^^^^^CURRENT
PID|1||123456789^^^^MR||BROS^MARIO^^^^||19850101000000|M|||123 FAKE STREET^MARIO LUIGI BROS PLACE^TOADSTOOL KINGDOM^NES^A1B2C3^JP^HOME^^1234|1234|(555)555-0123^HOME^JP:1234567^^1^555^5550123~(555)555-0124^HOME^JP:1234568^^1^555^5550124|||S|MSH|12345678|||||||0|||||N
NK1|1|PEACH^PRINCESS^^^^|SO|ANOTHER CASTLE^^TOADSTOOL KINGDOM^NES^^JP|(123)555-1234|(123)555-2345|NOK|||||||||||||
NK1|2|TOADSTOOL^PRINCESS^^^^|SO|YET ANOTHER CASTLE^^TOADSTOOL KINGDOM^NES^^JP|(123)555-3456|(123)555-4567|EMC|||||||||||||
PV1|1|O|ABCD^EFGH^|||^^|123456^DINO^YOSHI^^^^^^MSRM^CURRENT^^^NEIGHBOURHOOD DR NBR^|^DOG^DUCKHUNT^^^^^^^CURRENT||CRD|||||||123456^DINO^YOSHI^^^^^^MSRM^CURRENT^^^NEIGHBOURHOOD DR NBR^|AO|0123456789|1|||||||||||||||||||MSH||A|||20010101000000
IN1|1|PAR^PARENT||||LUIGI
IN1|2|FRI^FRIEND||||PRINCESS
13 changes: 13 additions & 0 deletions Healex.HL7v2Anonymizer.Tests/TestData/TestOru1.hl7
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
MSH|^~\&|LCS|LCA|LIS|TEST9999|199807311532||ORU^R01|3629|P|2.2
PID|2|2161348462|20809880170|1614614|20809880170^TESTPAT||19760924|M|||^^^^
ORC|NW|8642753100012^LIS|20809880170^LCS||||||19980727000000|||HAVILAND
OBR|1|8642753100012^LIS|20809880170^LCS|008342^UPPER RESPIRATORY
OBX|1|ST|008342^UPPER RESPIRATORY CULTURE^L||FINALREPORT|||||N|F||| 19980729160500|BN
ORC|NW|8642753100012^LIS|20809880170^LCS||||||19980727000000|||HAVILAND
OBR|2|8642753100012^LIS|20809880170^LCS|997602^.^L|||19980727175800||||G|||
OBX|2|CE|997231^RESULT 1^L||M415|||||N|F|||19980729160500|BN
NTE|1|L|MORAXELLA (BRANHAMELLA) CATARRHALIS
NTE|2|L| HEAVY GROWTH
NTE|3|L| BETA LACTAMASE POSITIVE
OBX|3|CE|997232^RESULT 2^L||MR105|||||N|F|||19980729160500|BN
NTE|1|L|ROUTINE RESPIRATORY FLORA
31 changes: 31 additions & 0 deletions Healex.HL7v2Anonymizer.sln
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.31005.135
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Healex.HL7v2Anonymizer", "Healex.HL7v2Anonymizer\Healex.HL7v2Anonymizer.csproj", "{9A79221A-7684-4BD6-9721-199934853893}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Healex.HL7v2Anonymizer.Tests", "Healex.HL7v2Anonymizer.Tests\Healex.HL7v2Anonymizer.Tests.csproj", "{2B44D800-3F01-4288-AFD1-1DF7D956B661}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{9A79221A-7684-4BD6-9721-199934853893}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9A79221A-7684-4BD6-9721-199934853893}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9A79221A-7684-4BD6-9721-199934853893}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9A79221A-7684-4BD6-9721-199934853893}.Release|Any CPU.Build.0 = Release|Any CPU
{2B44D800-3F01-4288-AFD1-1DF7D956B661}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2B44D800-3F01-4288-AFD1-1DF7D956B661}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2B44D800-3F01-4288-AFD1-1DF7D956B661}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2B44D800-3F01-4288-AFD1-1DF7D956B661}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {971ACC78-6922-482C-8AC1-693787A35B0B}
EndGlobalSection
EndGlobal
59 changes: 59 additions & 0 deletions Healex.HL7v2Anonymizer/Anonymizer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
using HL7.Dotnetcore;
using System;
using static Healex.HL7v2Anonymizer.ReplacementOptions;

namespace Healex.HL7v2Anonymizer
{
public class Anonymizer
{
private ReplacementOptions _replacementOptions;

public Anonymizer(ReplacementOptions replacementOptions)
{
_replacementOptions = replacementOptions;
}

public bool Anonymize(Message message)
{
var isSuccess = true;
foreach (SegmentReplacement segmentReplacement in _replacementOptions.Segments)
{
var segments = message.Segments(segmentReplacement.Segment);
foreach (Segment segment in segments)
{
// Create new temporary message for each repeating segment
// because we can't set values in all repeating segments at once
// We use references so this overwrites the original segments
var tempMessage = new Message();
tempMessage.AddNewSegment(segment);

foreach (Replacement replacement in segmentReplacement.Replacements)
{
tryReplaceValue(replacement, tempMessage);
}
}
}
return isSuccess;
}

private bool tryReplaceValue(Replacement replacement, Message message)
{
try
{
message.SetValue(replacement.Path, replacement.Value);
}
catch (HL7Exception)
{
// Throws if segment is not present
}
catch (Exception e)
{
Console.WriteLine(e.Message);
return false;
}
return true;
}
}


}
21 changes: 21 additions & 0 deletions Healex.HL7v2Anonymizer/Healex.HL7v2Anonymizer.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net5.0</TargetFramework>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="HL7-dotnetcore" Version="2.20.0" />
<PackageReference Include="Microsoft.Extensions.Configuration" Version="5.0.0" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="5.0.0" />
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="5.0.0" />
</ItemGroup>

<ItemGroup>
<None Update="appsettings.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>

</Project>
102 changes: 102 additions & 0 deletions Healex.HL7v2Anonymizer/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
using HL7.Dotnetcore;
using Microsoft.Extensions.Configuration;
using System;
using System.IO;

namespace Healex.HL7v2Anonymizer
{
class Program
{
static void Main(string[] args)
{
waitForInput();
}

private static void waitForInput()
{
Console.WriteLine("Welcome to the Healex HL7v2 anonymizer!");
Console.WriteLine("---------------------------------------------------------------------------------------");
Console.WriteLine("WARNING: THIS APPLICATION OVERWRITES THE ORIGINAL v2 MESSAGES. BACKUP YOUR FILES FIRST!");
Console.WriteLine("---------------------------------------------------------------------------------------");
Console.WriteLine("Enter the directory to your v2 messages and press enter:");
var directory = Console.ReadLine();
Console.WriteLine();
tryAnonymizeMessages(directory);
Console.WriteLine();
waitForInput();
}

private static void tryAnonymizeMessages(string directory)
{
var pathsToV2Messages = getPathsToV2Messages(directory);
var anonymizer = new Anonymizer(getReplacementOptions());

if (pathsToV2Messages is not null)
{
if (pathsToV2Messages.Length == 0)
Console.WriteLine($"=> No v2 messages found in {directory}");

foreach (string path in pathsToV2Messages)
{
var message = readAndParseMessage(path);
var success = anonymizer.Anonymize(message);
serializeAndWriteMessageOrLogError(success, message, path);
}
}
}

private static void serializeAndWriteMessageOrLogError(bool success, Message message, string path)
{
if (success)
{
Console.WriteLine($"=> Anonymization successful: {path}");
var serializedMessage = message.SerializeMessage(true);
File.WriteAllText(path, serializedMessage);
}
else
{
Console.WriteLine($"=> Anonymization fail: {path}");
}
}

private static string[] getPathsToV2Messages(string directory)
{
try
{
var v2Messages = Directory.GetFiles(directory, "*.hl7");
return v2Messages;
}
catch (Exception e)
{
Console.WriteLine(e.Message);
return null;
}
}

private static Message readAndParseMessage(string path)
{
try
{
var message = new Message(File.ReadAllText(path));
message.ParseMessage();
return message;
} catch (Exception e)
{
Console.Write(e.Message);
return null;
}
}

private static ReplacementOptions getReplacementOptions()
{
var builder = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json", optional: false);

IConfiguration config = builder.Build();

var replacementOptions = config.GetSection("ReplacementOptions").Get<ReplacementOptions>();
return replacementOptions;
}
}
}
19 changes: 19 additions & 0 deletions Healex.HL7v2Anonymizer/ReplacementOptions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
namespace Healex.HL7v2Anonymizer
{
public class ReplacementOptions
{
public SegmentReplacement[] Segments { get; set; }

public class SegmentReplacement
{
public string Segment { get; set; }
public Replacement[] Replacements { get; set; }
}

public class Replacement
{
public string Path { get; set; }
public string Value { get; set; }
}
}
}
Loading

0 comments on commit 8cdbe23

Please sign in to comment.