ddr-models 2.0.1 → 2.1.0.rc1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (92) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +23 -17
  3. data/app/models/collection.rb +1 -35
  4. data/ddr-models.gemspec +2 -1
  5. data/lib/ddr/actions.rb +1 -0
  6. data/lib/ddr/actions/virus_check.rb +28 -0
  7. data/lib/ddr/auth.rb +4 -0
  8. data/lib/ddr/auth/ability_definitions/datastream_ability_definitions.rb +7 -5
  9. data/lib/ddr/auth/grouper_gateway.rb +9 -1
  10. data/lib/ddr/auth/permissions.rb +2 -1
  11. data/lib/ddr/auth/role_based_access_controls_enforcement.rb +5 -5
  12. data/lib/ddr/auth/roles/role_types.rb +2 -1
  13. data/lib/ddr/datastreams.rb +2 -2
  14. data/lib/ddr/datastreams/administrative_metadata_datastream.rb +27 -14
  15. data/lib/ddr/datastreams/datastream_behavior.rb +13 -0
  16. data/lib/ddr/datastreams/fits_datastream.rb +88 -0
  17. data/lib/ddr/derivatives/png_generator.rb +2 -0
  18. data/lib/ddr/derivatives/ptif_generator.rb +2 -0
  19. data/lib/ddr/events/fixity_check_event.rb +2 -2
  20. data/lib/ddr/events/virus_check_event.rb +2 -14
  21. data/lib/ddr/index.rb +29 -0
  22. data/lib/ddr/index/abstract_query_result.rb +23 -0
  23. data/lib/ddr/index/connection.rb +17 -0
  24. data/lib/ddr/index/csv_query_result.rb +61 -0
  25. data/lib/ddr/index/document_builder.rb +9 -0
  26. data/lib/ddr/index/field.rb +23 -0
  27. data/lib/ddr/index/fields.rb +83 -0
  28. data/lib/ddr/index/filter.rb +48 -0
  29. data/lib/ddr/index/filters.rb +19 -0
  30. data/lib/ddr/index/legacy_license_fields.rb +14 -0
  31. data/lib/ddr/index/query.rb +35 -0
  32. data/lib/ddr/index/query_builder.rb +74 -0
  33. data/lib/ddr/index/query_clause.rb +52 -0
  34. data/lib/ddr/index/query_result.rb +70 -0
  35. data/lib/ddr/index/query_value.rb +16 -0
  36. data/lib/ddr/index/response.rb +13 -0
  37. data/lib/ddr/index/unique_key_field.rb +12 -0
  38. data/lib/ddr/index_fields.rb +7 -53
  39. data/lib/ddr/jobs.rb +1 -1
  40. data/lib/ddr/jobs/fits_file_characterization.rb +51 -0
  41. data/lib/ddr/managers.rb +1 -0
  42. data/lib/ddr/managers/technical_metadata_manager.rb +104 -0
  43. data/lib/ddr/models.rb +39 -23
  44. data/lib/ddr/models/base.rb +0 -2
  45. data/lib/ddr/models/describable.rb +1 -1
  46. data/lib/ddr/models/effective_license.rb +9 -0
  47. data/lib/ddr/models/engine.rb +13 -0
  48. data/lib/ddr/models/file_management.rb +157 -160
  49. data/lib/ddr/models/governable.rb +0 -4
  50. data/lib/ddr/models/has_admin_metadata.rb +80 -72
  51. data/lib/ddr/models/has_children.rb +1 -1
  52. data/lib/ddr/models/has_content.rb +18 -0
  53. data/lib/ddr/models/has_struct_metadata.rb +5 -1
  54. data/lib/ddr/models/indexing.rb +32 -20
  55. data/lib/ddr/models/inherited_license.rb +13 -0
  56. data/lib/ddr/models/license.rb +38 -0
  57. data/lib/ddr/models/solr_document.rb +195 -211
  58. data/lib/ddr/models/version.rb +1 -1
  59. data/lib/ddr/models/year_facet.rb +154 -0
  60. data/lib/ddr/utils.rb +13 -1
  61. data/lib/ddr/vocab/roles.rb +0 -10
  62. data/spec/controllers/including_role_based_access_controls_enforcement_spec.rb +4 -4
  63. data/spec/datastreams/fits_datastream_spec.rb +84 -0
  64. data/spec/fixtures/fits/document.xml +65 -0
  65. data/spec/fixtures/fits/image.xml +59 -0
  66. data/spec/index/filter_spec.rb +47 -0
  67. data/spec/index/filters_spec.rb +17 -0
  68. data/spec/index/query_spec.rb +19 -0
  69. data/spec/jobs/fits_file_characterization_spec.rb +52 -0
  70. data/spec/managers/technical_metadata_manager_spec.rb +140 -0
  71. data/spec/models/active_fedora_datastream_spec.rb +44 -0
  72. data/spec/models/collection_spec.rb +7 -12
  73. data/spec/models/component_spec.rb +3 -6
  74. data/spec/models/effective_license_spec.rb +49 -0
  75. data/spec/models/has_admin_metadata_spec.rb +143 -194
  76. data/spec/models/has_struct_metadata_spec.rb +2 -2
  77. data/spec/models/indexing_spec.rb +40 -0
  78. data/spec/models/solr_document_spec.rb +96 -37
  79. data/spec/models/year_facet_spec.rb +65 -0
  80. data/spec/spec_helper.rb +1 -7
  81. data/spec/support/shared_examples_for_ddr_models.rb +0 -2
  82. data/spec/support/shared_examples_for_has_content.rb +37 -3
  83. metadata +79 -32
  84. data/lib/ddr/datastreams/properties_datastream.rb +0 -25
  85. data/lib/ddr/jobs/migrate_legacy_authorization.rb +0 -23
  86. data/lib/ddr/models/has_properties.rb +0 -15
  87. data/lib/ddr/models/licensable.rb +0 -28
  88. data/spec/auth/legacy_authorization_spec.rb +0 -94
  89. data/spec/auth/legacy_roles_spec.rb +0 -32
  90. data/spec/jobs/migrate_legacy_authorization_spec.rb +0 -43
  91. data/spec/support/shared_examples_for_has_properties.rb +0 -5
  92. data/spec/support/shared_examples_for_licensable.rb +0 -15
@@ -5,8 +5,6 @@ module Ddr
5
5
  include Describable
6
6
  include Governable
7
7
  include AccessControllable
8
- include Licensable
9
- include HasProperties
10
8
  include HasThumbnail
11
9
  include EventLoggable
12
10
  include FixityCheckable
@@ -72,7 +72,7 @@ module Ddr
72
72
 
73
73
  module ClassMethods
74
74
  def find_by_identifier(identifier)
75
- find(Ddr::IndexFields::IDENTIFIER_ALL => identifier)
75
+ find(Ddr::Index::Fields::IDENTIFIER_ALL => identifier)
76
76
  end
77
77
  end
78
78
 
@@ -0,0 +1,9 @@
1
+ module Ddr::Models
2
+ class EffectiveLicense
3
+
4
+ def self.call(obj)
5
+ License.call(obj) || InheritedLicense.call(obj)
6
+ end
7
+
8
+ end
9
+ end
@@ -79,6 +79,19 @@ module Ddr
79
79
  end
80
80
  end
81
81
 
82
+ initializer "fits_home" do
83
+ Ddr::Models.fits_home = ENV["FITS_HOME"]
84
+ end
85
+
86
+ initializer "ddr_antivirus" do
87
+ require "ddr-antivirus"
88
+ if Rails.env.test?
89
+ Ddr::Antivirus.test_mode!
90
+ else
91
+ Ddr::Antivirus.scanner_adapter = :clamd
92
+ end
93
+ end
94
+
82
95
  end
83
96
  end
84
97
  end
@@ -1,198 +1,195 @@
1
- require "ddr-antivirus"
1
+ module Ddr::Models
2
+ module FileManagement
3
+ extend ActiveSupport::Concern
2
4
 
3
- module Ddr
4
- module Models
5
- module FileManagement
6
- extend ActiveSupport::Concern
5
+ EXTERNAL_FILE_PERMISSIONS = 0644
7
6
 
8
- EXTERNAL_FILE_PERMISSIONS = 0644
7
+ included do
8
+ attr_accessor :file_to_add
9
9
 
10
- included do
11
- attr_accessor :file_to_add
10
+ define_model_callbacks :add_file
11
+ before_add_file :virus_scan
12
12
 
13
- define_model_callbacks :add_file
14
- before_add_file :virus_scan
13
+ after_save :notify_virus_scan_results
15
14
 
16
- after_save :notify_virus_scan_results
17
-
18
- # Deleting the datastream external files on destroying the object can't
19
- # be handled with a datastream around_destroy callback.
20
- # See https://groups.google.com/d/msg/hydra-tech/xJaZr2wVhbg/4iafvso98w8J
21
- around_destroy :cleanup_external_files_on_destroy
22
- end
15
+ # Deleting the datastream external files on destroying the object can't
16
+ # be handled with a datastream around_destroy callback.
17
+ # See https://groups.google.com/d/msg/hydra-tech/xJaZr2wVhbg/4iafvso98w8J
18
+ around_destroy :cleanup_external_files_on_destroy
19
+ end
23
20
 
24
- # add_file(file, dsid, opts={})
25
- #
26
- # Comparable to Hydra::ModelMethods#add_file(file, dsid, file_name)
27
- #
28
- # Options:
29
- #
30
- # :mime_type - Explicit mime type to set (otherwise discerned from file path or name)
31
- #
32
- # :original_name - A String value will be understood as the original name of the file.
33
- # `false` or `nil` indicate that the file basename is not the original
34
- # name. Default processing will take the file basename as the original
35
- # name.
36
- #
37
- # :external - Add to file to external datastream. Not required for datastream specs
38
- # where :control_group=>"E".
39
- #
40
- # :use_original - For external datastream file, do not copy file to new file path,
41
- # but use in place (set dsLocation to file URI for current path.
42
- def add_file file, dsid, opts={}
43
- opts[:mime_type] ||= Ddr::Utils.mime_type_for(file)
44
-
45
- # @file_to_add is set for callbacks to access the data
46
- original_name = opts.fetch(:original_name, Ddr::Utils.file_name_for(file))
47
- self.file_to_add = FileToAdd.new(file, dsid, original_name)
48
-
49
- run_callbacks(:add_file) do
50
- if opts.delete(:external) || datastreams.include?(dsid) && datastreams[dsid].external?
51
- add_external_file(file, dsid, opts)
52
- else
53
- file = File.new(file, "rb") if Ddr::Utils.file_path?(file)
54
- # ActiveFedora method accepts file-like objects, not paths
55
- add_file_datastream(file, dsid: dsid, mimeType: opts[:mime_type])
56
- end
21
+ # add_file(file, dsid, opts={})
22
+ #
23
+ # Comparable to Hydra::ModelMethods#add_file(file, dsid, file_name)
24
+ #
25
+ # Options:
26
+ #
27
+ # :mime_type - Explicit mime type to set (otherwise discerned from file path or name)
28
+ #
29
+ # :original_name - A String value will be understood as the original name of the file.
30
+ # `false` or `nil` indicate that the file basename is not the original
31
+ # name. Default processing will take the file basename as the original
32
+ # name.
33
+ #
34
+ # :external - Add to file to external datastream. Not required for datastream specs
35
+ # where :control_group=>"E".
36
+ #
37
+ # :use_original - For external datastream file, do not copy file to new file path,
38
+ # but use in place (set dsLocation to file URI for current path.
39
+ def add_file file, dsid, opts={}
40
+ opts[:mime_type] ||= Ddr::Utils.mime_type_for(file)
41
+
42
+ # @file_to_add is set for callbacks to access the data
43
+ original_name = opts.fetch(:original_name, Ddr::Utils.file_name_for(file))
44
+ self.file_to_add = FileToAdd.new(file, dsid, original_name)
45
+
46
+ run_callbacks(:add_file) do
47
+ if opts.delete(:external) || datastreams.include?(dsid) && datastreams[dsid].external?
48
+ add_external_file(file, dsid, opts)
49
+ else
50
+ file = File.new(file, "rb") if Ddr::Utils.file_path?(file)
51
+ # ActiveFedora method accepts file-like objects, not paths
52
+ add_file_datastream(file, dsid: dsid, mimeType: opts[:mime_type])
57
53
  end
58
-
59
- # clear the instance data
60
- self.file_to_add = nil
61
54
  end
62
55
 
63
- # Normally this method should not be called directly. Call `add_file` with dsid for
64
- # external datastream id, or with `:external=>true` option if no spec for dsid.
65
- def add_external_file file, dsid, opts={}
66
- file_path = Ddr::Utils.file_path(file) # raises ArgumentError
67
-
68
- # Retrieve or create the datastream
69
- ds = datastreams.include?(dsid) ? datastreams[dsid] : add_external_datastream(dsid)
56
+ # clear the instance data
57
+ self.file_to_add = nil
58
+ end
70
59
 
71
- unless ds.external?
72
- raise ArgumentError, "Cannot add external file to datastream with controlGroup \"#{ds.controlGroup}\""
73
- end
60
+ # Normally this method should not be called directly. Call `add_file` with dsid for
61
+ # external datastream id, or with `:external=>true` option if no spec for dsid.
62
+ def add_external_file file, dsid, opts={}
63
+ file_path = Ddr::Utils.file_path(file) # raises ArgumentError
74
64
 
75
- if ds.dsLocation_changed?
76
- raise Ddr::Models::Error, "Cannot add external file to datastream when dsLocation change is pending."
77
- end
65
+ # Retrieve or create the datastream
66
+ ds = datastreams.include?(dsid) ? datastreams[dsid] : add_external_datastream(dsid)
78
67
 
79
- # Set the MIME type
80
- # The :mime_type option will be present when called from `add_file`.
81
- # The fallback is there in case `add_external_file` is called directly.
82
- ds.mimeType = opts[:mime_type] || Ddr::Utils.mime_type_for(file, file_path)
68
+ unless ds.external?
69
+ raise ArgumentError, "Cannot add external file to datastream with controlGroup \"#{ds.controlGroup}\""
70
+ end
83
71
 
84
- # Copy the file to storage unless we're using the original
85
- if opts[:use_original]
86
- raise Ddr::Models::Error, "Cannot add file to repository that is owned by another user." unless File.owned?(file_path)
87
- store_path = file_path
88
- else
89
- # generate new storage path for file
90
- store_path = create_external_file_path!(ds)
91
- # copy the original file to the storage location
92
- FileUtils.cp file_path, store_path
93
- end
72
+ if ds.dsLocation_changed?
73
+ raise Ddr::Models::Error, "Cannot add external file to datastream when dsLocation change is pending."
74
+ end
94
75
 
95
- # set appropriate permissions on the file
96
- set_external_file_permissions!(store_path)
76
+ # Set the MIME type
77
+ # The :mime_type option will be present when called from `add_file`.
78
+ # The fallback is there in case `add_external_file` is called directly.
79
+ ds.mimeType = opts[:mime_type] || Ddr::Utils.mime_type_for(file, file_path)
97
80
 
98
- # set dsLocation to file URI for storage path
99
- ds.dsLocation = Ddr::Utils.path_to_uri(store_path)
81
+ # Copy the file to storage unless we're using the original
82
+ if opts[:use_original]
83
+ raise Ddr::Models::Error, "Cannot add file to repository that is owned by another user." unless File.owned?(file_path)
84
+ store_path = file_path
85
+ else
86
+ # generate new storage path for file
87
+ store_path = create_external_file_path!(ds)
88
+ # copy the original file to the storage location
89
+ FileUtils.cp file_path, store_path
100
90
  end
101
91
 
102
- # Create directory (if necessary) for newly generated file path and return path
103
- def create_external_file_path! ds
104
- file_path = generate_external_file_path(ds)
105
- FileUtils.mkdir_p(File.dirname(file_path))
106
- file_path
107
- end
92
+ # set appropriate permissions on the file
93
+ set_external_file_permissions!(store_path)
108
94
 
109
- #
110
- # Generates a new external file storage location
111
- #
112
- # => {external_file_store}/1/e/69/1e691815-0631-4f9b-8e23-2dfb2eec9c70
113
- #
114
- def generate_external_file_path ds
115
- file_name = generate_external_file_name(ds)
116
- File.join(external_file_store(ds.dsid), generate_external_directory_subpath, file_name)
117
- end
95
+ # set dsLocation to file URI for storage path
96
+ ds.dsLocation = Ddr::Utils.path_to_uri(store_path)
97
+ end
118
98
 
119
- def external_datastreams
120
- datastreams.values.select { |ds| ds.external? }
121
- end
99
+ # Create directory (if necessary) for newly generated file path and return path
100
+ def create_external_file_path! ds
101
+ file_path = generate_external_file_path(ds)
102
+ FileUtils.mkdir_p(File.dirname(file_path))
103
+ file_path
104
+ end
122
105
 
123
- def external_datastream_file_paths
124
- external_datastreams.map(&:file_paths).flatten
125
- end
106
+ #
107
+ # Generates a new external file storage location
108
+ #
109
+ # => {external_file_store}/1/e/69/1e691815-0631-4f9b-8e23-2dfb2eec9c70
110
+ #
111
+ def generate_external_file_path ds
112
+ file_name = generate_external_file_name(ds)
113
+ File.join(external_file_store(ds.dsid), generate_external_directory_subpath, file_name)
114
+ end
126
115
 
127
- def add_external_datastream dsid, opts={}
128
- klass = self.class.datastream_class_for_name(dsid)
129
- datastream = create_datastream(klass, dsid, controlGroup: "E")
130
- add_datastream(datastream)
131
- self.class.build_datastream_accessor(dsid)
132
- datastream
133
- end
116
+ def external_datastreams
117
+ datastreams.values.select { |ds| ds.external? }
118
+ end
134
119
 
135
- protected
120
+ def external_datastream_file_paths
121
+ external_datastreams.map(&:file_paths).flatten
122
+ end
136
123
 
137
- FileToAdd = Struct.new(:file, :dsid, :original_name)
124
+ def add_external_datastream dsid, opts={}
125
+ klass = self.class.datastream_class_for_name(dsid)
126
+ datastream = create_datastream(klass, dsid, controlGroup: "E")
127
+ add_datastream(datastream)
128
+ self.class.build_datastream_accessor(dsid)
129
+ datastream
130
+ end
138
131
 
139
- def virus_scan_results
140
- @virus_scan_results ||= []
141
- end
132
+ protected
142
133
 
143
- def virus_scan
144
- path = Ddr::Utils.file_path(file_to_add[:file])
145
- virus_scan_results << Ddr::Antivirus::Scanner.scan(path)
146
- rescue ArgumentError => e # file is a blob
147
- logger.error(e)
148
- end
134
+ FileToAdd = Struct.new(:file, :dsid, :original_name)
149
135
 
150
- def notify_virus_scan_results
151
- while result = virus_scan_results.shift
152
- ActiveSupport::Notifications.instrument(Ddr::Notifications::VIRUS_CHECK, result: result, pid: pid)
153
- end
154
- end
136
+ def virus_scan_results
137
+ @virus_scan_results ||= []
138
+ end
155
139
 
156
- def external_file_store dsid
157
- case dsid
158
- when Ddr::Datastreams::MULTIRES_IMAGE
159
- Ddr::Models.multires_image_external_file_store
160
- else
161
- Ddr::Models.external_file_store
162
- end
163
- end
140
+ def virus_scan
141
+ path = Ddr::Utils.file_path(file_to_add[:file])
142
+ virus_scan_results << Ddr::Actions::VirusCheck.call(path)
143
+ rescue ArgumentError => e # file is a blob
144
+ logger.error(e)
145
+ end
164
146
 
165
- def set_external_file_permissions! file_path
166
- File.chmod(EXTERNAL_FILE_PERMISSIONS, file_path)
147
+ def notify_virus_scan_results
148
+ while result = virus_scan_results.shift
149
+ result.merge! pid: pid
150
+ ActiveSupport::Notifications.instrument(Ddr::Notifications::VIRUS_CHECK, result)
167
151
  end
152
+ end
168
153
 
169
- def generate_external_file_name ds
170
- content_file_name = Ddr::Utils::sanitize_filename(original_filename) || datastreams[ds.dsid].default_file_name
171
- case ds.dsid
172
- when Ddr::Datastreams::MULTIRES_IMAGE
173
- case ds.mimeType
174
- when "image/tiff"
175
- "#{File.basename(content_file_name, File.extname(content_file_name))}.ptif"
176
- end
177
- else
178
- content_file_name
179
- end
154
+ def external_file_store dsid
155
+ case dsid
156
+ when Ddr::Datastreams::MULTIRES_IMAGE
157
+ Ddr::Models.multires_image_external_file_store
158
+ else
159
+ Ddr::Models.external_file_store
180
160
  end
161
+ end
181
162
 
182
- def generate_external_directory_subpath
183
- subdir = SecureRandom.uuid
184
- m = Ddr::Models.external_file_subpath_regexp.match(subdir)
185
- raise "File name does not match external file subpath pattern: #{file_name}" unless m
186
- subpath_segments = m.to_a[1..-1]
187
- File.join *subpath_segments, subdir
188
- end
163
+ def set_external_file_permissions! file_path
164
+ File.chmod(EXTERNAL_FILE_PERMISSIONS, file_path)
165
+ end
189
166
 
190
- def cleanup_external_files_on_destroy
191
- paths = external_datastream_file_paths
192
- yield
193
- File.unlink *paths
167
+ def generate_external_file_name ds
168
+ content_file_name = Ddr::Utils::sanitize_filename(original_filename) || datastreams[ds.dsid].default_file_name
169
+ case ds.dsid
170
+ when Ddr::Datastreams::MULTIRES_IMAGE
171
+ case ds.mimeType
172
+ when "image/tiff"
173
+ "#{File.basename(content_file_name, File.extname(content_file_name))}.ptif"
174
+ end
175
+ else
176
+ content_file_name
194
177
  end
178
+ end
195
179
 
180
+ def generate_external_directory_subpath
181
+ subdir = SecureRandom.uuid
182
+ m = Ddr::Models.external_file_subpath_regexp.match(subdir)
183
+ raise "File name does not match external file subpath pattern: #{file_name}" unless m
184
+ subpath_segments = m.to_a[1..-1]
185
+ File.join *subpath_segments, subdir
196
186
  end
187
+
188
+ def cleanup_external_files_on_destroy
189
+ paths = external_datastream_file_paths
190
+ yield
191
+ File.unlink *paths
192
+ end
193
+
197
194
  end
198
195
  end
@@ -27,10 +27,6 @@ module Ddr
27
27
  end
28
28
  end
29
29
 
30
- def inherited_license
31
- admin_policy.default_license if admin_policy
32
- end
33
-
34
30
  def copy_admin_policy_from(other)
35
31
  # XXX In active-fedora 7.0 can do
36
32
  # self.admin_policy = other.admin_policy
@@ -1,78 +1,86 @@
1
1
  require "resque"
2
2
 
3
- module Ddr
4
- module Models
5
- module HasAdminMetadata
6
- extend ActiveSupport::Concern
7
-
8
- included do
9
- has_metadata "adminMetadata",
10
- type: Ddr::Datastreams::AdministrativeMetadataDatastream,
11
- versionable: true,
12
- control_group: "M"
13
-
14
- has_attributes :admin_set,
15
- :display_format,
16
- :local_id,
17
- :permanent_id,
18
- :permanent_url,
19
- :research_help_contact,
20
- :workflow_state,
21
- datastream: "adminMetadata",
22
- multiple: false
23
-
24
- delegate :publish, :publish!, :unpublish, :unpublish!, :published?, to: :workflow
25
-
26
- after_create :assign_permanent_id!, if: "Ddr::Models.auto_assign_permanent_ids"
27
- around_destroy :update_permanent_id_on_destroy, if: "permanent_id.present?"
28
- end
29
-
30
- def permanent_id_manager
31
- @permanent_id_manager ||= Ddr::Managers::PermanentIdManager.new(self)
32
- end
33
-
34
- def roles
35
- Ddr::Auth::Roles::PropertyRoleSet.new(adminMetadata.access_role)
36
- end
37
-
38
- def inherited_roles
39
- Ddr::Auth::InheritedRoles.call(self)
40
- end
41
-
42
- def workflow
43
- @workflow ||= Ddr::Managers::WorkflowManager.new(self)
44
- end
45
-
46
- def assign_permanent_id!
47
- permanent_id_manager.assign_later
48
- end
49
-
50
- def grant_roles_to_creator(creator)
51
- roles.grant type: Ddr::Auth::Roles::EDITOR,
52
- agent: creator,
53
- scope: Ddr::Auth::Roles::RESOURCE_SCOPE
54
- end
55
-
56
- def copy_resource_roles_from(other)
57
- roles.grant *(other.roles.in_resource_scope)
58
- end
59
-
60
- def effective_permissions(agents)
61
- Ddr::Auth::EffectivePermissions.call(self, agents)
62
- end
63
-
64
- def research_help
65
- Ddr::Contacts.get(research_help_contact) if research_help_contact
66
- end
67
-
68
- private
69
-
70
- def update_permanent_id_on_destroy
71
- @permanent_id = permanent_id
72
- yield
73
- Resque.enqueue(Ddr::Jobs::PermanentId::MakeUnavailable, @permanent_id, "deleted")
74
- end
3
+ module Ddr::Models
4
+ module HasAdminMetadata
5
+ extend ActiveSupport::Concern
6
+
7
+ included do
8
+ has_metadata "adminMetadata",
9
+ type: Ddr::Datastreams::AdministrativeMetadataDatastream,
10
+ versionable: true,
11
+ control_group: "M"
12
+
13
+ has_attributes :admin_set,
14
+ :depositor,
15
+ :display_format,
16
+ :license,
17
+ :local_id,
18
+ :permanent_id,
19
+ :permanent_url,
20
+ :research_help_contact,
21
+ :workflow_state,
22
+ datastream: "adminMetadata",
23
+ multiple: false
24
+
25
+ delegate :publish, :publish!, :unpublish, :unpublish!, :published?, to: :workflow
26
+
27
+ after_create :assign_permanent_id!, if: "Ddr::Models.auto_assign_permanent_ids"
28
+ around_destroy :update_permanent_id_on_destroy, if: "permanent_id.present?"
29
+ end
30
+
31
+ def permanent_id_manager
32
+ @permanent_id_manager ||= Ddr::Managers::PermanentIdManager.new(self)
33
+ end
34
+
35
+ def roles
36
+ Ddr::Auth::Roles::PropertyRoleSet.new(adminMetadata.access_role)
37
+ end
38
+
39
+ def inherited_roles
40
+ Ddr::Auth::InheritedRoles.call(self)
41
+ end
42
+
43
+ def workflow
44
+ @workflow ||= Ddr::Managers::WorkflowManager.new(self)
45
+ end
46
+
47
+ def assign_permanent_id!
48
+ permanent_id_manager.assign_later
49
+ end
50
+
51
+ def grant_roles_to_creator(creator)
52
+ roles.grant type: Ddr::Auth::Roles::EDITOR,
53
+ agent: creator,
54
+ scope: Ddr::Auth::Roles::RESOURCE_SCOPE
55
+ end
75
56
 
57
+ def copy_resource_roles_from(other)
58
+ roles.grant *(other.roles.in_resource_scope)
76
59
  end
60
+
61
+ def effective_permissions(agents)
62
+ Ddr::Auth::EffectivePermissions.call(self, agents)
63
+ end
64
+
65
+ def research_help
66
+ Ddr::Contacts.get(research_help_contact) if research_help_contact
67
+ end
68
+
69
+ def effective_license
70
+ EffectiveLicense.call(self)
71
+ end
72
+
73
+ def inherited_license
74
+ InheritedLicense.call(self)
75
+ end
76
+
77
+ private
78
+
79
+ def update_permanent_id_on_destroy
80
+ @permanent_id = permanent_id
81
+ yield
82
+ Resque.enqueue(Ddr::Jobs::PermanentId::MakeUnavailable, @permanent_id, "deleted")
83
+ end
84
+
77
85
  end
78
86
  end