20#include <unordered_map>
57void insert_sequence(dicom_dataset& ds, dicom_tag tag,
58 std::vector<dicom_dataset> items) {
59 dicom_element seq_elem(tag, vr_type::SQ);
60 seq_elem.sequence_items() = std::move(items);
61 ds.insert(std::move(seq_elem));
64std::string current_datetime() {
65 auto now = std::chrono::system_clock::now();
66 auto time_t_now = std::chrono::system_clock::to_time_t(now);
69 gmtime_s(&tm_now, &time_t_now);
71 gmtime_r(&time_t_now, &tm_now);
74 std::strftime(buf,
sizeof(buf),
"%Y%m%d%H%M%S", &tm_now);
78std::string current_date() {
79 return current_datetime().substr(0, 8);
82std::string current_time() {
83 return current_datetime().substr(8, 6);
97 const std::string& study_instance_uid,
98 const std::vector<kos_instance_reference>& references,
99 const std::optional<core::dicom_dataset>& patient_demographics)
const {
103 if (references.empty()) {
117 if (patient_demographics) {
119 if (patient_demographics->contains(tag)) {
120 kos.
set_string(tag,
vr, patient_demographics->get_string(tag));
218 if (!ref_physician.empty()) {
222 entry.
title =
"Key Object Selection Document";
228 const std::string& patient_id)
const {
246std::vector<std::string> collect_sop_instance_uids(
248 std::vector<std::string> uids;
249 const auto* evidence_elem =
251 if (!evidence_elem || !evidence_elem->is_sequence()) {
254 for (
const auto& study_item : evidence_elem->sequence_items()) {
255 const auto* series_elem =
257 if (!series_elem || !series_elem->is_sequence())
continue;
258 for (
const auto& series_item : series_elem->sequence_items()) {
259 const auto* sop_elem =
261 if (!sop_elem || !sop_elem->is_sequence())
continue;
262 for (
const auto& sop_item : sop_elem->sequence_items()) {
264 if (!
uid.empty()) uids.push_back(std::move(
uid));
276 bool is_imaging)
const {
283 auto sop_instance_uids = collect_sop_instance_uids(kos_dataset);
284 const auto transaction =
326 std::shared_ptr<kcenon::pacs::security::atna_service_auditor> auditor) {
341 static constexpr const char* uid_root =
"1.2.826.0.1.3680043.2.1545.1";
342 static std::mt19937_64 gen{std::random_device{}()};
343 static std::uniform_int_distribution<uint64_t> dist;
345 auto now = std::chrono::system_clock::now();
346 auto timestamp = std::chrono::duration_cast<std::chrono::milliseconds>(
347 now.time_since_epoch()).count();
349 return std::string(uid_root) +
"." + std::to_string(timestamp) +
350 "." + std::to_string(dist(gen) % 100000);
355 const std::vector<kos_instance_reference>& references)
const {
358 struct series_group {
359 std::string series_uid;
360 std::vector<std::pair<std::string, std::string>> instances;
363 std::unordered_map<std::string, std::vector<series_group>> study_map;
365 for (
const auto& ref : references) {
366 auto& series_list = study_map[ref.study_instance_uid];
368 auto it = std::find_if(series_list.begin(), series_list.end(),
369 [&](
const series_group& sg) {
370 return sg.series_uid == ref.series_instance_uid;
373 if (it != series_list.end()) {
374 it->instances.emplace_back(ref.sop_class_uid, ref.sop_instance_uid);
377 sg.series_uid = ref.series_instance_uid;
378 sg.instances.emplace_back(ref.sop_class_uid, ref.sop_instance_uid);
379 series_list.push_back(std::move(sg));
384 std::vector<dicom_dataset> study_items;
385 for (
const auto& [study_uid, series_list] : study_map) {
389 std::vector<dicom_dataset> series_items;
390 for (
const auto& sg : series_list) {
394 std::vector<dicom_dataset> sop_items;
395 for (
const auto& [sop_class, sop_instance] : sg.instances) {
399 sop_items.push_back(std::move(sop_item));
402 series_items.push_back(std::move(series_item));
405 study_items.push_back(std::move(study_item));
408 insert_sequence(kos_dataset,
410 std::move(study_items));
High-level facade for ATNA audit logging in DICOM services.
Represents a DICOM Dataset (ordered collection of Data Elements)
auto get(dicom_tag tag) noexcept -> dicom_element *
Get a pointer to the element with the given tag.
void set_string(dicom_tag tag, encoding::vr_type vr, std::string_view value)
Set a string value for the given tag.
auto get_string(dicom_tag tag, std::string_view default_value="") const -> std::string
Get the string value of an element.
Represents a DICOM tag (Group, Element pair)
@ rad_68
RAD-68 Provide and Register Imaging Document Set.
@ iti_41
ITI-41 Provide and Register Document Set-b.
virtual void audit_xds_provide_and_register(xds_source_transaction transaction, const std::string &source_ae, const std::string &dest_ae, const std::string &study_uid, const std::string &patient_id, const std::vector< std::string > &sop_instance_uids, bool success)
Audit an XDS-I.b Provide and Register Document Set transaction.
const imaging_document_source_config & config() const noexcept
Get current configuration.
publication_result publish_document(const core::dicom_dataset &kos_dataset, const xds_document_entry &entry, bool is_imaging=true) const
Publish a KOS document to the XDS registry/repository.
imaging_document_source()=default
std::string generate_uid() const
Generate a new UID for KOS instances.
void build_evidence_sequence(core::dicom_dataset &kos_dataset, const std::vector< kos_instance_reference > &references) const
Build the Current Requested Procedure Evidence Sequence.
std::shared_ptr< kcenon::pacs::security::atna_service_auditor > auditor_
void set_config(const imaging_document_source_config &config)
Set configuration.
xds_submission_set build_submission_set(const std::string &patient_id) const
Build XDS submission set metadata.
kos_creation_result create_kos_document(const std::string &study_instance_uid, const std::vector< kos_instance_reference > &references, const std::optional< core::dicom_dataset > &patient_demographics=std::nullopt) const
Create a KOS document from a set of DICOM instance references.
xds_document_entry build_document_entry(const core::dicom_dataset &kos_dataset) const
Build XDS document entry metadata from a KOS dataset.
imaging_document_source_config config_
void set_audit_handler(std::shared_ptr< kcenon::pacs::security::atna_service_auditor > auditor)
Install an ATNA audit handler for XDS-I.b transactions.
Compile-time constants for commonly used DICOM tags.
IHE XDS-I.b Imaging Document Source Actor.
vr_type
DICOM Value Representation (VR) types.
constexpr std::string_view key_object_selection_document_storage_uid
Key Object Selection Document Storage SOP Class UID.
Structured Report (SR) Storage SOP Classes.
Configuration for the Imaging Document Source actor.
std::string source_oid
Source system OID (used as sourceId in submissions)
std::string practice_setting_code_scheme
std::string practice_setting_code
Default practice setting code.
std::string registry_url
XDS Registry/Repository endpoint URL.
std::string facility_type_code_scheme
std::string facility_type_code
Default facility type code.
Result of a KOS document creation operation.
std::optional< core::dicom_dataset > kos_dataset
The created KOS dataset (if successful)
std::string error_message
Error message (if failed)
size_t reference_count
Number of referenced instances.
std::string kos_instance_uid
SOP Instance UID of the created KOS.
bool success
Whether the KOS was created successfully.
Result of publishing a document to an XDS registry/repository.
std::string document_entry_uuid
Registry-assigned document entry UUID.
std::string error_message
Error message (if failed)
bool success
Whether the publication was successful.
Document entry metadata for XDS registry submission.
std::string creation_time
Creation time (DTM format: YYYYMMDDhhmmss)
std::string patient_id
Patient ID in CX format (ID^^^&OID&ISO)
std::string format_code_scheme
std::string type_code_display
std::string service_start_time
Service start/stop time.
std::string class_code
Document class code (e.g., "Imaging Procedure")
std::string class_code_scheme
std::string facility_type_code_scheme
std::string type_code
Type code (e.g., "Key Object Selection")
std::string unique_id
Document unique ID (OID format)
std::string facility_type_code
Healthcare facility type.
std::string source_patient_id
Source patient ID (from the originating system)
std::string type_code_scheme
std::string class_code_display
std::string author_person
Author information.
std::string format_code
Format code (e.g., "1.2.840.10008.5.1.4.1.1.88.59")
std::string entry_uuid
Unique identifier for this document entry.
std::string service_stop_time
std::string title
Title/description.
std::string practice_setting_code_scheme
std::string practice_setting_code
Practice setting code.
Submission set metadata for XDS registry.
std::string content_type_code
Content type code.
std::string content_type_code_display
std::string patient_id
Patient ID.
std::string unique_id
Unique identifier for this submission set.
std::string source_id
Source ID (OID of the submitting system)
std::string content_type_code_scheme
std::string submission_time
Submission time (DTM format)