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.
- checksums.yaml +7 -0
- data/LICENSE.txt +12 -0
- data/README.md +5 -0
- data/Rakefile +37 -0
- data/app/models/attachment.rb +7 -0
- data/app/models/collection.rb +54 -0
- data/app/models/component.rb +15 -0
- data/app/models/item.rb +19 -0
- data/app/models/solr_document.rb +36 -0
- data/app/models/target.rb +8 -0
- data/config/initializers/active_fedora_base.rb +77 -0
- data/config/initializers/active_fedora_datastream.rb +5 -0
- data/config/initializers/ddr.rb +8 -0
- data/config/initializers/devise.rb +245 -0
- data/config/initializers/devise.rb~ +245 -0
- data/config/initializers/subscriptions.rb +15 -0
- data/config/routes.rb +2 -0
- data/db/migrate/20141021233359_create_events.rb +28 -0
- data/db/migrate/20141021234156_create_minted_ids.rb +19 -0
- data/db/migrate/20141103192146_create_workflow_state.rb +13 -0
- data/db/migrate/20141104181418_create_users.rb +34 -0
- data/db/migrate/20141104181418_create_users.rb~ +6 -0
- data/lib/ddr-models.rb +1 -0
- data/lib/ddr/actions.rb +8 -0
- data/lib/ddr/actions/fixity_check.rb +35 -0
- data/lib/ddr/auth.rb +45 -0
- data/lib/ddr/auth.rb~ +47 -0
- data/lib/ddr/auth/ability.rb +204 -0
- data/lib/ddr/auth/ability.rb~ +204 -0
- data/lib/ddr/auth/group_service.rb +53 -0
- data/lib/ddr/auth/group_service.rb~ +53 -0
- data/lib/ddr/auth/grouper_service.rb +76 -0
- data/lib/ddr/auth/grouper_service.rb~ +77 -0
- data/lib/ddr/auth/remote_group_service.rb +35 -0
- data/lib/ddr/auth/remote_group_service.rb~ +35 -0
- data/lib/ddr/auth/superuser.rb +13 -0
- data/lib/ddr/auth/superuser.rb~ +9 -0
- data/lib/ddr/auth/user.rb +71 -0
- data/lib/ddr/auth/user.rb~ +65 -0
- data/lib/ddr/configurable.rb +34 -0
- data/lib/ddr/datastreams.rb +32 -0
- data/lib/ddr/datastreams/content_metadata_datastream.rb +147 -0
- data/lib/ddr/datastreams/datastream_behavior.rb +95 -0
- data/lib/ddr/datastreams/descriptive_metadata_datastream.rb +84 -0
- data/lib/ddr/datastreams/properties_datastream.rb +25 -0
- data/lib/ddr/datastreams/role_assignments_datastream.rb +19 -0
- data/lib/ddr/events.rb +17 -0
- data/lib/ddr/events/creation_event.rb +12 -0
- data/lib/ddr/events/event.rb +163 -0
- data/lib/ddr/events/fixity_check_event.rb +43 -0
- data/lib/ddr/events/ingestion_event.rb +12 -0
- data/lib/ddr/events/preservation_event_behavior.rb +37 -0
- data/lib/ddr/events/preservation_event_type.rb +24 -0
- data/lib/ddr/events/reindex_object_after_save.rb +18 -0
- data/lib/ddr/events/update_event.rb +9 -0
- data/lib/ddr/events/validation_event.rb +11 -0
- data/lib/ddr/events/virus_check_event.rb +30 -0
- data/lib/ddr/index_fields.rb +39 -0
- data/lib/ddr/metadata.rb +22 -0
- data/lib/ddr/metadata/duke_terms.rb +15 -0
- data/lib/ddr/metadata/premis_event.rb +59 -0
- data/lib/ddr/metadata/rdf_vocabulary_parser.rb +45 -0
- data/lib/ddr/metadata/roles_vocabulary.rb +10 -0
- data/lib/ddr/metadata/sources/duketerms.rdf.xml +856 -0
- data/lib/ddr/metadata/vocabulary.rb +37 -0
- data/lib/ddr/models.rb +60 -0
- data/lib/ddr/models/access_controllable.rb +23 -0
- data/lib/ddr/models/base.rb +37 -0
- data/lib/ddr/models/describable.rb +81 -0
- data/lib/ddr/models/engine.rb +58 -0
- data/lib/ddr/models/error.rb +12 -0
- data/lib/ddr/models/event_loggable.rb +36 -0
- data/lib/ddr/models/file_management.rb +183 -0
- data/lib/ddr/models/fixity_checkable.rb +20 -0
- data/lib/ddr/models/governable.rb +48 -0
- data/lib/ddr/models/has_attachments.rb +12 -0
- data/lib/ddr/models/has_children.rb +21 -0
- data/lib/ddr/models/has_content.rb +114 -0
- data/lib/ddr/models/has_content_metadata.rb +16 -0
- data/lib/ddr/models/has_properties.rb +15 -0
- data/lib/ddr/models/has_role_assignments.rb +17 -0
- data/lib/ddr/models/has_thumbnail.rb +27 -0
- data/lib/ddr/models/has_workflow.rb +29 -0
- data/lib/ddr/models/indexing.rb +53 -0
- data/lib/ddr/models/licensable.rb +28 -0
- data/lib/ddr/models/minted_id.rb +10 -0
- data/lib/ddr/models/permanent_identification.rb +48 -0
- data/lib/ddr/models/solr_document.rb +193 -0
- data/lib/ddr/models/version.rb +5 -0
- data/lib/ddr/notifications.rb +15 -0
- data/lib/ddr/services.rb +8 -0
- data/lib/ddr/services/id_service.rb +48 -0
- data/lib/ddr/utils.rb +153 -0
- data/lib/ddr/workflow.rb +8 -0
- data/lib/ddr/workflow/workflow_state.rb +39 -0
- data/spec/dummy/README.rdoc +28 -0
- data/spec/dummy/Rakefile +6 -0
- data/spec/dummy/app/assets/javascripts/application.js +13 -0
- data/spec/dummy/app/assets/stylesheets/application.css +15 -0
- data/spec/dummy/app/controllers/application_controller.rb +5 -0
- data/spec/dummy/app/helpers/application_helper.rb +2 -0
- data/spec/dummy/app/models/user.rb +5 -0
- data/spec/dummy/app/views/layouts/application.html.erb +14 -0
- data/spec/dummy/bin/bundle +3 -0
- data/spec/dummy/bin/rails +4 -0
- data/spec/dummy/bin/rake +4 -0
- data/spec/dummy/config.ru +4 -0
- data/spec/dummy/config/application.rb +29 -0
- data/spec/dummy/config/boot.rb +5 -0
- data/spec/dummy/config/database.yml +25 -0
- data/spec/dummy/config/environment.rb +5 -0
- data/spec/dummy/config/environments/development.rb +37 -0
- data/spec/dummy/config/environments/production.rb +78 -0
- data/spec/dummy/config/environments/test.rb +39 -0
- data/spec/dummy/config/initializers/assets.rb +8 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummy/config/initializers/cookies_serializer.rb +3 -0
- data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
- data/spec/dummy/config/initializers/inflections.rb +16 -0
- data/spec/dummy/config/initializers/mime_types.rb +4 -0
- data/spec/dummy/config/initializers/session_store.rb +3 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/spec/dummy/config/locales/en.yml +23 -0
- data/spec/dummy/config/routes.rb +56 -0
- data/spec/dummy/config/secrets.yml +22 -0
- data/spec/dummy/db/development.sqlite3 +0 -0
- data/spec/dummy/db/schema.rb +80 -0
- data/spec/dummy/db/test.sqlite3 +0 -0
- data/spec/dummy/log/development.log +4974 -0
- data/spec/dummy/log/test.log +55627 -0
- data/spec/dummy/public/404.html +67 -0
- data/spec/dummy/public/422.html +67 -0
- data/spec/dummy/public/500.html +66 -0
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/factories/attachment_factories.rb +15 -0
- data/spec/factories/collection_factories.rb +16 -0
- data/spec/factories/component_factories.rb +15 -0
- data/spec/factories/event_factories.rb +7 -0
- data/spec/factories/item_factories.rb +16 -0
- data/spec/factories/target_factories.rb +11 -0
- data/spec/factories/test_model_factories.rb +133 -0
- data/spec/factories/user_factories.rb +7 -0
- data/spec/factories/user_factories.rb~ +7 -0
- data/spec/features/grouper_integration_spec.rb~ +21 -0
- data/spec/fixtures/contentMetadata.xml +37 -0
- data/spec/fixtures/image1.tiff +0 -0
- data/spec/fixtures/image2.tiff +0 -0
- data/spec/fixtures/image3.tiff +0 -0
- data/spec/fixtures/library-devil.tiff +0 -0
- data/spec/fixtures/sample.docx +0 -0
- data/spec/fixtures/sample.pdf +0 -0
- data/spec/fixtures/target.png +0 -0
- data/spec/models/ability_spec.rb +248 -0
- data/spec/models/ability_spec.rb~ +245 -0
- data/spec/models/active_fedora_base_spec.rb +107 -0
- data/spec/models/active_fedora_datastream_spec.rb +121 -0
- data/spec/models/attachment_spec.rb +13 -0
- data/spec/models/collection_spec.rb +33 -0
- data/spec/models/component_spec.rb +8 -0
- data/spec/models/descriptive_metadata_datastream_spec.rb +102 -0
- data/spec/models/events_spec.rb +64 -0
- data/spec/models/file_management_spec.rb +179 -0
- data/spec/models/has_role_assignments_spec.rb +29 -0
- data/spec/models/has_workflow_spec.rb +54 -0
- data/spec/models/item_spec.rb +8 -0
- data/spec/models/permanent_identification_spec.rb +65 -0
- data/spec/models/role_assignments_datastream_spec.rb +25 -0
- data/spec/models/superuser_spec.rb +13 -0
- data/spec/models/superuser_spec.rb~ +13 -0
- data/spec/models/target_spec.rb +8 -0
- data/spec/models/user_spec.rb +60 -0
- data/spec/models/user_spec.rb~ +56 -0
- data/spec/services/group_service_spec.rb +75 -0
- data/spec/services/group_service_spec.rb~ +71 -0
- data/spec/services/id_service_spec.rb +33 -0
- data/spec/spec_helper.rb +125 -0
- data/spec/support/shared_examples_for_access_controllables.rb +6 -0
- data/spec/support/shared_examples_for_associations.rb +8 -0
- data/spec/support/shared_examples_for_ddr_models.rb +7 -0
- data/spec/support/shared_examples_for_describables.rb +63 -0
- data/spec/support/shared_examples_for_event_loggables.rb +3 -0
- data/spec/support/shared_examples_for_events.rb +179 -0
- data/spec/support/shared_examples_for_governables.rb +17 -0
- data/spec/support/shared_examples_for_has_content.rb +136 -0
- data/spec/support/shared_examples_for_has_content_metadata.rb +74 -0
- data/spec/support/shared_examples_for_has_properties.rb +5 -0
- data/spec/support/shared_examples_for_indexing.rb +36 -0
- 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,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
|
data/lib/ddr/services.rb
ADDED
|
@@ -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
|
data/lib/ddr/utils.rb
ADDED
|
@@ -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
|
data/lib/ddr/workflow.rb
ADDED
|
@@ -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
|