dcm4chee 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. data/README.md +45 -0
  2. data/Rakefile +9 -0
  3. data/app/controllers/dcm4chee/api/v1/application_entities_controller.rb +178 -0
  4. data/app/controllers/dcm4chee/api/v1/base_controller.rb +15 -0
  5. data/app/controllers/dcm4chee/api/v1/dicom_objects_controller.rb +58 -0
  6. data/app/controllers/dcm4chee/api/v1/file_systems_controller.rb +37 -0
  7. data/app/controllers/dcm4chee/api/v1/instances_controller.rb +68 -0
  8. data/app/controllers/dcm4chee/api/v1/modalities_controller.rb +29 -0
  9. data/app/controllers/dcm4chee/api/v1/patients_controller.rb +77 -0
  10. data/app/controllers/dcm4chee/api/v1/series_controller.rb +69 -0
  11. data/app/controllers/dcm4chee/api/v1/source_aets_controller.rb +29 -0
  12. data/app/controllers/dcm4chee/api/v1/studies_controller.rb +69 -0
  13. data/app/controllers/dcm4chee/api/v1/trashed_instances_controller.rb +82 -0
  14. data/app/controllers/dcm4chee/api/v1/trashed_patients_controller.rb +84 -0
  15. data/app/controllers/dcm4chee/api/v1/trashed_series_controller.rb +81 -0
  16. data/app/controllers/dcm4chee/api/v1/trashed_studies_controller.rb +81 -0
  17. data/app/controllers/dcm4chee/api/v1/trashes_controller.rb +23 -0
  18. data/app/controllers/dcm4chee/application_controller.rb +4 -0
  19. data/app/models/dcm4chee/application_entity.rb +129 -0
  20. data/app/models/dcm4chee/dicom_file.rb +62 -0
  21. data/app/models/dcm4chee/file_system.rb +95 -0
  22. data/app/models/dcm4chee/instance.rb +69 -0
  23. data/app/models/dcm4chee/modality.rb +17 -0
  24. data/app/models/dcm4chee/patient.rb +42 -0
  25. data/app/models/dcm4chee/series.rb +78 -0
  26. data/app/models/dcm4chee/source_aet.rb +17 -0
  27. data/app/models/dcm4chee/study.rb +60 -0
  28. data/app/models/dcm4chee/trashed_dicom_file.rb +58 -0
  29. data/app/models/dcm4chee/trashed_instance.rb +56 -0
  30. data/app/models/dcm4chee/trashed_patient.rb +40 -0
  31. data/app/models/dcm4chee/trashed_series.rb +50 -0
  32. data/app/models/dcm4chee/trashed_study.rb +40 -0
  33. data/config/routes.rb +27 -0
  34. data/lib/dcm4chee.rb +58 -0
  35. data/lib/dcm4chee/api_constraints.rb +12 -0
  36. data/lib/dcm4chee/dicom_object_manager.rb +48 -0
  37. data/lib/dcm4chee/engine.rb +5 -0
  38. data/lib/dcm4chee/models/has_dicom_object.rb +71 -0
  39. data/lib/dcm4chee/services/application_entity_service.rb +113 -0
  40. data/lib/dcm4chee/services/content_edit_service.rb +37 -0
  41. data/lib/dcm4chee/services/file_system_management.rb +16 -0
  42. data/lib/dcm4chee/services/mbean.rb +11 -0
  43. data/lib/dcm4chee/services/move_scu_service.rb +54 -0
  44. data/lib/dcm4chee/version.rb +3 -0
  45. data/lib/tasks/dcm4chee_tasks.rake +4 -0
  46. metadata +241 -0
@@ -0,0 +1,81 @@
1
+ # -*- encoding: utf-8 -*-
2
+ module Dcm4chee
3
+ module Api
4
+ module V1
5
+ class TrashedStudiesController < BaseController
6
+ respond_to :json
7
+
8
+ # Search for studies from the trash. Supported querying
9
+ # conditions:
10
+ # trashed_patient_id
11
+ #
12
+ # Check {DataMapper::Searcher::ClassMethods} for supported
13
+ # querying operators.
14
+ #
15
+ # @example
16
+ # # Request
17
+ # GET /api/trashed_studies?q[trashed_patient_id]=... HTTP/1.1
18
+ # Accept: application/vnd.menglifang.org; version=1
19
+ #
20
+ # # Response
21
+ # HTTP/1.1 200 OK
22
+ # {
23
+ # "trashed_studies": [{
24
+ # "id": ...,
25
+ # "trashed_patient_id": ...,
26
+ # "study_iuid": ...,
27
+ # "accession_no": ...,
28
+ # "dcm_elements": [{
29
+ # "name": ...,
30
+ # "value": ...,
31
+ # "tag": ...,
32
+ # "value_representation": ...,
33
+ # "length": ...
34
+ # }, ...]
35
+ # }, ...]
36
+ # }
37
+ def index
38
+ studies = TrashedStudy.search(params[:q])
39
+
40
+ respond_with trashed_studies: studies
41
+ end
42
+
43
+ # Move a study to the trash including the related series, instances and files.
44
+ #
45
+ # @example
46
+ # # Request
47
+ # POST /api/trashed_studies HTTP/1.1
48
+ # Accept: application/vnd.menglifang.org; version=1
49
+ # Content-Type: application/json
50
+ #
51
+ # { "study_id": ... }
52
+ #
53
+ # # Response
54
+ # HTTP/1.1 201 Created
55
+ def create
56
+ study = Study.get!(params[:study_id])
57
+ study.move_to_trash
58
+
59
+ head :created
60
+ end
61
+
62
+ # Delete a study from the trash.
63
+ #
64
+ # @example
65
+ # # Request
66
+ # DELETE /api/trashed_studies/... HTTP/1.1
67
+ # Accept: application/vnd.menglifang.org; version=1
68
+ #
69
+ # # Response
70
+ # HTTP/1.1 200 OK
71
+ def destroy
72
+ study = TrashedStudy.get!(params[:id])
73
+ study.remove_from_trash
74
+
75
+ head :ok
76
+ end
77
+
78
+ end
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,23 @@
1
+ # -*- encoding: utf-8 -*-
2
+ module Dcm4chee
3
+ module Api
4
+ module V1
5
+ class TrashesController < BaseController
6
+ # Clean up the trash.
7
+ #
8
+ # @example
9
+ # # Request
10
+ # DELETE /api/trash HTTP/1.1
11
+ # Accept: application/vnd.menglifang.org; version=1
12
+ #
13
+ # # Response
14
+ # HTTP/1.1 200 OK
15
+ def destroy
16
+ Dcm4chee.content_edit_service.empty_trash
17
+
18
+ head :ok
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,4 @@
1
+ module Dcm4chee
2
+ class ApplicationController < ActionController::Base
3
+ end
4
+ end
@@ -0,0 +1,129 @@
1
+ # -*- encoding: utf-8 -*-
2
+ module Dcm4chee
3
+ class ApplicationEntity
4
+ include DataMapper::Resource
5
+
6
+ storage_names[Dcm4chee.config.repository_name] = 'ae'
7
+
8
+ # @return [Integer] primary key
9
+ property :id, Serial, field: 'pk'
10
+
11
+ # @return [String] name
12
+ property :title, String, field: 'aet'
13
+
14
+ # @return [String] hostname or ip address
15
+ property :host, String, field: 'hostname'
16
+
17
+ # @return [Integer] port
18
+ property :port, Integer, field: 'port'
19
+
20
+ # @return [String] cipher_suites, available values:SSL_RSA_WITH_NULL_SHA, TLS_RSA_WITH_AES_128_CBC_SHA, SSL_RSA_WITH_3DES_EDE_CBC_SHA
21
+ # Multi-suites should be specified in comma-separated format.
22
+ property :cipher_suites, String, field: 'cipher_suites'
23
+
24
+ # @return [String] issuer of the patient id
25
+ property :patient_id_issuer, String, field: 'pat_id_issuer'
26
+
27
+ # @return [String] issuer of the accession number
28
+ property :accession_number_issuer, String, field: 'acc_no_issuer'
29
+
30
+ # @return [String] username
31
+ property :username, String, field: 'user_id'
32
+
33
+ # @return [String] password
34
+ property :password, String, field: 'passwd'
35
+
36
+ # @return [String] group of the file system
37
+ property :fs_group, String, field: 'fs_group_id', default: 'ONLINE_STORAGE'
38
+
39
+ # @return [String] group of the application entity
40
+ property :group, String, field: 'ae_group'
41
+
42
+ # @return [String] description
43
+ property :description, String, field: 'ae_desc'
44
+
45
+ # @return [String] url of WADO
46
+ property :wado_url, String, field: 'wado_url'
47
+
48
+ # @return [String] station name
49
+ property :station_name, String, field: 'station_name'
50
+
51
+ # @return [String] institution
52
+ property :institution, String, field: 'institution'
53
+
54
+ # @return [String] department
55
+ property :department, String, field: 'department'
56
+
57
+ # @return [String] installed or not
58
+ property :installed, String, field: 'installed'
59
+
60
+ # Update an application entity through AEService of dcm4chee.
61
+ #
62
+ # @param [Hash] attrs Attributes of the application entity
63
+ def update_by_service(attrs = {})
64
+ params = [
65
+ id,
66
+ attrs[:title] || title,
67
+ attrs[:host] || host,
68
+ attrs[:port] || port,
69
+ attrs[:cipher_suites] || cipher_suites,
70
+ attrs[:patient_id_issuer] || patient_id_issuer,
71
+ attrs[:accession_number_issuer] || accession_number_issuer,
72
+ attrs[:username] || username,
73
+ attrs[:password] || password,
74
+ attrs[:fs_group] || fs_group,
75
+ attrs[:group] || group,
76
+ attrs[:description] || description,
77
+ attrs[:wado_url] || wado_url,
78
+ attrs[:station_name] || station_name,
79
+ attrs[:institution] || institution,
80
+ attrs[:department] || department,
81
+ attrs[:installed] || installed,
82
+ true
83
+ ]
84
+ Dcm4chee.application_entity_service.update_ae(params)
85
+ reload
86
+
87
+ self
88
+ end
89
+
90
+ # Delete an application entity through AEService of dcm4chee
91
+ def destroy_by_service
92
+ Dcm4chee.application_entity_service.remove_ae(title)
93
+ end
94
+
95
+ class << self
96
+ # Create an application entity through AEService of dcm4chee.
97
+ #
98
+ # @param [Hash] attrs Attributes of the new application entity
99
+ def create_by_service(attrs = {})
100
+ params = [
101
+ attrs[:title],
102
+ attrs[:host],
103
+ attrs[:port],
104
+ attrs[:cipher_suites],
105
+ attrs[:patient_id_issuer],
106
+ attrs[:accession_number_issuer],
107
+ attrs[:username],
108
+ attrs[:password],
109
+ attrs[:fs_group],
110
+ attrs[:group],
111
+ attrs[:description],
112
+ attrs[:wado_url],
113
+ attrs[:station_name],
114
+ attrs[:institution],
115
+ attrs[:department],
116
+ !!(attrs[:installed]),
117
+ true
118
+ ]
119
+ Dcm4chee.application_entity_service.add_ae(params)
120
+
121
+ first(title: attrs[:title])
122
+ end
123
+
124
+ def repository(name = nil, &block)
125
+ super(Dcm4chee.config.repository_name, &block)
126
+ end
127
+ end
128
+ end
129
+ end
@@ -0,0 +1,62 @@
1
+ # -*- encoding: utf-8 -*-
2
+ module Dcm4chee
3
+ class DicomFile
4
+ include DataMapper::Resource
5
+ include HasDicomObject
6
+
7
+ storage_names[Dcm4chee.config.repository_name] = 'files'
8
+
9
+ # @return [Integer] primary key
10
+ property :id, Serial, field: 'pk'
11
+
12
+ # @return [Integer] foreign key of {Instance}
13
+ property :instance_id, Integer, field: 'instance_fk'
14
+
15
+ # @return [Integer] foreign key of {FileSystem}
16
+ property :file_system_id, Integer, field: 'filesystem_fk'
17
+
18
+ # @return [String] path
19
+ property :path, Text, field: 'filepath'
20
+
21
+ # @return [String] DICOM transfer syntax UID(0002,0010)
22
+ property :transfer_syntax_uid, Text, field: 'file_tsuid'
23
+
24
+ # @return [String] MD5 of the file
25
+ property :md5, String, field: 'file_md5'
26
+
27
+ # @return [Integer] file size
28
+ property :size, Integer, field: 'file_size'
29
+
30
+ # Available values:
31
+ # -4: QUERY_HSM_FAILED
32
+ # -3: MD5_CHECK_FAILED
33
+ # -2: VERIFY_COMPRESS_FAILED
34
+ # -1: COMPRESS_FAILED
35
+ # 0: DEFAULT
36
+ # 1: TO_ARCHIVE
37
+ # 2: ARCHIVED
38
+ # 3: COMPRESSING
39
+ #
40
+ # @return [Integer] file status
41
+ property :availability, Enum[-4, -3, -2, -1, 0, 1, 2, 3], field: 'file_status'
42
+
43
+ # @return [DateTime] last MD5 checking time of the file
44
+ property :md5_checked_at, DateTime, field: 'md5_check_time'
45
+
46
+ # @return [DateTime] created time
47
+ property :created_at, DateTime, field: 'created_time'
48
+
49
+ belongs_to :instance, 'Dcm4chee::Instance'
50
+ belongs_to :file_system, 'Dcm4chee::FileSystem'
51
+
52
+ # Load the dicom object
53
+ # @return [DICOM::DObject] DICOM object
54
+ def dcm
55
+ @dcm ||= DICOM::DObject.read(File.join(file_system.path, path))
56
+ end
57
+
58
+ def self.repository(name = nil, &block)
59
+ super(Dcm4chee.config.repository_name, &block)
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,95 @@
1
+ # -*- encoding: utf-8 -*-
2
+ module Dcm4chee
3
+ class FileSystem
4
+ include DataMapper::Resource
5
+
6
+ storage_names[Dcm4chee.config.repository_name] = 'filesystem'
7
+
8
+ # @return [Integer] primary key
9
+ property :id, Serial, field: 'pk'
10
+
11
+ # @return [String] path of the directory
12
+ property :path, String, field: 'dirpath'
13
+
14
+ # @return [Integer] type of the file system
15
+ # 0: ONLINE
16
+ # 1: NEARLINE
17
+ # 2: OFFLINE
18
+ property :availability, Integer, field: 'availability'
19
+
20
+ has n, :dicom_files, 'Dcm4chee::DicomFile'
21
+ has n, :trashed_dicom_files, 'Dcm4chee::TrashedDicomFile'
22
+
23
+ # Check whether the path is relative or absolute. The default path of the relative one is `#{Dcm4chee.config.server_home}/server/default`
24
+ def path
25
+ p = self[:path]
26
+
27
+ return p if p.start_with?('/')
28
+
29
+ raise 'Home of dcm4chee must be set' unless Dcm4chee.config.server_home
30
+
31
+ File.join(Dcm4chee.config.server_home, 'server/default', p)
32
+ end
33
+
34
+ # @return [Integer] Total space of the file system(in bytes)
35
+ def total_space
36
+ status.block_size * status.blocks
37
+ end
38
+
39
+ # @return [Integer] Available space of the file system(in bytes)
40
+ def free_space
41
+ status.block_size * status.blocks_available
42
+ end
43
+
44
+ # @return [Integer] Used space of the file system(in bytes)
45
+ def used_space
46
+ total_space - free_space
47
+ end
48
+
49
+ # @return [Integer] Minimum free space of the file system. If the free space is under the limit, dcm4chee will use the next one instead.
50
+ def min_free_space
51
+ @min_free_space ||= Dcm4chee.file_system_management.minimum_free_disk_space_bytes
52
+ end
53
+
54
+ # @return [Integer] Expected space per day(in bytes)
55
+ def expected_space_per_day
56
+ @expected_space_per_day ||= Dcm4chee.file_system_management.expected_data_volume_per_day_bytes
57
+ end
58
+
59
+ # @return [Integer] Remaining days of the file system
60
+ def remaining_days
61
+ @remaining_days ||= (free_space - min_free_space) / expected_space_per_day
62
+ end
63
+
64
+ # @return [Hash] Serialized data
65
+ def as_json(opts = {})
66
+ opts[:exclude] ||= []
67
+ opts[:exclude] << :availability
68
+
69
+ opts[:methods] ||= []
70
+ opts[:methods].concat([:path, :total_space, :free_space,
71
+ :used_space, :min_free_space,
72
+ :expected_space_per_day, :remaining_days])
73
+
74
+ super(opts)
75
+ end
76
+
77
+ class << self
78
+ # @return [DataMapper::Collection] All online file systems
79
+ def online
80
+ all(availability: 0)
81
+ end
82
+
83
+ def repository(name = nil, &block)
84
+ super(Dcm4chee.config.repository_name, &block)
85
+ end
86
+ end
87
+
88
+ private
89
+
90
+ # @return [Sys::Filesystem] Status of the file system
91
+ def status
92
+ @status ||= Sys::Filesystem.stat(path)
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,69 @@
1
+ # -*- encoding: utf-8 -*-
2
+ module Dcm4chee
3
+ class Instance
4
+ include DataMapper::Resource
5
+ include DataMapper::Searcher
6
+
7
+ include HasDicomObject
8
+
9
+ storage_names[Dcm4chee.config.repository_name] = 'instance'
10
+
11
+ # @return [Integer] primary key
12
+ property :id, Serial, field: 'pk'
13
+
14
+ # @return [Integer] foreign key of {Series}
15
+ property :series_id, Integer, field: 'series_fk'
16
+
17
+ # @return [DateTime] created time
18
+ property :created_at, DateTime, field: 'created_time'
19
+
20
+ # @return [String] DICOM Instance NO(0020,0013)
21
+ property :instance_no, String, field: 'inst_no'
22
+
23
+ # @return [String] DICOM SOP Instance UID(0008,0018)
24
+ property :sop_iuid, Text, field: 'sop_iuid'
25
+
26
+ # @return [String] DICOM SOP Class UID(0008,0016)
27
+ property :sop_cuid, Text, field: 'sop_cuid'
28
+
29
+ # DICOM Instance Availability(0008,0056)
30
+ # 0: ONLINE
31
+ # 1: NEARLINE
32
+ # 2: OFFLINE
33
+ # 3: UNAVAILABLE
34
+ #
35
+ # @return [Integer] DICOM Integer Availability
36
+ property :availability, Enum[0, 1, 2, 3], field: 'availability'
37
+
38
+ # TODO Added description
39
+
40
+ dicom_field 'inst_attrs'
41
+
42
+ belongs_to :series, 'Dcm4chee::Series'
43
+ has n, :dicom_files, 'Dcm4chee::DicomFile'
44
+
45
+ def study_iuid
46
+ series.study.study_iuid
47
+ end
48
+
49
+ def series_iuid
50
+ series.series_iuid
51
+ end
52
+
53
+ def move_to_trash
54
+ Dcm4chee.content_edit_service.move_instance_to_trash(id)
55
+ end
56
+
57
+ def as_json(opts = {})
58
+ opts[:methods] ||= []
59
+ opts[:methods] << :series_iuid
60
+ opts[:methods] << :study_iuid
61
+
62
+ super(opts)
63
+ end
64
+
65
+ def self.repository(name = nil, &block)
66
+ super(Dcm4chee.config.repository_name, &block)
67
+ end
68
+ end
69
+ end