ddr-models 1.2.0

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 (188) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE.txt +12 -0
  3. data/README.md +5 -0
  4. data/Rakefile +37 -0
  5. data/app/models/attachment.rb +7 -0
  6. data/app/models/collection.rb +54 -0
  7. data/app/models/component.rb +15 -0
  8. data/app/models/item.rb +19 -0
  9. data/app/models/solr_document.rb +36 -0
  10. data/app/models/target.rb +8 -0
  11. data/config/initializers/active_fedora_base.rb +77 -0
  12. data/config/initializers/active_fedora_datastream.rb +5 -0
  13. data/config/initializers/ddr.rb +8 -0
  14. data/config/initializers/devise.rb +245 -0
  15. data/config/initializers/devise.rb~ +245 -0
  16. data/config/initializers/subscriptions.rb +15 -0
  17. data/config/routes.rb +2 -0
  18. data/db/migrate/20141021233359_create_events.rb +28 -0
  19. data/db/migrate/20141021234156_create_minted_ids.rb +19 -0
  20. data/db/migrate/20141103192146_create_workflow_state.rb +13 -0
  21. data/db/migrate/20141104181418_create_users.rb +34 -0
  22. data/db/migrate/20141104181418_create_users.rb~ +6 -0
  23. data/lib/ddr-models.rb +1 -0
  24. data/lib/ddr/actions.rb +8 -0
  25. data/lib/ddr/actions/fixity_check.rb +35 -0
  26. data/lib/ddr/auth.rb +45 -0
  27. data/lib/ddr/auth.rb~ +47 -0
  28. data/lib/ddr/auth/ability.rb +204 -0
  29. data/lib/ddr/auth/ability.rb~ +204 -0
  30. data/lib/ddr/auth/group_service.rb +53 -0
  31. data/lib/ddr/auth/group_service.rb~ +53 -0
  32. data/lib/ddr/auth/grouper_service.rb +76 -0
  33. data/lib/ddr/auth/grouper_service.rb~ +77 -0
  34. data/lib/ddr/auth/remote_group_service.rb +35 -0
  35. data/lib/ddr/auth/remote_group_service.rb~ +35 -0
  36. data/lib/ddr/auth/superuser.rb +13 -0
  37. data/lib/ddr/auth/superuser.rb~ +9 -0
  38. data/lib/ddr/auth/user.rb +71 -0
  39. data/lib/ddr/auth/user.rb~ +65 -0
  40. data/lib/ddr/configurable.rb +34 -0
  41. data/lib/ddr/datastreams.rb +32 -0
  42. data/lib/ddr/datastreams/content_metadata_datastream.rb +147 -0
  43. data/lib/ddr/datastreams/datastream_behavior.rb +95 -0
  44. data/lib/ddr/datastreams/descriptive_metadata_datastream.rb +84 -0
  45. data/lib/ddr/datastreams/properties_datastream.rb +25 -0
  46. data/lib/ddr/datastreams/role_assignments_datastream.rb +19 -0
  47. data/lib/ddr/events.rb +17 -0
  48. data/lib/ddr/events/creation_event.rb +12 -0
  49. data/lib/ddr/events/event.rb +163 -0
  50. data/lib/ddr/events/fixity_check_event.rb +43 -0
  51. data/lib/ddr/events/ingestion_event.rb +12 -0
  52. data/lib/ddr/events/preservation_event_behavior.rb +37 -0
  53. data/lib/ddr/events/preservation_event_type.rb +24 -0
  54. data/lib/ddr/events/reindex_object_after_save.rb +18 -0
  55. data/lib/ddr/events/update_event.rb +9 -0
  56. data/lib/ddr/events/validation_event.rb +11 -0
  57. data/lib/ddr/events/virus_check_event.rb +30 -0
  58. data/lib/ddr/index_fields.rb +39 -0
  59. data/lib/ddr/metadata.rb +22 -0
  60. data/lib/ddr/metadata/duke_terms.rb +15 -0
  61. data/lib/ddr/metadata/premis_event.rb +59 -0
  62. data/lib/ddr/metadata/rdf_vocabulary_parser.rb +45 -0
  63. data/lib/ddr/metadata/roles_vocabulary.rb +10 -0
  64. data/lib/ddr/metadata/sources/duketerms.rdf.xml +856 -0
  65. data/lib/ddr/metadata/vocabulary.rb +37 -0
  66. data/lib/ddr/models.rb +60 -0
  67. data/lib/ddr/models/access_controllable.rb +23 -0
  68. data/lib/ddr/models/base.rb +37 -0
  69. data/lib/ddr/models/describable.rb +81 -0
  70. data/lib/ddr/models/engine.rb +58 -0
  71. data/lib/ddr/models/error.rb +12 -0
  72. data/lib/ddr/models/event_loggable.rb +36 -0
  73. data/lib/ddr/models/file_management.rb +183 -0
  74. data/lib/ddr/models/fixity_checkable.rb +20 -0
  75. data/lib/ddr/models/governable.rb +48 -0
  76. data/lib/ddr/models/has_attachments.rb +12 -0
  77. data/lib/ddr/models/has_children.rb +21 -0
  78. data/lib/ddr/models/has_content.rb +114 -0
  79. data/lib/ddr/models/has_content_metadata.rb +16 -0
  80. data/lib/ddr/models/has_properties.rb +15 -0
  81. data/lib/ddr/models/has_role_assignments.rb +17 -0
  82. data/lib/ddr/models/has_thumbnail.rb +27 -0
  83. data/lib/ddr/models/has_workflow.rb +29 -0
  84. data/lib/ddr/models/indexing.rb +53 -0
  85. data/lib/ddr/models/licensable.rb +28 -0
  86. data/lib/ddr/models/minted_id.rb +10 -0
  87. data/lib/ddr/models/permanent_identification.rb +48 -0
  88. data/lib/ddr/models/solr_document.rb +193 -0
  89. data/lib/ddr/models/version.rb +5 -0
  90. data/lib/ddr/notifications.rb +15 -0
  91. data/lib/ddr/services.rb +8 -0
  92. data/lib/ddr/services/id_service.rb +48 -0
  93. data/lib/ddr/utils.rb +153 -0
  94. data/lib/ddr/workflow.rb +8 -0
  95. data/lib/ddr/workflow/workflow_state.rb +39 -0
  96. data/spec/dummy/README.rdoc +28 -0
  97. data/spec/dummy/Rakefile +6 -0
  98. data/spec/dummy/app/assets/javascripts/application.js +13 -0
  99. data/spec/dummy/app/assets/stylesheets/application.css +15 -0
  100. data/spec/dummy/app/controllers/application_controller.rb +5 -0
  101. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  102. data/spec/dummy/app/models/user.rb +5 -0
  103. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  104. data/spec/dummy/bin/bundle +3 -0
  105. data/spec/dummy/bin/rails +4 -0
  106. data/spec/dummy/bin/rake +4 -0
  107. data/spec/dummy/config.ru +4 -0
  108. data/spec/dummy/config/application.rb +29 -0
  109. data/spec/dummy/config/boot.rb +5 -0
  110. data/spec/dummy/config/database.yml +25 -0
  111. data/spec/dummy/config/environment.rb +5 -0
  112. data/spec/dummy/config/environments/development.rb +37 -0
  113. data/spec/dummy/config/environments/production.rb +78 -0
  114. data/spec/dummy/config/environments/test.rb +39 -0
  115. data/spec/dummy/config/initializers/assets.rb +8 -0
  116. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  117. data/spec/dummy/config/initializers/cookies_serializer.rb +3 -0
  118. data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  119. data/spec/dummy/config/initializers/inflections.rb +16 -0
  120. data/spec/dummy/config/initializers/mime_types.rb +4 -0
  121. data/spec/dummy/config/initializers/session_store.rb +3 -0
  122. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  123. data/spec/dummy/config/locales/en.yml +23 -0
  124. data/spec/dummy/config/routes.rb +56 -0
  125. data/spec/dummy/config/secrets.yml +22 -0
  126. data/spec/dummy/db/development.sqlite3 +0 -0
  127. data/spec/dummy/db/schema.rb +80 -0
  128. data/spec/dummy/db/test.sqlite3 +0 -0
  129. data/spec/dummy/log/development.log +4974 -0
  130. data/spec/dummy/log/test.log +55627 -0
  131. data/spec/dummy/public/404.html +67 -0
  132. data/spec/dummy/public/422.html +67 -0
  133. data/spec/dummy/public/500.html +66 -0
  134. data/spec/dummy/public/favicon.ico +0 -0
  135. data/spec/factories/attachment_factories.rb +15 -0
  136. data/spec/factories/collection_factories.rb +16 -0
  137. data/spec/factories/component_factories.rb +15 -0
  138. data/spec/factories/event_factories.rb +7 -0
  139. data/spec/factories/item_factories.rb +16 -0
  140. data/spec/factories/target_factories.rb +11 -0
  141. data/spec/factories/test_model_factories.rb +133 -0
  142. data/spec/factories/user_factories.rb +7 -0
  143. data/spec/factories/user_factories.rb~ +7 -0
  144. data/spec/features/grouper_integration_spec.rb~ +21 -0
  145. data/spec/fixtures/contentMetadata.xml +37 -0
  146. data/spec/fixtures/image1.tiff +0 -0
  147. data/spec/fixtures/image2.tiff +0 -0
  148. data/spec/fixtures/image3.tiff +0 -0
  149. data/spec/fixtures/library-devil.tiff +0 -0
  150. data/spec/fixtures/sample.docx +0 -0
  151. data/spec/fixtures/sample.pdf +0 -0
  152. data/spec/fixtures/target.png +0 -0
  153. data/spec/models/ability_spec.rb +248 -0
  154. data/spec/models/ability_spec.rb~ +245 -0
  155. data/spec/models/active_fedora_base_spec.rb +107 -0
  156. data/spec/models/active_fedora_datastream_spec.rb +121 -0
  157. data/spec/models/attachment_spec.rb +13 -0
  158. data/spec/models/collection_spec.rb +33 -0
  159. data/spec/models/component_spec.rb +8 -0
  160. data/spec/models/descriptive_metadata_datastream_spec.rb +102 -0
  161. data/spec/models/events_spec.rb +64 -0
  162. data/spec/models/file_management_spec.rb +179 -0
  163. data/spec/models/has_role_assignments_spec.rb +29 -0
  164. data/spec/models/has_workflow_spec.rb +54 -0
  165. data/spec/models/item_spec.rb +8 -0
  166. data/spec/models/permanent_identification_spec.rb +65 -0
  167. data/spec/models/role_assignments_datastream_spec.rb +25 -0
  168. data/spec/models/superuser_spec.rb +13 -0
  169. data/spec/models/superuser_spec.rb~ +13 -0
  170. data/spec/models/target_spec.rb +8 -0
  171. data/spec/models/user_spec.rb +60 -0
  172. data/spec/models/user_spec.rb~ +56 -0
  173. data/spec/services/group_service_spec.rb +75 -0
  174. data/spec/services/group_service_spec.rb~ +71 -0
  175. data/spec/services/id_service_spec.rb +33 -0
  176. data/spec/spec_helper.rb +125 -0
  177. data/spec/support/shared_examples_for_access_controllables.rb +6 -0
  178. data/spec/support/shared_examples_for_associations.rb +8 -0
  179. data/spec/support/shared_examples_for_ddr_models.rb +7 -0
  180. data/spec/support/shared_examples_for_describables.rb +63 -0
  181. data/spec/support/shared_examples_for_event_loggables.rb +3 -0
  182. data/spec/support/shared_examples_for_events.rb +179 -0
  183. data/spec/support/shared_examples_for_governables.rb +17 -0
  184. data/spec/support/shared_examples_for_has_content.rb +136 -0
  185. data/spec/support/shared_examples_for_has_content_metadata.rb +74 -0
  186. data/spec/support/shared_examples_for_has_properties.rb +5 -0
  187. data/spec/support/shared_examples_for_indexing.rb +36 -0
  188. metadata +562 -0
@@ -0,0 +1,193 @@
1
+ require 'json'
2
+
3
+ module Ddr
4
+ module Models
5
+ module SolrDocument
6
+ extend ActiveSupport::Concern
7
+
8
+ included do
9
+ alias_method :pid, :id
10
+ end
11
+
12
+ def to_partial_path
13
+ 'document'
14
+ end
15
+
16
+ def safe_id
17
+ id.sub(/:/, "-")
18
+ end
19
+
20
+ def active_fedora_model
21
+ get(Ddr::IndexFields::ACTIVE_FEDORA_MODEL)
22
+ end
23
+
24
+ def internal_uri
25
+ get(Ddr::IndexFields::INTERNAL_URI)
26
+ end
27
+
28
+ def object_profile
29
+ @object_profile ||= get_json(Ddr::IndexFields::OBJECT_PROFILE)
30
+ end
31
+
32
+ def object_state
33
+ object_profile["objState"]
34
+ end
35
+
36
+ def object_create_date
37
+ parse_date(object_profile["objCreateDate"])
38
+ end
39
+
40
+ def object_modified_date
41
+ parse_date(object_profile["objLastModDate"])
42
+ end
43
+
44
+ def last_fixity_check_on
45
+ get_date(Ddr::IndexFields::LAST_FIXITY_CHECK_ON)
46
+ end
47
+
48
+ def last_fixity_check_outcome
49
+ get(Ddr::IndexFields::LAST_FIXITY_CHECK_OUTCOME)
50
+ end
51
+
52
+ def last_virus_check_on
53
+ get_date(Ddr::IndexFields::LAST_VIRUS_CHECK_ON)
54
+ end
55
+
56
+ def last_virus_check_outcome
57
+ get(Ddr::IndexFields::LAST_VIRUS_CHECK_OUTCOME)
58
+ end
59
+
60
+ def datastreams
61
+ object_profile["datastreams"]
62
+ end
63
+
64
+ def has_datastream?(dsID)
65
+ datastreams[dsID].present?
66
+ end
67
+
68
+ def has_admin_policy?
69
+ admin_policy_uri.present?
70
+ end
71
+
72
+ def admin_policy_uri
73
+ get(Ddr::IndexFields::IS_GOVERNED_BY)
74
+ end
75
+
76
+ def admin_policy_pid
77
+ uri = admin_policy_uri
78
+ uri &&= ActiveFedora::Base.pid_from_uri(uri)
79
+ end
80
+
81
+ def has_children?
82
+ ActiveFedora::SolrService.class_from_solr_document(self).reflect_on_association(:children).present?
83
+ end
84
+
85
+ def label
86
+ object_profile["objLabel"]
87
+ end
88
+
89
+ def title
90
+ get(Ddr::IndexFields::TITLE)
91
+ end
92
+ alias_method :title_display, :title # duck-type Ddr::Models::Base
93
+
94
+ def principal_has_role?(principal, role)
95
+ (Array(get("role_assignments__#{role}_ssim")) & Array(principal)).any?
96
+ end
97
+
98
+ def identifier
99
+ # We want the multivalued version here
100
+ get(ActiveFedora::SolrService.solr_name(:identifier, :stored_searchable, type: :text))
101
+ end
102
+
103
+ def source
104
+ get(ActiveFedora::SolrService.solr_name(:source, :stored_searchable, type: :text))
105
+ end
106
+
107
+ def has_thumbnail?
108
+ has_datastream?(Ddr::Datastreams::THUMBNAIL)
109
+ end
110
+
111
+ def has_content?
112
+ has_datastream?(Ddr::Datastreams::CONTENT)
113
+ end
114
+
115
+ def content_ds
116
+ datastreams[Ddr::Datastreams::CONTENT]
117
+ end
118
+
119
+ def content_mime_type
120
+ content_ds["dsMIME"] rescue nil
121
+ end
122
+ # For duck-typing with Ddr::Models::HasContent
123
+ alias_method :content_type, :content_mime_type
124
+
125
+ def content_size
126
+ get(Ddr::IndexFields::CONTENT_SIZE)
127
+ end
128
+
129
+ def content_size_human
130
+ get(Ddr::IndexFields::CONTENT_SIZE_HUMAN)
131
+ end
132
+
133
+ def content_checksum
134
+ content_ds["dsChecksum"] rescue nil
135
+ end
136
+
137
+ def targets
138
+ @targets ||= ActiveFedora::SolrService.query(targets_query)
139
+ end
140
+
141
+ def targets_count
142
+ @targets_count ||= ActiveFedora::SolrService.count(targets_query)
143
+ end
144
+
145
+ def has_target?
146
+ targets_count > 0
147
+ end
148
+
149
+ def has_default_rights?
150
+ has_datastream?(Ddr::Datastreams::DEFAULT_RIGHTS)
151
+ end
152
+
153
+ def parsed_content_metadata
154
+ JSON.parse(self[Ddr::IndexFields::CONTENT_METADATA_PARSED].first)
155
+ end
156
+
157
+ def association(name)
158
+ get_pid(ActiveFedora::SolrService.solr_name(name, :symbol))
159
+ end
160
+
161
+ def controller_name
162
+ active_fedora_model.tableize
163
+ end
164
+
165
+ private
166
+
167
+ def targets_query
168
+ "#{Ddr::IndexFields::IS_EXTERNAL_TARGET_FOR}:#{internal_uri_for_query}"
169
+ end
170
+
171
+ def internal_uri_for_query
172
+ ActiveFedora::SolrService.escape_uri_for_query(internal_uri)
173
+ end
174
+
175
+ def get_date(field)
176
+ parse_date(get(field))
177
+ end
178
+
179
+ def get_json(field)
180
+ JSON.parse(self[field].first)
181
+ end
182
+
183
+ def parse_date(date)
184
+ Time.parse(date).localtime if date
185
+ end
186
+
187
+ def get_pid(field)
188
+ ActiveFedora::Base.pid_from_uri(get(field)) rescue nil
189
+ end
190
+
191
+ end
192
+ end
193
+ end
@@ -0,0 +1,5 @@
1
+ module Ddr
2
+ module Models
3
+ VERSION = "1.2.0"
4
+ end
5
+ end
@@ -0,0 +1,15 @@
1
+ module Ddr
2
+ module Notifications
3
+
4
+ FIXITY_CHECK = "fixity_check.events.ddr"
5
+ VIRUS_CHECK = "virus_check.events.ddr"
6
+ CREATION = "creation.events.ddr"
7
+ UPDATE = "update.events.ddr"
8
+
9
+ def self.notify_event(type, args={})
10
+ name = "#{type}.events.ddr"
11
+ ActiveSupport::Notifications.instrument(name, args)
12
+ end
13
+
14
+ end
15
+ end
@@ -0,0 +1,8 @@
1
+ module Ddr
2
+ module Services
3
+ extend ActiveSupport::Autoload
4
+
5
+ autoload :IdService
6
+
7
+ end
8
+ end
@@ -0,0 +1,48 @@
1
+ require 'noid'
2
+
3
+ module Ddr
4
+ module Services
5
+ module IdService
6
+
7
+ def self.noid_template
8
+ Ddr::Models.noid_template
9
+ end
10
+
11
+ @minter = ::Noid::Minter.new(template: noid_template)
12
+ @semaphore = Mutex.new
13
+
14
+ def self.valid? noid
15
+ @minter.valid? noid
16
+ end
17
+
18
+ def self.mint
19
+ @semaphore.synchronize do
20
+ while true
21
+ minted = Ddr::Models::MintedId.new(minted_id: self.next_id)
22
+ return minted.minted_id if minted.save
23
+ end
24
+ end
25
+ end
26
+
27
+ protected
28
+
29
+ def self.next_id
30
+ noid = ''
31
+ File.open(Ddr::Models.minter_statefile, File::RDWR|File::CREAT, 0644) do |f|
32
+ f.flock(File::LOCK_EX)
33
+ yaml = YAML::load(f.read)
34
+ yaml = {template: noid_template} unless yaml
35
+ minter = ::Noid::Minter.new(yaml)
36
+ noid = minter.mint
37
+ f.rewind
38
+ yaml = YAML::dump(minter.dump)
39
+ f.write yaml
40
+ f.flush
41
+ f.truncate(f.pos)
42
+ end
43
+ noid
44
+ end
45
+
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,153 @@
1
+ require 'openssl'
2
+
3
+ module Ddr::Utils
4
+
5
+ DEFAULT_MIME_TYPE = "application/octet-stream"
6
+
7
+ def self.digest content, algorithm
8
+ raise TypeError, "Algorithm must be a string: #{algorithm.inspect}" unless algorithm.is_a?(String)
9
+ digest_class = OpenSSL::Digest.const_get(algorithm.sub("-", "").to_sym)
10
+ digest_class.new(content).to_s
11
+ rescue NameError => e
12
+ raise ArgumentError, "Invalid algorithm: #{algorithm}"
13
+ end
14
+
15
+ # Return a mime type for the file, using the file_name if necessary
16
+ # file can be a File object or file path (String)
17
+ # Return default mime type if unable to determine otherwise
18
+ def self.mime_type_for(file, file_name=nil)
19
+ return file.content_type if file.respond_to?(:content_type) # E.g., Rails uploaded file
20
+ path = file_name || file_path(file) rescue nil
21
+ mime_types = MIME::Types.of(path) rescue [] # MIME::Types.of blows up on nil
22
+ mime_types.empty? ? DEFAULT_MIME_TYPE : mime_types.first.content_type
23
+ end
24
+
25
+ def self.file_or_path? file
26
+ file_path(file)
27
+ rescue ArgumentError
28
+ false
29
+ end
30
+
31
+ def self.file_path? file
32
+ # length is a sanity check
33
+ file.is_a?(String) && (file.length < 1024) && File.exists?(file)
34
+ end
35
+
36
+ def self.file_path file
37
+ if file.respond_to?(:path)
38
+ File.absolute_path(file.path)
39
+ elsif file_path?(file)
40
+ file
41
+ else
42
+ raise ArgumentError, "File argument is neither a File nor a path to an existing file."
43
+ end
44
+ end
45
+
46
+ def self.file_name_for file
47
+ return file.original_filename if file.respond_to?(:original_filename) && file.original_filename.present?
48
+ File.basename(file_path(file)) rescue nil
49
+ end
50
+
51
+ def self.file_uri?(uri)
52
+ return false unless uri
53
+ URI.parse(uri).scheme == "file"
54
+ end
55
+
56
+ # Return file path for URI string
57
+ # Should reverse .path_to_uri
58
+ # "file:/path/to/file" => "/path/to/file"
59
+ def self.path_from_uri(uri)
60
+ URI.unescape(URI.parse(uri).path)
61
+ end
62
+
63
+ # Return URI string for file path
64
+ # Should reverse .path_from_uri
65
+ # "/path/to/file" => "file:/path/to/file"
66
+ def self.path_to_uri(path)
67
+ uri = URI.parse(URI.escape(path))
68
+ uri.scheme = "file"
69
+ uri.to_s
70
+ end
71
+
72
+ def self.ds_as_of_date_time(ds)
73
+ ds.create_date_string
74
+ end
75
+
76
+ # Find an object with a given identifier and return its PID.
77
+ # Returns the PID if a single object is found.
78
+ # Returns nil if no object is found.
79
+ # Raises Ddr::Error if more than one object is found.
80
+ # Options can be provided to limit the scope of matching objects
81
+ # model: Will only consider objects of that model
82
+ # collection: Will only consider objects that either are that collection or which are
83
+ # direct children of that collection (i.e., effectively searches a collection and its
84
+ # items for an object with the given identifier)
85
+ def self.pid_for_identifier(identifier, opts={})
86
+ model = opts.fetch(:model, nil)
87
+ collection = opts.fetch(:collection, nil)
88
+ objs = []
89
+ ActiveFedora::Base.find_each( { Ddr::IndexFields::IDENTIFIER => identifier }, { :cast => true } ) { |o| objs << o }
90
+ pids = []
91
+ objs.each { |obj| pids << obj.pid }
92
+ if model.present?
93
+ objs.each { |obj| pids.delete(obj.pid) unless obj.is_a?(model.constantize) }
94
+ end
95
+ if collection.present?
96
+ objs.each do |obj|
97
+ pids.delete(obj.pid) unless obj == collection || obj.parent == collection
98
+ end
99
+ end
100
+ case pids.size
101
+ when 0
102
+ nil
103
+ when 1
104
+ pids.first
105
+ else
106
+ raise Ddr::Error, I18n.t('ddr.errors.multiple_object_matches', :criteria => "identifier #{identifier}")
107
+ end
108
+ end
109
+
110
+ # Returns the reflection object for a given model name and relationship name
111
+ # E.g., relationship_object_reflection("Item", "parent") returns the reflection object for
112
+ # an Item's parent relationship. This reflection object can then be used to obtain the
113
+ # class of the relationship object using the reflection_object_class(reflection) method below.
114
+ def self.relationship_object_reflection(model, relationship_name)
115
+ reflection = nil
116
+ if model
117
+ begin
118
+ reflections = model.constantize.reflections
119
+ rescue NameError
120
+ # nothing to do here except that we can't return the appropriate reflection
121
+ else
122
+ reflections.each do |reflect|
123
+ if reflect[0].eql?(relationship_name.to_sym)
124
+ reflection = reflect
125
+ end
126
+ end
127
+ end
128
+ end
129
+ return reflection
130
+ end
131
+
132
+ # Returns the class associated with the :class_name attribute in the options of a reflection
133
+ # E.g., reflection_object_class(relationship_object_reflection("Item", "parent")) returns the
134
+ # Collection class.
135
+ def self.reflection_object_class(reflection)
136
+ reflection_object_model = nil
137
+ klass = nil
138
+ if reflection[1].options[:class_name]
139
+ reflection_object_model = reflection[1].options[:class_name]
140
+ else
141
+ reflection_object_model = ActiveSupport::Inflector.camelize(reflection[0])
142
+ end
143
+ if reflection_object_model
144
+ begin
145
+ klass = reflection_object_model.constantize
146
+ rescue NameError
147
+ # nothing to do here except that we can't return the reflection object class
148
+ end
149
+ end
150
+ return klass
151
+ end
152
+
153
+ end
@@ -0,0 +1,8 @@
1
+ module Ddr
2
+ module Workflow
3
+ extend ActiveSupport::Autoload
4
+
5
+ autoload :WorkflowState
6
+
7
+ end
8
+ end
@@ -0,0 +1,39 @@
1
+ module Ddr
2
+ module Workflow
3
+ class WorkflowState < ActiveRecord::Base
4
+
5
+ PUBLISHED = "published"
6
+
7
+ def self.workflow_state_for_object(obj)
8
+ workflow_state_for_pid(obj.pid)
9
+ end
10
+
11
+ def self.workflow_state_for_pid(pid)
12
+ for_pid(pid).present? ? for_pid(pid).first.workflow_state : nil
13
+ end
14
+
15
+ def self.set_for_object(obj, state)
16
+ set_for_pid(obj.pid, state)
17
+ end
18
+
19
+ def self.set_for_pid(pid, state)
20
+ if for_pid(pid).present?
21
+ for_pid(pid).first.update(workflow_state: state)
22
+ else
23
+ create(pid: pid, workflow_state: state)
24
+ end
25
+ end
26
+
27
+ private
28
+
29
+ def self.for_object(obj)
30
+ for_pid(obj.pid)
31
+ end
32
+
33
+ def self.for_pid(pid)
34
+ where(pid: pid)
35
+ end
36
+
37
+ end
38
+ end
39
+ end