Skip to content

Commit

Permalink
feat: #15 audit message for QIDO-RS
Browse files Browse the repository at this point in the history
  • Loading branch information
Chinlinlee committed Aug 28, 2023
1 parent 5fe83d0 commit 14c21e0
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 7 deletions.
35 changes: 34 additions & 1 deletion api/dicom-web/controller/QIDO-RS/service/QIDO-RS.service.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ const {
DicomWebServiceError,
DicomWebStatusCodes
} = require("@error/dicom-web-service");
const { AuditManager } = require("@models/DICOM/audit/auditManager");
const auditMessageModel = require("@models/mongodb/models/auditMessage");
const { EventType } = require("@models/DICOM/audit/eventType");
const { EventOutcomeIndicator } = require("@models/DICOM/audit/auditUtils");

class QidoRsService {

Expand Down Expand Up @@ -73,7 +77,13 @@ class QidoRsService {

async getAndResponseDicomJson() {
try {

let queryAudit = new AuditManager(
auditMessageModel,
EventType.QUERY,
EventOutcomeIndicator.Success,
DicomWebService.getRemoteAddress(this.request), DicomWebService.getRemoteHostname(this.request),
DicomWebService.getServerAddress(), DicomWebService.getServerHostname()
);
let dicomWebService = new DicomWebService(this.request, this.response);

let queryOptions = {
Expand All @@ -85,12 +95,18 @@ class QidoRsService {
requestParams: this.request.params
};

queryAudit.onQuery(
`SearchFor${this.level}`,
JSON.stringify({...queryOptions.requestParams,...queryOptions.query}),
"UTF-8"
);
let qidoDicomJsonFactory = new QidoDicomJsonFactory(queryOptions, this.level);

let dicomJson = await qidoDicomJsonFactory.getDicomJson();

let dicomJsonLength = _.get(dicomJson, "length", 0);
if (dicomJsonLength > 0) {
this.auditInstancesAccessed(dicomJson);
this.response.writeHead(200, {
"Content-Type": "application/dicom+json"
});
Expand All @@ -105,6 +121,22 @@ class QidoRsService {
}
}

async auditInstancesAccessed(dicomJson) {
let queryAccessedAudit = new AuditManager(
auditMessageModel,
EventType.QUERY_ACCESSED_INSTANCE,
EventOutcomeIndicator.Success,
DicomWebService.getRemoteAddress(this.request), DicomWebService.getRemoteHostname(this.request),
DicomWebService.getServerAddress(), DicomWebService.getServerHostname()
);

for(let i = 0 ; i < dicomJson.length ; i++) {
let studyUID = _.get(dicomJson[i], "0020000D.Value.0");
queryAccessedAudit.onDicomInstancesAccessed([studyUID]);
}

}

}

class QidoDicomJsonFactory {
Expand Down Expand Up @@ -353,6 +385,7 @@ async function getStudyDicomJson(queryOptions) {
try {
let query = await convertRequestQueryToMongoQuery(queryOptions.query);
queryOptions.query = {
...queryOptions.requestParams,
...query.$match
};

Expand Down
14 changes: 8 additions & 6 deletions models/DICOM/audit/auditMessageFactory.js
Original file line number Diff line number Diff line change
Expand Up @@ -235,8 +235,8 @@ class AuditMessageFactory {
eventType, eventResult,
clientAETitle, clientHostname,
serverAETitle, serverHostname,
SOPClassUID,
queryData, TransferSyntax
sopClassUID,
queryData, transferSyntax
) {

/**
Expand All @@ -263,22 +263,24 @@ class AuditMessageFactory {
await theQuery.setParticipantObjectTypeCode(AuditMessages$ParticipantObjectTypeCode.SystemObject);
await theQuery.setParticipantObjectTypeCodeRole(AuditMessages$ParticipantObjectTypeCodeRole.Report);
await theQuery.setParticipantObjectIDTypeCode(AuditMessages$ParticipantObjectIDTypeCode.SOPClassUID);
await theQuery.setParticipantObjectID(SOPClassUID); // this field shall hold the UID of the SOP Class being queried
await theQuery.setParticipantObjectID(sopClassUID); // this field shall hold the UID of the SOP Class being queried
await theQuery.setParticipantObjectQuery(
Buffer.from(queryData, "utf8")
); // this field shall hold the Dataset of the DICOM query, xs:base64Binary encoded.
// 但是他沒有說本體encoded之前的dataset是何種形式,故我們輸入參數字串後直接encode,本體為何種形式我們暫時不管。


let ObjDetail = await ParticipantObjectDetail.newInstanceAsync();
await ObjDetail.setType("TransferSyntax");
await ObjDetail.setValue(TransferSyntax.getBytes());
await ObjDetail.setType("QueryEncoding");
await ObjDetail.setValue(
Buffer.from(transferSyntax, "utf8")
);
await (await theQuery.getParticipantObjectDetail()).add(ObjDetail); // A ParticipantObjectDetail element with the XML attribute "TransferSyntax" shall be present. The value of the Transfer Syntax attribute shall be the UID of the transfer syntax of the query. The element contents shall be xs:base64Binary encoding. The Transfer Syntax shall be a DICOM Transfer Syntax.

/**
將上述已經記錄完成的Real World Entities,組合成一個Audit Message。
*/
let msg = await AuditMessages.createMessage(theEvent, theActiveParticipants, theQuery);
let msg = await AuditMessages.createMessage(theEvent, theActiveParticipants, [theQuery]);

return await AuditUtils.toJson(msg);
}
Expand Down
9 changes: 9 additions & 0 deletions models/DICOM/audit/eventType.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,15 @@ class EventType {
AuditMessages$RoleIDCode.Destination
);

static QUERY_ACCESSED_INSTANCE = new EventType(
"QUERY_ACCESSED_INSTANCE",
AuditMessages$EventID.DICOMInstancesAccessed,
AuditMessages$EventActionCode.Read,
AuditMessages$RoleIDCode.Source,
AuditMessages$RoleIDCode.Destination,
undefined
);

constructor(eventName, eventID, eventActionCode, source, destination, eventTypeCode) {
this.eventName = eventName;
this.eventID = eventID;
Expand Down

0 comments on commit 14c21e0

Please sign in to comment.