diff --git a/api/dicom-web/controller/QIDO-RS/service/QIDO-RS.service.js b/api/dicom-web/controller/QIDO-RS/service/QIDO-RS.service.js index 0f995080..0a113f51 100644 --- a/api/dicom-web/controller/QIDO-RS/service/QIDO-RS.service.js +++ b/api/dicom-web/controller/QIDO-RS/service/QIDO-RS.service.js @@ -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 { @@ -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 = { @@ -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" }); @@ -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 { @@ -353,6 +385,7 @@ async function getStudyDicomJson(queryOptions) { try { let query = await convertRequestQueryToMongoQuery(queryOptions.query); queryOptions.query = { + ...queryOptions.requestParams, ...query.$match }; diff --git a/models/DICOM/audit/auditMessageFactory.js b/models/DICOM/audit/auditMessageFactory.js index acea86f0..d627ceee 100644 --- a/models/DICOM/audit/auditMessageFactory.js +++ b/models/DICOM/audit/auditMessageFactory.js @@ -235,8 +235,8 @@ class AuditMessageFactory { eventType, eventResult, clientAETitle, clientHostname, serverAETitle, serverHostname, - SOPClassUID, - queryData, TransferSyntax + sopClassUID, + queryData, transferSyntax ) { /** @@ -263,7 +263,7 @@ 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. @@ -271,14 +271,16 @@ class AuditMessageFactory { 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); } diff --git a/models/DICOM/audit/eventType.js b/models/DICOM/audit/eventType.js index 7d43438e..ebcfccc7 100644 --- a/models/DICOM/audit/eventType.js +++ b/models/DICOM/audit/eventType.js @@ -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;