Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BAH-4120 | Migrate Scan and Share Feature to use ABDM v3 APIs #173

Merged
merged 6 commits into from
Nov 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions src/In.ProjectEKA.HipService/Common/Constants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public static class Constants
public const string APP_PATH_CREATE_ABHA_ADDRESS = "/" + VERSION_V3 + "/hip/createAbhaAddress";
public const string APP_PATH_GET_ABHA_CARD = "/" + VERSION_V3 + "/hip/getAbhaCard";

public const string PATH_SESSIONS = CURRENT_VERSION + "/sessions";
public const string PATH_SESSIONS = "api/hiecm/gateway/"+VERSION_V3+"/sessions";
public const string PATH_CARE_CONTEXTS_DISCOVER = CURRENT_VERSION + "/care-contexts/discover";
public const string PATH_CONSENTS_HIP = CURRENT_VERSION + "/consents/hip/notify";
public const string PATH_LINKS_LINK_INIT = CURRENT_VERSION + "/links/link/init";
Expand Down Expand Up @@ -86,9 +86,9 @@ public static class Constants
public const string DEEPLINK_URL = "https://link.to.health.records";
public const string PATH_PATIENT_NOTIFY = "/" + CURRENT_VERSION + "/patients/status/notify";
public const string PATH_PATIENT_ON_NOTIFY = "/" + CURRENT_VERSION + "/patients/status/on-notify";
public const string PATH_PROFILE_SHARE = "/" + UPDATED_VERSION + "/patients/profile/share";
public const string PATH_PROFILE_ON_SHARE = "/" + UPDATED_VERSION + "/patients/profile/on-share";
public const string PATH_PROFILE_FETCH = "/" + CURRENT_VERSION + "/patients/profile/fetch";
public const string PATH_PROFILE_SHARE = "/api/" + VERSION_V3 + "/hip/patient/share";
public const string PATH_PROFILE_ON_SHARE = "/api/hiecm/patient-share/"+VERSION_V3 +"/on-share";
public const string GET_PATIENT_QUEUE = "/" + VERSION_V3 + "/hip/getPatientQueue";

public const string ABHA_SERVICE_CERT_URL = "/" + VERSION_V3 + "/profile/public/certificate";
public const string ENROLLMENT_REQUEST_OTP = "/" + VERSION_V3 + "/enrollment/request/otp";
Expand Down
2 changes: 1 addition & 1 deletion src/In.ProjectEKA.HipService/Common/HttpRequestHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ public static HttpRequestMessage CreateHttpRequest<T>(
if (transactionId != null)
httpRequestMessage.Headers.Add("Transaction_Id", transactionId);
httpRequestMessage.Headers.Add("REQUEST-ID", Guid.NewGuid().ToString());
httpRequestMessage.Headers.Add("TIMESTAMP", DateTime.Now.ToString(TIMESTAMP_FORMAT));
httpRequestMessage.Headers.Add("TIMESTAMP", DateTime.UtcNow.ToString(TIMESTAMP_FORMAT));
return httpRequestMessage;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
using System;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Configuration;
using Log = Serilog.Log;

namespace In.ProjectEKA.HipService.Common.Model;

public class GatewayAuthHttpHandler : HttpClientHandler
{
public GatewayAuthHttpHandler(IConfiguration configuration)
{
Configuration = configuration;
}

private IConfiguration Configuration;

protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request,
CancellationToken cancellationToken)
{
request.Headers.Add("X-CM-ID", Configuration.GetValue<string>("Gateway:cmSuffix"));
request.Headers.Add("REQUEST-ID", Guid.NewGuid().ToString());
request.Headers.Add("TIMESTAMP", DateTime.UtcNow.ToString(Constants.TIMESTAMP_FORMAT));
HttpResponseMessage responseMessage = await base.SendAsync(request, cancellationToken);
return responseMessage;
}
}
6 changes: 5 additions & 1 deletion src/In.ProjectEKA.HipService/Gateway/GatewayClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@ public virtual async Task<Option<string>> Authenticate(String correlationId)
var json = JsonConvert.SerializeObject(new
{
clientId = configuration.ClientId,
clientSecret = configuration.ClientSecret
clientSecret = configuration.ClientSecret,
grantType = "client_credentials"
}, new JsonSerializerSettings
{
NullValueHandling = NullValueHandling.Ignore,
Expand All @@ -56,6 +57,9 @@ public virtual async Task<Option<string>> Authenticate(String correlationId)
};
if (correlationId != null)
message.Headers.Add(Constants.CORRELATION_ID, correlationId);
message.Headers.Add("REQUEST-ID", Guid.NewGuid().ToString());
message.Headers.Add("TIMESTAMP", DateTime.UtcNow.ToString(Constants.TIMESTAMP_FORMAT));
message.Headers.Add("X-CM-ID", configuration.CmSuffix);
var responseMessage = await httpClient.SendAsync(message).ConfigureAwait(false);
var response = await responseMessage.Content.ReadAsStringAsync();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,8 @@ namespace In.ProjectEKA.HipService.Patient
{
public interface IPatientProfileService
{
Task<int> SavePatient(ShareProfileRequest shareProfileRequest);
Task<int> SavePatient(ShareProfileRequest shareProfileRequest, string requestId, string timestamp);
bool IsValidRequest(ShareProfileRequest shareProfileRequest);
Task<List<PatientQueue>> GetPatientQueue();
Task linkToken(PatientDemographics patientDemographics);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,34 +5,35 @@ namespace In.ProjectEKA.HipService.Patient.Model
{
public class PatientDemographics
{
public string HealthId { get; }
public string HealthIdNumber { get; }
public string AbhaAddress { get; }
public string AbhaNumber { get; }
public string Name { get; }
public string Gender { get; }
public Address Address { get; }
public int YearOfBirth { get; }
public int? DayOfBirth { get; }
public int? MonthOfBirth { get; }
public List<Identifier> Identifiers { get; }
public string PhoneNumber { get; }

public PatientDemographics(string name,
string gender,
string healthId,
string abhaAddress,
Address address,
int yearOfBirth,
int? dayOfBirth,
int? monthOfBirth,
List<Identifier> identifiers, string healthIdNumber)
string abhaNumber,
string phoneNumber)
{
Name = name;
Gender = gender;
HealthId = healthId;
AbhaAddress = abhaAddress;
Address = address;
YearOfBirth = yearOfBirth;
DayOfBirth = dayOfBirth;
MonthOfBirth = monthOfBirth;
Identifiers = identifiers;
HealthIdNumber = healthIdNumber;
PhoneNumber = phoneNumber;
AbhaNumber = abhaNumber;
}
}
}
8 changes: 3 additions & 5 deletions src/In.ProjectEKA.HipService/Patient/Model/Profile.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,10 @@ namespace In.ProjectEKA.HipService.Patient.Model
{
public class Profile
{
public string HipCode { get; }
public PatientDemographics PatientDemographics { get; }
public Profile(string hipCode, PatientDemographics patient)
public PatientDemographics Patient { get; }
public Profile(PatientDemographics patient)
{
HipCode = hipCode;
PatientDemographics = patient;
Patient = patient;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,29 @@ namespace In.ProjectEKA.HipService.Patient.Model
{
public class ProfileShareAcknowledgement
{
public ProfileShareAcknowledgement(string status,string healthId, string tokenNumber)
public ProfileShareAcknowledgement(string status, string abhaAddress, ProfileShareAckProfile profile)
{
Status = status;
HealthId = healthId;
TokenNumber = tokenNumber;
AbhaAddress = abhaAddress;
Profile = profile;
}

public string Status { get; }
public string HealthId { get; }
public string AbhaAddress { get; }
public ProfileShareAckProfile Profile { get; }
}

public class ProfileShareAckProfile
{
public string Context { get; }
public string TokenNumber { get; }
public string Expiry { get; }

public ProfileShareAckProfile(string context, string tokenNumber, string expiry)
{
Context = context;
TokenNumber = tokenNumber;
Expiry = expiry;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,14 @@ namespace In.ProjectEKA.HipService.Patient.Model
{
public class ProfileShareConfirmation
{
public ProfileShareConfirmation(string requestId, string timestamp,
ProfileShareAcknowledgement acknowledgement, Error error, Resp resp)
public ProfileShareConfirmation(ProfileShareAcknowledgement acknowledgement, Error error, Resp resp)
{
RequestId = requestId;
Timestamp = timestamp;
Acknowledgement = acknowledgement;
Error = error;
Resp = resp;
Response = resp;
}
public string RequestId { get; }
public string Timestamp { get; }
public Error Error { get; }
public Resp Resp { get; }
public Resp Response { get; }
public ProfileShareAcknowledgement Acknowledgement { get; }
}
}
34 changes: 26 additions & 8 deletions src/In.ProjectEKA.HipService/Patient/Model/ShareProfileRequest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,34 @@ namespace In.ProjectEKA.HipService.Patient.Model
{
public class ShareProfileRequest
{
[Required]
public string RequestId { get;}
[Required]
public DateTime? Timestamp { get;}
public Profile Profile { get; }
public ShareProfileRequest(string requestId,DateTime? timestamp, Profile profile)
public string Intent { get; }

public ShareProfileMetadata Metadata { get; }
[Required] public Profile Profile { get; }

public ShareProfileRequest(string intent, ShareProfileMetadata metadata, Profile profile)
{
RequestId = requestId;
Timestamp = timestamp;
Intent = intent;
Metadata = metadata;
Profile = profile;
}
}

public class ShareProfileMetadata
{
public string HipId { get; }
public string Context { get; }
public string HprId { get; }
public string Latitude { get; }
public string Longitude { get; }

public ShareProfileMetadata(string hipId, string context, string hprId, string latitude, string longitude)
{
HipId = hipId;
Context = context;
HprId = hprId;
Latitude = latitude;
Longitude = longitude;
}
}
}
16 changes: 7 additions & 9 deletions src/In.ProjectEKA.HipService/Patient/PatientController.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using In.ProjectEKA.HipService.Common;
using Microsoft.AspNetCore.Authorization;

namespace In.ProjectEKA.HipService.Patient
{
Expand Down Expand Up @@ -48,7 +49,7 @@

[Route(PATH_PROFILE_SHARE)]
public async Task<ActionResult> StoreDetails([FromHeader(Name = CORRELATION_ID)] string correlationId,
[FromBody] ShareProfileRequest shareProfileRequest)
[FromBody] ShareProfileRequest shareProfileRequest, [FromHeader(Name = "request-id")] string requestId, [FromHeader(Name = "timestamp")] string timestamp)
{
var cmSuffix = _gatewayConfiguration.CmSuffix;
var status = Status.SUCCESS;
Expand All @@ -62,23 +63,19 @@
int token = 0;
if(error == null)
{
token = await _patientProfileService.SavePatient(shareProfileRequest);
token = await _patientProfileService.SavePatient(shareProfileRequest,requestId, timestamp);
}

var gatewayResponse = new ProfileShareConfirmation(
Guid.NewGuid().ToString(),
DateTime.Now.ToUniversalTime().ToString(DateTimeFormat),
new ProfileShareAcknowledgement(status.ToString(),shareProfileRequest.Profile.PatientDemographics.HealthId,token.ToString()), error,
new Resp(shareProfileRequest.RequestId));
new ProfileShareAcknowledgement(status.ToString(),shareProfileRequest.Profile.Patient.AbhaAddress,new ProfileShareAckProfile(shareProfileRequest.Metadata.Context,token.ToString(),"1800")), error,
new Resp(requestId));
Task.Run(async () =>

Check warning on line 72 in src/In.ProjectEKA.HipService/Patient/PatientController.cs

View workflow job for this annotation

GitHub Actions / build

Because this call is not awaited, execution of the current method continues before the call is completed. Consider applying the 'await' operator to the result of the call.

Check warning on line 72 in src/In.ProjectEKA.HipService/Patient/PatientController.cs

View workflow job for this annotation

GitHub Actions / build

Because this call is not awaited, execution of the current method continues before the call is completed. Consider applying the 'await' operator to the result of the call.

Check warning on line 72 in src/In.ProjectEKA.HipService/Patient/PatientController.cs

View workflow job for this annotation

GitHub Actions / build

Because this call is not awaited, execution of the current method continues before the call is completed. Consider applying the 'await' operator to the result of the call.
{
await Task.Delay(500);
await _gatewayClient.SendDataToGateway(PATH_PROFILE_ON_SHARE,
gatewayResponse,
cmSuffix,
correlationId);
if(error == null)
await _patientProfileService.linkToken(shareProfileRequest.Profile.PatientDemographics);
});
if (error == null)
{
Expand All @@ -87,7 +84,8 @@
return BadRequest();
}

[Route(PATH_PROFILE_FETCH)]
[Authorize(AuthenticationSchemes = BAHMNI_AUTH)]
[Route(GET_PATIENT_QUEUE)]
public async Task<ActionResult> GetDetails()
{
var patientQueueResult = await _patientProfileService.GetPatientQueue();
Expand Down
27 changes: 6 additions & 21 deletions src/In.ProjectEKA.HipService/Patient/PatientProfileService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,11 @@
this.hipConfiguration = hipConfiguration;
}

public async Task<int> SavePatient(ShareProfileRequest shareProfileRequest)
public async Task<int> SavePatient(ShareProfileRequest shareProfileRequest, string requestId, string timestamp)
{
var requesId = shareProfileRequest.RequestId;
var timeStamp = shareProfileRequest.Timestamp.ToString();
var hipCode = shareProfileRequest.Profile.HipCode;
var patient = shareProfileRequest.Profile.PatientDemographics;
var response = await Save(new PatientQueue(requesId, timeStamp, patient, hipCode));
var hipCode = shareProfileRequest.Metadata.HipId;
var patient = shareProfileRequest.Profile.Patient;
var response = await Save(new PatientQueue(requestId, timestamp, patient, hipCode));
if(response.HasValue)
Log.Information("Patient saved to queue");
return response.ValueOrDefault();
Expand All @@ -65,10 +63,10 @@
public bool IsValidRequest(ShareProfileRequest shareProfileRequest)
{
var profile = shareProfileRequest?.Profile;
var demographics = profile?.PatientDemographics;
return demographics is {HealthId: { }, Identifiers: { }, Name: { },Gender:{}} && Enum.IsDefined(typeof(Gender), demographics.Gender) && demographics.YearOfBirth != 0;
var demographics = profile?.Patient;
return demographics is {AbhaAddress: { }, Name: { },Gender:{}} && Enum.IsDefined(typeof(Gender), demographics.Gender) && demographics.YearOfBirth != 0;
}
public async Task<List<PatientQueue>> GetPatientQueue()

Check warning on line 69 in src/In.ProjectEKA.HipService/Patient/PatientProfileService.cs

View workflow job for this annotation

GitHub Actions / build

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.

Check warning on line 69 in src/In.ProjectEKA.HipService/Patient/PatientProfileService.cs

View workflow job for this annotation

GitHub Actions / build

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.

Check warning on line 69 in src/In.ProjectEKA.HipService/Patient/PatientProfileService.cs

View workflow job for this annotation

GitHub Actions / build

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.
{
try
{
Expand All @@ -85,19 +83,6 @@
}
}

public async Task linkToken(PatientDemographics patientDemographics)
{
var dob = new Date(patientDemographics.YearOfBirth, patientDemographics.MonthOfBirth ?? 1,
patientDemographics.DayOfBirth ?? 1).ToString();
var ndhmDemograhics = new NdhmDemographics(patientDemographics.HealthId, patientDemographics.Name,
patientDemographics.Gender,
dob, patientDemographics.Identifiers[0].value);
var request = new HttpRequestMessage(HttpMethod.Post, hipConfiguration.Value.Url + PATH_DEMOGRAPHICS);
request.Content = new StringContent(JsonConvert.SerializeObject(ndhmDemograhics), Encoding.UTF8,
"application/json");
await httpClient.SendAsync(request).ConfigureAwait(false);
}


}
}
33 changes: 33 additions & 0 deletions src/In.ProjectEKA.HipService/Patient/jobs/CleanPatientQueueJob.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
using System;
using System.Collections.Generic;
using System.Linq;
using In.ProjectEKA.HipService.Logger;
using In.ProjectEKA.HipService.OpenMrs;
using In.ProjectEKA.HipService.Patient.Database;

namespace In.ProjectEKA.HipService.Patient.jobs;

public class CleanPatientQueueJob
{
private readonly PatientContext patientContext;
private readonly OpenMrsConfiguration openMrsConfiguration;

public CleanPatientQueueJob(PatientContext patientContext, OpenMrsConfiguration openMrsConfiguration)
{
this.patientContext = patientContext;
this.openMrsConfiguration = openMrsConfiguration;
}

public void CleanPatientQueue()
{
List<PatientQueue> oldEntries = patientContext.PatientQueue.ToList().FindAll(
patient => DateTime.Now.Subtract(DateTime.Parse(patient.DateTimeStamp)).TotalMinutes >
openMrsConfiguration.PatientQueueTimeLimit
);

patientContext.PatientQueue.RemoveRange(oldEntries);
patientContext.SaveChanges();

Log.Information($"Deleted {oldEntries.Count} old patient queue at {DateTime.UtcNow}");
}
}
Loading
Loading