ddr-models 3.0.0.beta.3 → 3.0.0.beta.4
Sign up to get free protection for your applications and to get access to all the features.
- 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
|