ddr-models 3.0.0.beta.3 → 3.0.0.beta.4
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 +4 -4
- data/.travis.yml +3 -3
- data/config/locales/ddr-models.en.yml +74 -0
- data/ddr-models.gemspec +3 -2
- data/lib/ddr/auth.rb +5 -2
- data/lib/ddr/auth/roles.rb +0 -2
- data/lib/ddr/auth/roles/role_set.rb +1 -0
- data/lib/ddr/derivatives/generators/png_generator.rb +1 -1
- data/lib/ddr/index.rb +6 -2
- data/lib/ddr/index/abstract_query_result.rb +1 -1
- data/lib/ddr/index/csv_options.rb +14 -0
- data/lib/ddr/index/csv_query_result.rb +39 -32
- data/lib/ddr/index/field.rb +11 -1
- data/lib/ddr/index/field_attribute.rb +22 -0
- data/lib/ddr/index/fields.rb +29 -20
- data/lib/ddr/index/filter.rb +81 -30
- data/lib/ddr/index/filters.rb +15 -10
- data/lib/ddr/index/query.rb +34 -13
- data/lib/ddr/index/query_builder.rb +150 -30
- data/lib/ddr/index/query_clause.rb +64 -19
- data/lib/ddr/index/query_params.rb +40 -0
- data/lib/ddr/index/solr_csv_options.rb +18 -0
- data/lib/ddr/index/sort_order.rb +28 -0
- data/lib/ddr/jobs.rb +5 -1
- data/lib/ddr/jobs/fits_file_characterization.rb +3 -41
- data/lib/ddr/jobs/fixity_check.rb +13 -0
- data/lib/ddr/jobs/job.rb +36 -0
- data/lib/ddr/jobs/queue.rb +27 -0
- data/lib/ddr/jobs/update_index.rb +13 -0
- data/lib/ddr/models.rb +20 -3
- data/lib/ddr/models/admin_set.rb +7 -3
- data/lib/ddr/models/contact.rb +19 -0
- data/lib/ddr/models/error.rb +3 -0
- data/lib/ddr/models/file_characterization.rb +37 -0
- data/lib/ddr/models/finding_aid.rb +35 -2
- data/lib/ddr/models/has_admin_metadata.rb +5 -1
- data/lib/ddr/models/has_content.rb +4 -2
- data/lib/ddr/models/indexing.rb +7 -0
- data/lib/ddr/models/licenses/license.rb +7 -3
- data/lib/ddr/models/solr_document.rb +2 -2
- data/lib/ddr/models/version.rb +1 -1
- data/lib/ddr/models/with_content_file.rb +37 -0
- data/lib/ddr/vocab/asset.rb +3 -0
- data/spec/derivatives/png_generator_spec.rb +8 -1
- data/spec/fixtures/arrow1rightred_e0.gif +0 -0
- data/spec/index/fields_spec.rb +197 -0
- data/spec/index/filter_spec.rb +155 -30
- data/spec/index/query_builder_spec.rb +116 -0
- data/spec/index/query_clause_spec.rb +58 -0
- data/spec/index/query_spec.rb +39 -10
- data/spec/jobs/fits_file_characterization_spec.rb +7 -43
- data/spec/jobs/fixity_check_spec.rb +22 -0
- data/spec/jobs/job_spec.rb +40 -0
- data/spec/jobs/update_index_spec.rb +22 -0
- data/spec/managers/derivatives_manager_spec.rb +15 -11
- data/spec/models/admin_set_spec.rb +28 -10
- data/spec/models/contact_spec.rb +42 -0
- data/spec/models/effective_license_spec.rb +17 -7
- data/spec/models/file_characterization_spec.rb +38 -0
- data/spec/models/finding_aid_spec.rb +31 -8
- data/spec/models/has_admin_metadata_spec.rb +8 -5
- data/spec/models/indexing_spec.rb +2 -0
- data/spec/models/license_spec.rb +31 -10
- data/spec/models/solr_document_spec.rb +23 -3
- data/spec/models/with_content_file_spec.rb +32 -0
- data/spec/spec_helper.rb +2 -0
- metadata +66 -28
- data/lib/ddr/contacts.rb +0 -25
- data/lib/ddr/index/query_value.rb +0 -18
- data/lib/ddr/models/access_controllable.rb +0 -12
- data/spec/auth/ldap_gateway_spec.rb +0 -9
- data/spec/contacts/contacts_spec.rb +0 -26
- data/spec/index/filters_spec.rb +0 -17
@@ -1,51 +1,96 @@
|
|
1
|
+
require "virtus"
|
2
|
+
|
1
3
|
module Ddr::Index
|
2
4
|
class QueryClause
|
5
|
+
include Virtus.value_object
|
6
|
+
|
7
|
+
ANY_FIELD = Field.new('*').freeze
|
8
|
+
ANY_VALUE = "[* TO *]"
|
9
|
+
QUOTE = '"'
|
10
|
+
|
11
|
+
TERM_QUERY = "{!term f=%{field}}%{value}"
|
12
|
+
STANDARD_QUERY = "%{field}:%{value}"
|
13
|
+
NEGATIVE_QUERY = "-%{field}:%{value}"
|
14
|
+
DISJUNCTION = "{!lucene q.op=OR df=%{field}}%{value}"
|
15
|
+
|
16
|
+
values do
|
17
|
+
attribute :field, FieldAttribute
|
18
|
+
attribute :value, String
|
19
|
+
attribute :quote_value, Boolean, default: false
|
20
|
+
attribute :template, String, default: STANDARD_QUERY
|
21
|
+
end
|
22
|
+
|
23
|
+
def to_s
|
24
|
+
template % { field: field, value: quote_value ? quote(value) : value }
|
25
|
+
end
|
3
26
|
|
4
|
-
|
5
|
-
|
6
|
-
|
27
|
+
def quote(value)
|
28
|
+
self.class.quote(value)
|
29
|
+
end
|
7
30
|
|
8
31
|
class << self
|
9
|
-
|
10
|
-
def
|
11
|
-
|
32
|
+
|
33
|
+
def quote(value)
|
34
|
+
# Derived from Blacklight::Solr::SearchBuilderBehavior#solr_param_quote
|
35
|
+
unless value =~ /\A[a-zA-Z0-9$_\-\^]+\z/
|
36
|
+
QUOTE + value.gsub("'", "\\\\\'").gsub('"', "\\\\\"") + QUOTE
|
37
|
+
else
|
38
|
+
value
|
39
|
+
end
|
12
40
|
end
|
13
41
|
|
42
|
+
# Builds a query clause to retrieve the index document by unique key.
|
14
43
|
def unique_key(value)
|
15
44
|
term(UniqueKeyField.instance, value)
|
16
45
|
end
|
17
46
|
alias_method :id, :unique_key
|
18
|
-
alias_method :pid, :unique_key
|
19
47
|
|
48
|
+
def where(field, value)
|
49
|
+
values = Array(value)
|
50
|
+
if values.size > 1
|
51
|
+
disjunction(field, values)
|
52
|
+
else
|
53
|
+
new(field: field, value: values.first, quote_value: true)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
# Builds a query clause to filter where field does not have the given value.
|
20
58
|
def negative(field, value)
|
21
|
-
|
59
|
+
new(field: field, value: value, template: NEGATIVE_QUERY, quote_value: true)
|
22
60
|
end
|
23
61
|
|
62
|
+
# Builds a query clause to filter where field is present (i.e, has any value)
|
24
63
|
def present(field)
|
25
|
-
|
64
|
+
new(field: field, value: ANY_VALUE)
|
26
65
|
end
|
27
66
|
|
67
|
+
# Builds a query clause to filter where field is NOT present (no values)
|
28
68
|
def absent(field)
|
29
|
-
|
69
|
+
new(field: field, value: ANY_VALUE, template: NEGATIVE_QUERY)
|
30
70
|
end
|
31
71
|
|
32
|
-
|
33
|
-
|
72
|
+
# Builds a query clause to filter where field contains at least one of a set of values.
|
73
|
+
def disjunction(field, values)
|
74
|
+
value = values.map { |v| quote(v) }.join(" ")
|
75
|
+
new(field: field, value: value, template: DISJUNCTION)
|
34
76
|
end
|
35
77
|
|
36
|
-
|
37
|
-
|
38
|
-
|
78
|
+
# Builds a query clause to filter where date field value is earlier than a date/time value.
|
79
|
+
def before(field, value)
|
80
|
+
new(field: field, value: "[* TO %s]" % Ddr::Utils.solr_date(value))
|
39
81
|
end
|
82
|
+
alias_method :before_date_time, :before
|
40
83
|
|
41
|
-
|
42
|
-
|
43
|
-
|
84
|
+
# Builds a query clause to filter where date field value is earlier than a number of days before now.
|
85
|
+
def before_days(field, value)
|
86
|
+
new(field: field, value: "[* TO NOW-%iDAYS]" % value)
|
44
87
|
end
|
45
88
|
|
89
|
+
# Builds a "term query" clause to filter where field contains value.
|
46
90
|
def term(field, value)
|
47
|
-
|
91
|
+
new(field: field, value: value, template: TERM_QUERY)
|
48
92
|
end
|
93
|
+
|
49
94
|
end
|
50
95
|
|
51
96
|
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module Ddr::Index
|
2
|
+
class QueryParams
|
3
|
+
|
4
|
+
attr_reader :query
|
5
|
+
|
6
|
+
def initialize(query)
|
7
|
+
@query = query
|
8
|
+
end
|
9
|
+
|
10
|
+
def params
|
11
|
+
{ q: q_param,
|
12
|
+
fq: filter_queries,
|
13
|
+
fl: fields,
|
14
|
+
sort: sort,
|
15
|
+
rows: rows,
|
16
|
+
}.select { |k, v| v.present? }
|
17
|
+
end
|
18
|
+
|
19
|
+
def q_param
|
20
|
+
query.q.to_s
|
21
|
+
end
|
22
|
+
|
23
|
+
def filter_queries
|
24
|
+
query.filter_clauses.map(&:to_s)
|
25
|
+
end
|
26
|
+
|
27
|
+
def fields
|
28
|
+
query.fields.join(",")
|
29
|
+
end
|
30
|
+
|
31
|
+
def sort
|
32
|
+
query.sort.join(",")
|
33
|
+
end
|
34
|
+
|
35
|
+
def rows
|
36
|
+
query.rows
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require "hashie"
|
2
|
+
|
3
|
+
module Ddr::Index
|
4
|
+
class SolrCSVOptions < Hashie::Trash
|
5
|
+
|
6
|
+
property "csv.header", from: :header, default: false
|
7
|
+
property "csv.separator", from: :col_sep, default: ","
|
8
|
+
property "csv.encapsulator", from: :quote_char, default: '"'
|
9
|
+
property "csv.mv.separator", from: :mv_sep, default: ","
|
10
|
+
property :wt, default: "csv"
|
11
|
+
property :rows
|
12
|
+
|
13
|
+
def params
|
14
|
+
to_h.reject { |k, v| v.nil? }
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require "virtus"
|
2
|
+
|
3
|
+
module Ddr::Index
|
4
|
+
class SortOrder
|
5
|
+
include Virtus.value_object
|
6
|
+
|
7
|
+
ASC = "asc"
|
8
|
+
DESC = "desc"
|
9
|
+
|
10
|
+
values do
|
11
|
+
attribute :field, FieldAttribute
|
12
|
+
attribute :order, String
|
13
|
+
end
|
14
|
+
|
15
|
+
def to_s
|
16
|
+
[ field, order ].join(" ")
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.asc(field)
|
20
|
+
new(field: field, order: ASC)
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.desc(field)
|
24
|
+
new(field: field, order: DESC)
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
end
|
data/lib/ddr/jobs.rb
CHANGED
@@ -2,8 +2,12 @@ module Ddr
|
|
2
2
|
module Jobs
|
3
3
|
extend ActiveSupport::Autoload
|
4
4
|
|
5
|
-
autoload :PermanentId
|
6
5
|
autoload :FitsFileCharacterization
|
6
|
+
autoload :FixityCheck
|
7
|
+
autoload :Job
|
8
|
+
autoload :PermanentId
|
9
|
+
autoload :Queue
|
10
|
+
autoload :UpdateIndex
|
7
11
|
|
8
12
|
autoload_at 'ddr/jobs/permanent_id' do
|
9
13
|
autoload :MakeUnavailable
|
@@ -1,51 +1,13 @@
|
|
1
|
-
require 'open3'
|
2
|
-
|
3
1
|
module Ddr::Jobs
|
4
2
|
class FitsFileCharacterization
|
3
|
+
extend Job
|
5
4
|
|
6
5
|
@queue = :file_characterization
|
7
6
|
|
8
|
-
EVENT_SUMMARY = 'FITS characterization of content file'.freeze
|
9
|
-
|
10
7
|
def self.perform(pid)
|
11
8
|
obj = ActiveFedora::Base.find(pid)
|
12
|
-
|
13
|
-
Dir.mktmpdir do |dir|
|
14
|
-
infile = create_temp_infile(dir, tmp_filename, obj.content.content)
|
15
|
-
fits_output, err, status = Open3.capture3(fits_command, '-i', infile)
|
16
|
-
if status.success? && fits_output.present?
|
17
|
-
obj.reload
|
18
|
-
obj.fits.content = fits_output
|
19
|
-
obj.save!
|
20
|
-
end
|
21
|
-
notify_event(pid, err, status)
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
def self.fits_command
|
26
|
-
File.join(Ddr::Models.fits_home, 'fits.sh')
|
27
|
-
end
|
28
|
-
|
29
|
-
def self.fits_version
|
30
|
-
`#{fits_command} -v`.strip
|
31
|
-
end
|
32
|
-
|
33
|
-
private
|
34
|
-
|
35
|
-
def self.create_temp_infile(dir, tmp_filename, content)
|
36
|
-
temp_infile = File.join(dir, tmp_filename)
|
37
|
-
File.open(temp_infile, 'wb') do |f|
|
38
|
-
f.write content
|
39
|
-
end
|
40
|
-
temp_infile
|
41
|
-
end
|
42
|
-
|
43
|
-
def self.notify_event(pid, err, status)
|
44
|
-
details = status.success? ? nil : err
|
45
|
-
event_args = { pid: pid, summary: EVENT_SUMMARY, software: "fits #{fits_version}", detail: details }
|
46
|
-
event_args[:outcome] = status.success? ? Ddr::Events::Event::SUCCESS : Ddr::Events::Event::FAILURE
|
47
|
-
Ddr::Notifications.notify_event(:update, event_args)
|
9
|
+
Ddr::Models::FileCharacterization.call(obj)
|
48
10
|
end
|
49
11
|
|
50
12
|
end
|
51
|
-
end
|
13
|
+
end
|
data/lib/ddr/jobs/job.rb
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
require "resque"
|
2
|
+
|
3
|
+
module Ddr::Jobs
|
4
|
+
module Job
|
5
|
+
|
6
|
+
def self.extended(base)
|
7
|
+
base.extend ClassMethods
|
8
|
+
end
|
9
|
+
|
10
|
+
module ClassMethods
|
11
|
+
# @return [Array<String>] list of object ids queued for this job type.
|
12
|
+
# @note Assumes that the object_id is the first argument of the .perform method.
|
13
|
+
def queued_object_ids(**args)
|
14
|
+
args[:type] = self
|
15
|
+
__queue__.jobs(**args).map { |job| job["args"].first }
|
16
|
+
end
|
17
|
+
|
18
|
+
protected
|
19
|
+
|
20
|
+
def method_missing(name, *args, &block)
|
21
|
+
# If .queue method not defined, do the right thing
|
22
|
+
if name == :queue
|
23
|
+
return Resque.queue_from_class(self)
|
24
|
+
end
|
25
|
+
super
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def __queue__
|
31
|
+
Queue.new(queue)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require "resque"
|
2
|
+
|
3
|
+
module Ddr::Jobs
|
4
|
+
class Queue
|
5
|
+
|
6
|
+
attr_reader :name
|
7
|
+
|
8
|
+
def initialize(name)
|
9
|
+
@name = name
|
10
|
+
end
|
11
|
+
|
12
|
+
def size
|
13
|
+
Resque.size(name)
|
14
|
+
end
|
15
|
+
|
16
|
+
# @return [Array<Hash>] jobs in the queue, optionally filtered by type,
|
17
|
+
# start position, and count.
|
18
|
+
def jobs(type: nil, start: 0, count: nil)
|
19
|
+
jobs = Resque.peek(name, start, count || size)
|
20
|
+
if type
|
21
|
+
jobs.select! { |job| job["class"] == type.to_s }
|
22
|
+
end
|
23
|
+
jobs
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
end
|
data/lib/ddr/models.rb
CHANGED
@@ -7,15 +7,14 @@ require 'hydra/validations'
|
|
7
7
|
|
8
8
|
module Ddr
|
9
9
|
extend ActiveSupport::Autoload
|
10
|
+
extend Deprecation
|
10
11
|
|
11
12
|
autoload :Actions
|
12
13
|
autoload :Auth
|
13
|
-
autoload :Contacts
|
14
14
|
autoload :Datastreams
|
15
15
|
autoload :Derivatives
|
16
16
|
autoload :Events
|
17
17
|
autoload :Index
|
18
|
-
autoload :IndexFields
|
19
18
|
autoload :Jobs
|
20
19
|
autoload :Managers
|
21
20
|
autoload :Metadata
|
@@ -23,19 +22,30 @@ module Ddr
|
|
23
22
|
autoload :Utils
|
24
23
|
autoload :Vocab
|
25
24
|
|
25
|
+
def self.const_missing(name)
|
26
|
+
if name == :IndexFields
|
27
|
+
Deprecation.warn(Ddr::Models, "`Ddr::IndexFields` is deprecated and will be removed in ddr-models 3.0." \
|
28
|
+
" Use `Ddr::Index::Fields` instead.")
|
29
|
+
Index::Fields
|
30
|
+
else
|
31
|
+
super
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
26
35
|
module Models
|
27
36
|
extend ActiveSupport::Autoload
|
28
37
|
|
29
|
-
autoload :AccessControllable
|
30
38
|
autoload :AdminSet
|
31
39
|
autoload :AttachedFileProfile
|
32
40
|
autoload :AttachedFilesProfile
|
33
41
|
autoload :Base
|
34
42
|
autoload :ChecksumInvalid, 'ddr/models/error'
|
43
|
+
autoload :Contact
|
35
44
|
autoload :ContentModelError, 'ddr/models/error'
|
36
45
|
autoload :DerivativeGenerationFailure, 'ddr/models/error'
|
37
46
|
autoload :Error
|
38
47
|
autoload :EventLoggable
|
48
|
+
autoload :FileCharacterization
|
39
49
|
autoload :FileManagement
|
40
50
|
autoload :FindingAid
|
41
51
|
autoload :FixityCheckable
|
@@ -48,6 +58,7 @@ module Ddr
|
|
48
58
|
autoload :HasStructMetadata
|
49
59
|
autoload :HasThumbnail
|
50
60
|
autoload :Indexing
|
61
|
+
autoload :NotFoundError, 'ddr/models/error'
|
51
62
|
autoload :ObjectApi
|
52
63
|
autoload :SolrDocument
|
53
64
|
autoload :StructDiv
|
@@ -55,6 +66,7 @@ module Ddr
|
|
55
66
|
autoload :UrlSafeId
|
56
67
|
autoload :Validatable
|
57
68
|
autoload :Validator
|
69
|
+
autoload :WithContentFile
|
58
70
|
autoload :YearFacet
|
59
71
|
|
60
72
|
autoload_under "licenses" do
|
@@ -113,6 +125,11 @@ module Ddr
|
|
113
125
|
"http://library.duke.edu/rubenstein/findingaids/"
|
114
126
|
end
|
115
127
|
|
128
|
+
# Application temp dir - defaults to system temp dir
|
129
|
+
mattr_accessor :tempdir do
|
130
|
+
Dir.tmpdir
|
131
|
+
end
|
132
|
+
|
116
133
|
# Yields an object with module configuration accessors
|
117
134
|
def self.configure
|
118
135
|
yield self
|