iiif_print 1.1.0 → 2.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +1 -1
- data/Gemfile.lock +2 -2
- data/README.md +4 -0
- data/app/actors/iiif_print/actors/file_set_actor_decorator.rb +1 -1
- data/app/indexers/concerns/iiif_print/child_work_indexer.rb +27 -0
- data/app/indexers/concerns/iiif_print/file_set_indexer.rb +37 -22
- data/{lib → app/jobs}/iiif_print/jobs/application_job.rb +2 -1
- data/{lib → app/jobs}/iiif_print/jobs/child_works_from_pdf_job.rb +14 -9
- data/{lib → app/jobs}/iiif_print/jobs/create_relationships_job.rb +10 -20
- data/app/listeners/iiif_print/listener.rb +31 -0
- data/app/models/concerns/iiif_print/set_child_flag.rb +1 -1
- data/app/models/concerns/iiif_print/solr/document.rb +5 -3
- data/app/presenters/iiif_print/file_set_presenter_decorator.rb +11 -0
- data/app/presenters/iiif_print/iiif_manifest_presenter_factory_behavior.rb +1 -1
- data/app/presenters/iiif_print/work_show_presenter_decorator.rb +5 -2
- data/app/services/iiif_print/manifest_builder_service_behavior.rb +4 -2
- data/app/services/iiif_print/pluggable_derivative_service.rb +5 -1
- data/app/services/iiif_print/simple_schema_loader_decorator.rb +11 -0
- data/app/transactions/hyrax/transactions/iiif_print_container_decorator.rb +34 -0
- data/app/transactions/hyrax/transactions/steps/conditionally_destroy_children_from_split.rb +32 -0
- data/app/transactions/hyrax/transactions/steps/delete_all_file_sets_decorator.rb +35 -0
- data/app/views/hyrax/file_sets/_show_actions.html.erb +1 -1
- data/config/initializers/simple_schema_loader.rb +1 -0
- data/config/metadata/child_works_from_pdf_splitting.yaml +17 -0
- data/db/migrate/20181214181358_create_iiif_print_derivative_attachments.rb +8 -6
- data/db/migrate/20190107165909_create_iiif_print_ingest_file_relations.rb +7 -5
- data/db/migrate/20230109000000_create_iiif_print_pending_relationships.rb +8 -6
- data/db/migrate/20231110163052_add_model_details_to_iiif_print_pending_relationships.rb +3 -3
- data/iiif_print.gemspec +1 -1
- data/lib/iiif_print/base_derivative_service.rb +13 -2
- data/lib/iiif_print/blacklight_iiif_search/annotation_decorator.rb +2 -2
- data/lib/iiif_print/catalog_search_builder.rb +2 -2
- data/lib/iiif_print/configuration.rb +65 -5
- data/lib/iiif_print/data/fileset_helper.rb +2 -2
- data/lib/iiif_print/data/work_derivatives.rb +1 -1
- data/lib/iiif_print/engine.rb +46 -2
- data/lib/iiif_print/homepage_search_builder.rb +2 -2
- data/lib/iiif_print/jp2_derivative_service.rb +4 -1
- data/lib/iiif_print/lineage_service.rb +19 -6
- data/lib/iiif_print/pdf_derivative_service.rb +3 -1
- data/lib/iiif_print/persistence_layer/active_fedora_adapter.rb +189 -0
- data/lib/iiif_print/persistence_layer/valkyrie_adapter.rb +183 -0
- data/lib/iiif_print/persistence_layer.rb +118 -0
- data/lib/iiif_print/split_pdfs/base_splitter.rb +11 -0
- data/lib/iiif_print/split_pdfs/child_work_creation_from_pdf_service.rb +19 -9
- data/lib/iiif_print/split_pdfs/destroy_pdf_child_works_service.rb +5 -16
- data/lib/iiif_print/text_extraction_derivative_service.rb +4 -2
- data/lib/iiif_print/text_formats_from_alto_service.rb +3 -1
- data/lib/iiif_print/tiff_derivative_service.rb +3 -1
- data/lib/iiif_print/version.rb +1 -1
- data/lib/iiif_print.rb +79 -44
- metadata +19 -192
- data/app/indexers/concerns/iiif_print/child_indexer.rb +0 -40
- data/app/views/hyrax/file_sets/_actions.html.erb +0 -46
- data/bin/rails +0 -13
- data/spec/.keep.txt +0 -1
- data/spec/factories/ability.rb +0 -6
- data/spec/factories/newspaper_issue.rb +0 -7
- data/spec/factories/newspaper_page.rb +0 -7
- data/spec/factories/newspaper_page_solr_document.rb +0 -20
- data/spec/factories/newspaper_title.rb +0 -8
- data/spec/factories/uploaded_pdf_file.rb +0 -9
- data/spec/factories/uploaded_txt_file.rb +0 -9
- data/spec/factories/user.rb +0 -13
- data/spec/fixtures/authorities/licenses.yml +0 -4
- data/spec/fixtures/authorities/rights_statements.yml +0 -4
- data/spec/fixtures/files/4.1.07.jp2 +0 -0
- data/spec/fixtures/files/4.1.07.tiff +0 -0
- data/spec/fixtures/files/README.md +0 -7
- data/spec/fixtures/files/alto-2-0.xsd +0 -714
- data/spec/fixtures/files/broken-truncated.pdf +0 -0
- data/spec/fixtures/files/credits.md +0 -16
- data/spec/fixtures/files/lowres-gray-via-ndnp-sample.tiff +0 -0
- data/spec/fixtures/files/minimal-1-page.pdf +0 -0
- data/spec/fixtures/files/minimal-2-page.pdf +0 -0
- data/spec/fixtures/files/minimal-alto.xml +0 -31
- data/spec/fixtures/files/ndnp-alto-sample.xml +0 -24
- data/spec/fixtures/files/ndnp-sample1-json.json +0 -1
- data/spec/fixtures/files/ndnp-sample1-txt.txt +0 -1
- data/spec/fixtures/files/ndnp-sample1.pdf +0 -0
- data/spec/fixtures/files/ocr_alto.xml +0 -202
- data/spec/fixtures/files/ocr_alto_scaled_4pts_per_px.xml +0 -202
- data/spec/fixtures/files/ocr_color.tiff +0 -0
- data/spec/fixtures/files/ocr_gray.jp2 +0 -0
- data/spec/fixtures/files/ocr_gray.tiff +0 -0
- data/spec/fixtures/files/ocr_mono.tiff +0 -0
- data/spec/fixtures/files/ocr_mono_text_hocr.html +0 -78
- data/spec/fixtures/files/page1.tiff +0 -0
- data/spec/fixtures/files/sample-4page-issue.pdf +0 -0
- data/spec/fixtures/files/sample-color-newsletter.pdf +0 -0
- data/spec/fixtures/files/thumbnail.jpg +0 -0
- data/spec/helpers/hyrax/iiif_helper_spec.rb +0 -65
- data/spec/helpers/iiif_print_helper_spec.rb +0 -43
- data/spec/iiif_print/base_derivative_service_spec.rb +0 -28
- data/spec/iiif_print/blacklight_iiif_search/annotation_decorator_spec.rb +0 -59
- data/spec/iiif_print/catalog_search_builder_spec.rb +0 -60
- data/spec/iiif_print/configuration_spec.rb +0 -193
- data/spec/iiif_print/data/work_derivatives_spec.rb +0 -245
- data/spec/iiif_print/data/work_file_spec.rb +0 -99
- data/spec/iiif_print/data/work_files_spec.rb +0 -237
- data/spec/iiif_print/image_tool_spec.rb +0 -109
- data/spec/iiif_print/jobs/child_works_from_pdf_job_spec.rb +0 -35
- data/spec/iiif_print/jobs/create_relationships_job_spec.rb +0 -118
- data/spec/iiif_print/jp2_image_metadata_spec.rb +0 -37
- data/spec/iiif_print/lineage_service_spec.rb +0 -13
- data/spec/iiif_print/metadata_spec.rb +0 -249
- data/spec/iiif_print/split_pdfs/base_splitter_spec.rb +0 -27
- data/spec/iiif_print/split_pdfs/derivative_rodeo_splitter_spec.rb +0 -80
- data/spec/iiif_print/split_pdfs/destroy_pdf_child_works_service_spec.rb +0 -92
- data/spec/iiif_print/split_pdfs/pages_to_jpgs_splitter_spec.rb +0 -22
- data/spec/iiif_print/split_pdfs/pages_to_pngs_splitter_spec.rb +0 -18
- data/spec/iiif_print/split_pdfs/pages_to_tiffs_splitter_spec.rb +0 -19
- data/spec/iiif_print/text_extraction/alto_reader_spec.rb +0 -49
- data/spec/iiif_print/text_extraction/hocr_reader_spec.rb +0 -45
- data/spec/iiif_print/text_extraction/page_ocr_spec.rb +0 -84
- data/spec/iiif_print/text_extraction/render_alto_spec.rb +0 -54
- data/spec/iiif_print/text_extraction/word_coords_builder_spec.rb +0 -44
- data/spec/iiif_print_spec.rb +0 -171
- data/spec/misc_shared.rb +0 -111
- data/spec/models/iiif_print/derivative_attachment_spec.rb +0 -37
- data/spec/models/iiif_print/iiif_search_decorator_spec.rb +0 -27
- data/spec/models/iiif_print/ingest_file_relation_spec.rb +0 -56
- data/spec/models/solr_document_spec.rb +0 -14
- data/spec/presenters/iiif_print/iiif_manifest_presenter_behavior_spec.rb +0 -70
- data/spec/presenters/iiif_print/iiif_manifest_presenter_factory_behavior_spec.rb +0 -49
- data/spec/samvera/derivatives/configuration_spec.rb +0 -41
- data/spec/samvera/derivatives/hyrax_spec.rb +0 -62
- data/spec/samvera/derivatives_spec.rb +0 -54
- data/spec/services/iiif_print/derivative_rodeo_service_spec.rb +0 -103
- data/spec/services/iiif_print/jp2_derivative_service_spec.rb +0 -59
- data/spec/services/iiif_print/manifest_builder_service_behavior_spec.rb +0 -20
- data/spec/services/iiif_print/pdf_derivative_service_spec.rb +0 -66
- data/spec/services/iiif_print/pluggable_derivative_service_spec.rb +0 -175
- data/spec/services/iiif_print/text_extraction_derivative_service_spec.rb +0 -82
- data/spec/services/iiif_print/text_formats_from_alto_service_spec.rb +0 -127
- data/spec/services/iiif_print/tiff_derivative_service_spec.rb +0 -65
- data/spec/spec_helper.rb +0 -181
- data/spec/support/controller_level_helpers.rb +0 -28
- data/spec/support/iiif_print_models.rb +0 -127
- data/spec/test_app_templates/blacklight.yml +0 -9
- data/spec/test_app_templates/fedora.yml +0 -15
- data/spec/test_app_templates/lib/generators/test_app_generator.rb +0 -40
- data/spec/test_app_templates/redis.yml +0 -9
- data/spec/test_app_templates/solr/conf/schema.xml +0 -362
- data/spec/test_app_templates/solr/conf/solrconfig.xml +0 -322
- data/spec/test_app_templates/solr.yml +0 -7
- /data/{lib → app/jobs}/iiif_print/jobs/request_split_pdf_job.rb +0 -0
@@ -1,84 +0,0 @@
|
|
1
|
-
require 'json'
|
2
|
-
require 'nokogiri'
|
3
|
-
require 'spec_helper'
|
4
|
-
|
5
|
-
RSpec.describe IiifPrint::TextExtraction::PageOCR do
|
6
|
-
let(:fixture_path) do
|
7
|
-
File.join(
|
8
|
-
IiifPrint::GEM_PATH, 'spec', 'fixtures', 'files'
|
9
|
-
)
|
10
|
-
end
|
11
|
-
|
12
|
-
let(:altoxsd) do
|
13
|
-
xsdpath = File.join(fixture_path, 'alto-2-0.xsd')
|
14
|
-
Nokogiri::XML::Schema(File.read(xsdpath))
|
15
|
-
end
|
16
|
-
|
17
|
-
# sample "snippet" images for OCR testing:
|
18
|
-
let(:example_gray_tiff) { File.join(fixture_path, 'ocr_gray.tiff') }
|
19
|
-
let(:example_mono_tiff) { File.join(fixture_path, 'ocr_mono.tiff') }
|
20
|
-
let(:example_color_tiff) { File.join(fixture_path, 'ocr_color.tiff') }
|
21
|
-
let(:example_gray_jp2) { File.join(fixture_path, 'ocr_gray.jp2') }
|
22
|
-
let(:ocr_from_gray_tiff) { described_class.new(example_gray_tiff) }
|
23
|
-
|
24
|
-
describe "performs OCR" do
|
25
|
-
def match_ocr_expectations(words)
|
26
|
-
expect(words).to be_an(Array)
|
27
|
-
expect(words).not_to be_empty
|
28
|
-
expect(words[0]).to be_a(Hash)
|
29
|
-
[:word, :coordinates].each do |key|
|
30
|
-
expect(words[0].keys).to include key
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
it "gets words and coordinates from grayscale source" do
|
35
|
-
match_ocr_expectations(ocr_from_gray_tiff.words)
|
36
|
-
end
|
37
|
-
|
38
|
-
it "gets words and coordinates from one-bit source" do
|
39
|
-
ocr = described_class.new(example_mono_tiff)
|
40
|
-
match_ocr_expectations(ocr.words)
|
41
|
-
end
|
42
|
-
|
43
|
-
it "gets words and coordinates from color source" do
|
44
|
-
ocr = described_class.new(example_color_tiff)
|
45
|
-
match_ocr_expectations(ocr.words)
|
46
|
-
end
|
47
|
-
|
48
|
-
it "gets words and coordinates from jp2 source" do
|
49
|
-
ocr = described_class.new(example_gray_jp2)
|
50
|
-
match_ocr_expectations(ocr.words)
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
describe "turns image into ALTO" do
|
55
|
-
xit "takes grayscale tiff, outputs valid ALTO, geometry" do
|
56
|
-
alto = ocr_from_gray_tiff.alto
|
57
|
-
document = Nokogiri::XML(alto)
|
58
|
-
errors = altoxsd.validate(document)
|
59
|
-
expect(errors.length).to eq 0
|
60
|
-
expect(document.at_css('PrintSpace')['WIDTH']).to eq "418"
|
61
|
-
expect(document.at_css('PrintSpace')['HEIGHT']).to eq "1046"
|
62
|
-
end
|
63
|
-
end
|
64
|
-
|
65
|
-
describe "plain text" do
|
66
|
-
it "makes plain text available for image" do
|
67
|
-
plain = ocr_from_gray_tiff.plain
|
68
|
-
expect(plain.class).to be String
|
69
|
-
expect(plain.length).to be > 0
|
70
|
-
end
|
71
|
-
end
|
72
|
-
|
73
|
-
describe "JSON word coordinates" do
|
74
|
-
it "passes properly formatted data to WordCoordsBuilder and receives output" do
|
75
|
-
parsed = JSON.parse(ocr_from_gray_tiff.word_json)
|
76
|
-
expect(parsed['coords'].length).to be > 1
|
77
|
-
word = ocr_from_gray_tiff.words[0]
|
78
|
-
word1 = parsed['coords'][word[:word]]
|
79
|
-
word1_coords = word1[0]
|
80
|
-
expect(word1_coords[2]).to eq word[:coordinates][2]
|
81
|
-
expect(word1_coords[3]).to eq word[:coordinates][3]
|
82
|
-
end
|
83
|
-
end
|
84
|
-
end
|
@@ -1,54 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
RSpec.describe IiifPrint::TextExtraction::RenderAlto do
|
4
|
-
let(:fixture_path) do
|
5
|
-
File.join(
|
6
|
-
IiifPrint::GEM_PATH, 'spec', 'fixtures', 'files'
|
7
|
-
)
|
8
|
-
end
|
9
|
-
|
10
|
-
let(:altoxsd) do
|
11
|
-
xsdpath = File.join(fixture_path, 'alto-2-0.xsd')
|
12
|
-
Nokogiri::XML::Schema(File.read(xsdpath))
|
13
|
-
end
|
14
|
-
|
15
|
-
let(:page_prefix) { '<Page ID="ID1" PHYSICAL_IMG_NR="1"' }
|
16
|
-
|
17
|
-
let(:words) do
|
18
|
-
[
|
19
|
-
{ word: "If", coordinates: [52, 13, 11, 14] },
|
20
|
-
{ word: "you", coordinates: [69, 17, 31, 14] },
|
21
|
-
{ word: "are", coordinates: [108, 17, 28, 10] },
|
22
|
-
{ word: "a", coordinates: [143, 17, 8, 10] },
|
23
|
-
{ word: "friend,", coordinates: [158, 13, 56, 16] },
|
24
|
-
{ word: "you", coordinates: [51, 39, 31, 14] },
|
25
|
-
{ word: "speak", coordinates: [90, 35, 50, 18] },
|
26
|
-
{ word: "the", coordinates: [146, 35, 28, 14] },
|
27
|
-
{ word: "password,", coordinates: [182, 35, 85, 18] },
|
28
|
-
{ word: "and", coordinates: [51, 57, 30, 14] },
|
29
|
-
{ word: "the", coordinates: [89, 57, 28, 14] },
|
30
|
-
{ word: "doors", coordinates: [124, 57, 48, 14] },
|
31
|
-
{ word: "will", coordinates: [180, 57, 28, 14] },
|
32
|
-
{ word: "open.", coordinates: [216, 61, 47, 14] }
|
33
|
-
]
|
34
|
-
end
|
35
|
-
|
36
|
-
describe "renders alto" do
|
37
|
-
it "creates alto given width, height, words" do
|
38
|
-
renderer = described_class.new(12_000, 9600)
|
39
|
-
output = renderer.to_alto(words)
|
40
|
-
expect(output.class).to be String
|
41
|
-
expect(output).to include '<alto'
|
42
|
-
expect(output).to include '<String'
|
43
|
-
expect(output).to include page_prefix + ' HEIGHT="9600" WIDTH="12000"'
|
44
|
-
expect(Nokogiri::XML(output).errors.empty?).to be true
|
45
|
-
end
|
46
|
-
|
47
|
-
xit "makes alto 2.0 that validates" do
|
48
|
-
renderer = described_class.new(12_000, 9600)
|
49
|
-
output = renderer.to_alto(words)
|
50
|
-
document = Nokogiri::XML(output)
|
51
|
-
altoxsd.validate(document)
|
52
|
-
end
|
53
|
-
end
|
54
|
-
end
|
@@ -1,44 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
RSpec.describe IiifPrint::TextExtraction::WordCoordsBuilder do
|
4
|
-
let(:words) do
|
5
|
-
[
|
6
|
-
{ word: "foo", coordinates: [1, 2, 3, 4] },
|
7
|
-
{ word: "bar", coordinates: [5, 6, 7, 8] },
|
8
|
-
{ word: "baz", coordinates: [9, 10, 11, 12] },
|
9
|
-
{ word: "foo", coordinates: [13, 14, 15, 16] }
|
10
|
-
]
|
11
|
-
end
|
12
|
-
let(:image_width) { 1_234 }
|
13
|
-
let(:image_height) { 5_678 }
|
14
|
-
|
15
|
-
describe '.json_coordinates_for' do
|
16
|
-
let(:wcb_to_json) { JSON.parse(described_class.json_coordinates_for(words: words, width: image_width, height: image_height)) }
|
17
|
-
it 'has the correct structure' do
|
18
|
-
expect(wcb_to_json['height']).to eq image_height
|
19
|
-
expect(wcb_to_json['width']).to eq image_width
|
20
|
-
expect(wcb_to_json['coords'].length).to eq 3
|
21
|
-
expect(wcb_to_json['coords']['foo']).not_to be_falsey
|
22
|
-
end
|
23
|
-
|
24
|
-
it 'combines coordinates for the same word' do
|
25
|
-
expect(wcb_to_json['coords']['foo']).to eq [[1, 2, 3, 4], [13, 14, 15, 16]]
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
describe '#to_json' do
|
30
|
-
let(:wcb_to_json) { JSON.parse(wcb.to_json) }
|
31
|
-
let(:wcb) { described_class.new(words, image_width, image_height) }
|
32
|
-
|
33
|
-
it 'has the correct structure' do
|
34
|
-
expect(wcb_to_json['height']).to eq image_height
|
35
|
-
expect(wcb_to_json['width']).to eq image_width
|
36
|
-
expect(wcb_to_json['coords'].length).to eq 3
|
37
|
-
expect(wcb_to_json['coords']['foo']).not_to be_falsey
|
38
|
-
end
|
39
|
-
|
40
|
-
it 'combines coordinates for the same word' do
|
41
|
-
expect(wcb_to_json['coords']['foo']).to eq [[1, 2, 3, 4], [13, 14, 15, 16]]
|
42
|
-
end
|
43
|
-
end
|
44
|
-
end
|
data/spec/iiif_print_spec.rb
DELETED
@@ -1,171 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
RSpec.describe IiifPrint do
|
4
|
-
describe '.skip_splitting_pdf_files_that_end_with_these_texts' do
|
5
|
-
subject { described_class }
|
6
|
-
it { is_expected.to respond_to :skip_splitting_pdf_files_that_end_with_these_texts }
|
7
|
-
end
|
8
|
-
|
9
|
-
describe ".manifest_metadata_for" do
|
10
|
-
let(:attributes) do
|
11
|
-
{ "id" => "abc123",
|
12
|
-
"title_tesim" => ['My Awesome Title'] }
|
13
|
-
end
|
14
|
-
let(:solr_document) { SolrDocument.new(attributes) }
|
15
|
-
let(:base_url) { "https://my.dev.test" }
|
16
|
-
|
17
|
-
subject(:manifest_metadata) do
|
18
|
-
described_class.manifest_metadata_for(work: solr_document, current_ability: double(Ability), base_url: base_url)
|
19
|
-
end
|
20
|
-
it { is_expected.not_to be_falsey }
|
21
|
-
it "does not contain any nil values" do
|
22
|
-
expect(subject).not_to include(nil)
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
describe ".model_configuration" do
|
27
|
-
context "default configuration" do
|
28
|
-
let(:model) do
|
29
|
-
Class.new do
|
30
|
-
include IiifPrint.model_configuration(pdf_split_child_model: Class.new)
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
subject(:record) { model.new }
|
35
|
-
|
36
|
-
it { is_expected.to be_iiif_print_config }
|
37
|
-
|
38
|
-
it "has a #pdf_splitter_job" do
|
39
|
-
expect(record.iiif_print_config.pdf_splitter_job).to be(IiifPrint::Jobs::ChildWorksFromPdfJob)
|
40
|
-
end
|
41
|
-
|
42
|
-
it "has a #pdf_splitter_service" do
|
43
|
-
expect(record.iiif_print_config.pdf_splitter_service).to be(IiifPrint::SplitPdfs::PagesToJpgsSplitter)
|
44
|
-
end
|
45
|
-
|
46
|
-
it "has #derivative_service_plugins" do
|
47
|
-
expect(record.iiif_print_config.derivative_service_plugins).to eq(
|
48
|
-
[IiifPrint::TextExtractionDerivativeService]
|
49
|
-
)
|
50
|
-
end
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
describe ".fields_for_allinson_flex" do
|
55
|
-
subject { described_class.fields_for_allinson_flex(fields: fields, sort_order: sort_order) }
|
56
|
-
let(:sort_order) { [] }
|
57
|
-
|
58
|
-
context "when the fields include an admin only indexing property" do
|
59
|
-
let(:fields) do
|
60
|
-
[
|
61
|
-
IiifPrint::CollectionFieldShim.new(name: :title, value: "My Title"),
|
62
|
-
IiifPrint::CollectionFieldShim.new(name: :creator, value: "Hyrax, Sam", indexing: ["admin_only"])
|
63
|
-
]
|
64
|
-
end
|
65
|
-
|
66
|
-
it "does not include the admin only field" do
|
67
|
-
# We are mapping from one data structure to another
|
68
|
-
expect(subject.map(&:name)).to eq([fields.first.name])
|
69
|
-
end
|
70
|
-
end
|
71
|
-
|
72
|
-
context "when the fields include duplicate name properties" do
|
73
|
-
let(:fields) do
|
74
|
-
[
|
75
|
-
IiifPrint::CollectionFieldShim.new(name: :title, value: "My Title"),
|
76
|
-
IiifPrint::CollectionFieldShim.new(name: :title, value: "My Other Title")
|
77
|
-
]
|
78
|
-
end
|
79
|
-
|
80
|
-
it "does not include later duplicates" do
|
81
|
-
expect(subject.map(&:label)).to eq([fields.first.value])
|
82
|
-
end
|
83
|
-
end
|
84
|
-
|
85
|
-
context "when we provide a fields sort order" do
|
86
|
-
let(:fields) do
|
87
|
-
[
|
88
|
-
IiifPrint::CollectionFieldShim.new(name: :title, value: "My Title"),
|
89
|
-
IiifPrint::CollectionFieldShim.new(name: :creator, value: "Hyrax, Sam"),
|
90
|
-
IiifPrint::CollectionFieldShim.new(name: :date_created, value: "2023-05-02")
|
91
|
-
]
|
92
|
-
end
|
93
|
-
let(:sort_order) { [:creator, :title] }
|
94
|
-
|
95
|
-
it "returns the fields in the order specified and puts unspecified fields last" do
|
96
|
-
expect(subject.map(&:name)).to eq([:creator, :title, :date_created])
|
97
|
-
end
|
98
|
-
end
|
99
|
-
end
|
100
|
-
|
101
|
-
describe ".sort_af_fields!" do
|
102
|
-
let(:fields) { [:title, :creator, :date_created].map { |name| IiifPrint::Field.new(name: name) } }
|
103
|
-
subject(:sort_af_fields) { described_class.sort_af_fields!(fields, sort_order: sort_order) }
|
104
|
-
|
105
|
-
context "when the sort order is an empty array" do
|
106
|
-
let(:sort_order) { [] }
|
107
|
-
|
108
|
-
it "returns the fields in the order they were given" do
|
109
|
-
expect(sort_af_fields).to eq(fields)
|
110
|
-
end
|
111
|
-
end
|
112
|
-
|
113
|
-
context "when the sort order specifies some of the fields" do
|
114
|
-
let(:sort_order) { [:date_created, :title] }
|
115
|
-
|
116
|
-
it "returns the fields in the order specified and puts unspecified fields last" do
|
117
|
-
expect(sort_af_fields).to eq([:date_created, :title, :creator].map { |name| IiifPrint::Field.new(name: name) })
|
118
|
-
end
|
119
|
-
end
|
120
|
-
end
|
121
|
-
|
122
|
-
describe '.conditionally_submit_split_for' do
|
123
|
-
context 'when the file suffix is one that we skip' do
|
124
|
-
subject do
|
125
|
-
described_class.conditionally_submit_split_for(
|
126
|
-
work: double,
|
127
|
-
file_set: double,
|
128
|
-
locations: ['hello.reader.pdf'],
|
129
|
-
skip_these_endings: ['.reader.pdf'],
|
130
|
-
user: double
|
131
|
-
)
|
132
|
-
end
|
133
|
-
|
134
|
-
it { is_expected.to eq(:no_pdfs_for_splitting) }
|
135
|
-
end
|
136
|
-
end
|
137
|
-
|
138
|
-
describe '.split_for_path_suffix?' do
|
139
|
-
context 'with default .skip_splitting_pdf_files_that_end_with_these_texts' do
|
140
|
-
subject { described_class.split_for_path_suffix?(path) }
|
141
|
-
[
|
142
|
-
["hello.pdf", true],
|
143
|
-
["hello.PDF", true],
|
144
|
-
["hello.reader.pdf", true],
|
145
|
-
["hello.png", false],
|
146
|
-
["hello.pdf.png", false]
|
147
|
-
].each do |given_path, expected_value|
|
148
|
-
context "with #{given_path.inspect}" do
|
149
|
-
let(:path) { given_path }
|
150
|
-
it { is_expected.to eq(expected_value) }
|
151
|
-
end
|
152
|
-
end
|
153
|
-
end
|
154
|
-
|
155
|
-
context 'with customized .skip_splitting_pdf_files_that_end_with_these_texts' do
|
156
|
-
subject { described_class.split_for_path_suffix?(path, skip_these_endings: ['.READER.pdf']) }
|
157
|
-
[
|
158
|
-
["hello.pdf", true],
|
159
|
-
["hello.PDF", true],
|
160
|
-
["hello.reader.pdf", false],
|
161
|
-
["hello.png", false],
|
162
|
-
["hello.pdf.png", false]
|
163
|
-
].each do |given_path, expected_value|
|
164
|
-
context "with #{given_path.inspect}" do
|
165
|
-
let(:path) { given_path }
|
166
|
-
it { is_expected.to eq(expected_value) }
|
167
|
-
end
|
168
|
-
end
|
169
|
-
end
|
170
|
-
end
|
171
|
-
end
|
data/spec/misc_shared.rb
DELETED
@@ -1,111 +0,0 @@
|
|
1
|
-
RSpec.shared_context "shared setup", shared_context: :metadata do
|
2
|
-
let(:fixture_path) do
|
3
|
-
path = File.join(
|
4
|
-
IiifPrint::GEM_PATH, 'spec', 'fixtures', 'files'
|
5
|
-
)
|
6
|
-
# TODO: NOTE: this has potential timing issues in the specs, because we're adjusting the
|
7
|
-
# configured value during the spec run.
|
8
|
-
registered = Hyrax.config.registered_ingest_dirs
|
9
|
-
registered.push(path) unless registered.include?(path)
|
10
|
-
path
|
11
|
-
end
|
12
|
-
|
13
|
-
# shared date to be invariant across all tests in a run:
|
14
|
-
date_static = Hyrax::TimeService.time_in_utc
|
15
|
-
let(:static_date) { date_static }
|
16
|
-
|
17
|
-
# path fixtures:
|
18
|
-
let(:example_gray_jp2) { File.join(fixture_path, 'ocr_gray.jp2') }
|
19
|
-
let(:txt_path) { File.join(fixture_path, 'credits.md') }
|
20
|
-
let(:sample_thumbnail) { File.join(fixture_path, 'thumbnail.jpg') }
|
21
|
-
|
22
|
-
# sample data:
|
23
|
-
let(:sample_text) { 'even in a mythical Age there must be some enigmas' }
|
24
|
-
|
25
|
-
let(:valid_file_set) do
|
26
|
-
file_set = FileSet.new
|
27
|
-
file_set.save!(validate: false)
|
28
|
-
file_set
|
29
|
-
end
|
30
|
-
|
31
|
-
let(:sample_work) do
|
32
|
-
work = MyWork.new
|
33
|
-
work.title = ['Bombadil']
|
34
|
-
work.members.push(valid_file_set)
|
35
|
-
work.save!
|
36
|
-
work
|
37
|
-
end
|
38
|
-
|
39
|
-
# sample objects:
|
40
|
-
let(:work_with_file) do
|
41
|
-
# we need a work with not just a valid (but empty) fileset, but also
|
42
|
-
# a persisted file, so we use the shared work sample, and expand
|
43
|
-
# on it with actual file data/metadata.
|
44
|
-
work = sample_work
|
45
|
-
fileset = work.members.first
|
46
|
-
file = Hydra::PCDM::File.create
|
47
|
-
fileset.original_file = file
|
48
|
-
# Set binary content on file via ActiveFedora content= mutator method
|
49
|
-
# which also makes .size method return valid result for content
|
50
|
-
file.content = File.open(txt_path)
|
51
|
-
# Set some metdata we would expect to otherwise be set upon an upload
|
52
|
-
file.original_name = 'credits.md'
|
53
|
-
file.mime_type = 'text/plain'
|
54
|
-
file.date_modified = static_date
|
55
|
-
file.date_created = static_date
|
56
|
-
# saving fileset also saves file content
|
57
|
-
fileset.save!
|
58
|
-
work
|
59
|
-
end
|
60
|
-
|
61
|
-
def path_factory
|
62
|
-
Hyrax::DerivativePath
|
63
|
-
end
|
64
|
-
|
65
|
-
def work_file_set(work)
|
66
|
-
work.members.detect { |m| m.is_a? FileSet }
|
67
|
-
end
|
68
|
-
|
69
|
-
def text_path(work)
|
70
|
-
path_factory.derivative_path_for_reference(work_file_set(work), 'txt')
|
71
|
-
end
|
72
|
-
|
73
|
-
def jp2_path(work)
|
74
|
-
path_factory.derivative_path_for_reference(work_file_set(work), 'jp2')
|
75
|
-
end
|
76
|
-
|
77
|
-
def thumbnail_path(work)
|
78
|
-
path_factory.derivative_path_for_reference(work_file_set(work), 'thumbnail')
|
79
|
-
end
|
80
|
-
|
81
|
-
def mkdir_derivative(work, name)
|
82
|
-
# make shared path for derivatives to live, Hyrax ususally does this
|
83
|
-
# for thumbnails, and iiif_print does this in its derivative
|
84
|
-
# service plugins; here we do same.
|
85
|
-
fsid = work_file_set(work).id
|
86
|
-
path = path_factory.derivative_path_for_reference(fsid, name)
|
87
|
-
dir = File.join(path.split('/')[0..-2])
|
88
|
-
FileUtils.mkdir_p(dir) unless Dir.exist?(dir)
|
89
|
-
end
|
90
|
-
|
91
|
-
def mk_jp2_derivative(work)
|
92
|
-
mkdir_derivative(work, 'jp2')
|
93
|
-
dst_path = jp2_path(work)
|
94
|
-
FileUtils.copy(example_gray_jp2, dst_path)
|
95
|
-
expect(File.exist?(dst_path)).to be true
|
96
|
-
end
|
97
|
-
|
98
|
-
def mk_txt_derivative(work)
|
99
|
-
mkdir_derivative(work, 'txt')
|
100
|
-
dst_path = text_path(work)
|
101
|
-
File.open(dst_path, 'w') { |f| f.write(sample_text) }
|
102
|
-
expect(File.exist?(dst_path)).to be true
|
103
|
-
end
|
104
|
-
|
105
|
-
def mk_thumbnail_derivative(work)
|
106
|
-
mkdir_derivative(work, 'thumbnail')
|
107
|
-
dst_path = thumbnail_path(work)
|
108
|
-
FileUtils.copy(sample_thumbnail, dst_path)
|
109
|
-
expect(File.exist?(dst_path)).to be true
|
110
|
-
end
|
111
|
-
end
|
@@ -1,37 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
module IiifPrint
|
4
|
-
RSpec.describe DerivativeAttachment, type: :model do
|
5
|
-
it "requires some columns to be considered complete" do
|
6
|
-
model = described_class.create
|
7
|
-
# attempt save without required data; expect failure
|
8
|
-
expect { model.save! }.to raise_exception(ActiveRecord::RecordInvalid)
|
9
|
-
end
|
10
|
-
|
11
|
-
it "saves when constructed with all field values" do
|
12
|
-
model = described_class.create(
|
13
|
-
fileset_id: 'a1b2c3d4e5',
|
14
|
-
path: '/path/to/somefile',
|
15
|
-
destination_name: 'txt'
|
16
|
-
)
|
17
|
-
# attempt save without required data; expect failure
|
18
|
-
expect { model.save! }.not_to raise_exception
|
19
|
-
end
|
20
|
-
|
21
|
-
it "saves when all fields completely set" do
|
22
|
-
model = described_class.create
|
23
|
-
model.fileset_id = 'someid123'
|
24
|
-
model.path = '/path/to/somefile'
|
25
|
-
model.destination_name = 'txt'
|
26
|
-
expect { model.save! }.not_to raise_exception
|
27
|
-
end
|
28
|
-
|
29
|
-
it "saves when only path, destination_name set" do
|
30
|
-
model = described_class.create
|
31
|
-
model.fileset_id = nil
|
32
|
-
model.path = '/path/to/somefile'
|
33
|
-
model.destination_name = 'txt'
|
34
|
-
expect { model.save! }.not_to raise_exception
|
35
|
-
end
|
36
|
-
end
|
37
|
-
end
|
@@ -1,27 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
RSpec.describe IiifPrint::IiifSearchDecorator do
|
4
|
-
let(:iiif_config) { { object_relation_field: 'is_page_of_ssim' } }
|
5
|
-
let(:parent_document) { double(SolrDocument, id: 'abc123') }
|
6
|
-
let(:iiif_search) { BlacklightIiifSearch::IiifSearch.new(params, iiif_config, parent_document) }
|
7
|
-
|
8
|
-
describe '#solr_params' do
|
9
|
-
subject { iiif_search.solr_params }
|
10
|
-
|
11
|
-
context 'when q is nil' do
|
12
|
-
let(:params) { { q: nil } }
|
13
|
-
|
14
|
-
it 'returns nil:nil' do
|
15
|
-
expect(subject).to eq({ q: 'nil:nil' })
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
context 'when q is not nil' do
|
20
|
-
let(:params) { { q: 'catscan' } }
|
21
|
-
|
22
|
-
it 'returns a query with the search term and filters for child or parent id' do
|
23
|
-
expect(subject).to eq({ q: "catscan AND (is_page_of_ssim:\"abc123\" OR id:\"abc123\")", rows: 50, page: nil })
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
@@ -1,56 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
module IiifPrint
|
4
|
-
RSpec.describe IngestFileRelation, type: :model do
|
5
|
-
def make_test_records
|
6
|
-
# two unique values
|
7
|
-
described_class.create(
|
8
|
-
file_path: '/some/path/to/this',
|
9
|
-
derivative_path: '/some/path/to/that'
|
10
|
-
)
|
11
|
-
described_class.create(
|
12
|
-
file_path: '/some/path/to/this',
|
13
|
-
derivative_path: '/some/path/to/other_thing'
|
14
|
-
)
|
15
|
-
# a duplicate will save, presumption is that dupes are filtered on query:
|
16
|
-
described_class.create(
|
17
|
-
file_path: '/some/path/to/this',
|
18
|
-
derivative_path: '/some/path/to/other_thing'
|
19
|
-
)
|
20
|
-
end
|
21
|
-
|
22
|
-
it "will not save unless record is complete" do
|
23
|
-
model = described_class.create
|
24
|
-
# attempt save without required data; expect failure
|
25
|
-
expect { model.save! }.to raise_exception(ActiveRecord::RecordInvalid)
|
26
|
-
model2 = described_class.create
|
27
|
-
model2.file_path = '/path/to/sourcefile.tiff'
|
28
|
-
expect { model2.save! }.to raise_exception(ActiveRecord::RecordInvalid)
|
29
|
-
model3 = described_class.create
|
30
|
-
model3.derivative_path = '/path/to/sourcefile.tiff'
|
31
|
-
expect { model3.save! }.to raise_exception(ActiveRecord::RecordInvalid)
|
32
|
-
end
|
33
|
-
|
34
|
-
it "will save sufficiently constructed record" do
|
35
|
-
model = described_class.create(
|
36
|
-
file_path: '/path/to/this',
|
37
|
-
derivative_path: '/path/to/that'
|
38
|
-
)
|
39
|
-
expect { model.save! }.not_to raise_exception
|
40
|
-
end
|
41
|
-
|
42
|
-
it "will save when all fields completely set" do
|
43
|
-
model = described_class.create
|
44
|
-
model.file_path = '/path/to/sourcefile.tiff'
|
45
|
-
model.derivative_path = '/path/to/derived.jp2'
|
46
|
-
expect { model.save! }.not_to raise_exception
|
47
|
-
end
|
48
|
-
|
49
|
-
it "can query derivative paths for primary file" do
|
50
|
-
make_test_records
|
51
|
-
result = described_class.derivatives_for_file('/some/path/to/this')
|
52
|
-
expect(result).to be_an Array
|
53
|
-
expect(result.size).to eq 2
|
54
|
-
end
|
55
|
-
end
|
56
|
-
end
|
@@ -1,14 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
RSpec.describe SolrDocument do
|
3
|
-
let(:solr_doc) { described_class.new(id: 'foo', file_set_ids_ssim: ['bar']) }
|
4
|
-
|
5
|
-
describe 'file_set_ids' do
|
6
|
-
it 'responds to #file_set_ids' do
|
7
|
-
expect(solr_doc).to respond_to(:file_set_ids)
|
8
|
-
end
|
9
|
-
|
10
|
-
it 'returns the correct value' do
|
11
|
-
expect(solr_doc.file_set_ids).to eq(['bar'])
|
12
|
-
end
|
13
|
-
end
|
14
|
-
end
|
@@ -1,70 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
RSpec.describe IiifPrint::IiifManifestPresenterBehavior do
|
4
|
-
let(:attributes) do
|
5
|
-
{ "id" => "abc123",
|
6
|
-
"title_tesim" => ['Page the first'],
|
7
|
-
"description_tesim" => ['A book or something'],
|
8
|
-
"creator_tesim" => ['Arthur McAuthor'] }
|
9
|
-
end
|
10
|
-
let(:solr_document) { SolrDocument.new(attributes) }
|
11
|
-
let(:presenter) { Hyrax::IiifManifestPresenter.new(solr_document) }
|
12
|
-
let(:test_request) { ActionDispatch::TestRequest.new({}) }
|
13
|
-
|
14
|
-
describe '#search_service' do
|
15
|
-
it 'returns the correct URL for the IIIF Search service' do
|
16
|
-
expect(presenter.search_service).to include("#{solr_document.id}/iiif_search")
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
context 'with IIIF external support' do
|
21
|
-
let(:presenter) { Hyrax::IiifManifestPresenter::DisplayImagePresenter.new(solr_document) }
|
22
|
-
let(:id) { 'abc123' }
|
23
|
-
let(:url) { 'external_iiif_url' }
|
24
|
-
let(:iiif_info_url_builder) { ->(file_id, base_url) { "#{base_url}/#{file_id}" } }
|
25
|
-
|
26
|
-
before { allow(solr_document).to receive(:image?).and_return(true) }
|
27
|
-
|
28
|
-
context 'when external iiif is enabled' do
|
29
|
-
before do
|
30
|
-
allow(ENV).to receive(:[])
|
31
|
-
allow(ENV).to receive(:[]).with('EXTERNAL_IIIF_URL').and_return(url)
|
32
|
-
allow(presenter).to receive(:latest_file_id).and_return(id)
|
33
|
-
end
|
34
|
-
|
35
|
-
describe '#display_image' do
|
36
|
-
it 'renders a external url' do
|
37
|
-
expect(presenter.display_image.iiif_endpoint.url).to eq "#{url}/#{id}"
|
38
|
-
expect(presenter.display_image.iiif_endpoint.profile).to eq "http://iiif.io/api/image/2/level2.json"
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
describe '#display_content' do
|
43
|
-
it 'renders a external url' do
|
44
|
-
expect(presenter.display_content.iiif_endpoint.url).to eq "#{url}/#{id}"
|
45
|
-
expect(presenter.display_content.iiif_endpoint.profile).to eq "http://iiif.io/api/image/2/level2.json"
|
46
|
-
end
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
context 'when external iiif is not enabled' do
|
51
|
-
before do
|
52
|
-
allow(presenter).to receive(:latest_file_id).and_return(id)
|
53
|
-
allow(Hyrax.config).to receive(:iiif_image_server?).and_return(true)
|
54
|
-
allow(Hyrax.config).to receive(:iiif_info_url_builder).and_return(iiif_info_url_builder)
|
55
|
-
end
|
56
|
-
|
57
|
-
describe '#display_image' do
|
58
|
-
it 'does not render a external url' do
|
59
|
-
expect(presenter.display_image.iiif_endpoint.url).to eq "localhost/#{id}"
|
60
|
-
end
|
61
|
-
end
|
62
|
-
|
63
|
-
describe '#display_content' do
|
64
|
-
it 'does not render a external url' do
|
65
|
-
expect(presenter.display_content.iiif_endpoint.url).to eq "localhost/#{id}"
|
66
|
-
end
|
67
|
-
end
|
68
|
-
end
|
69
|
-
end
|
70
|
-
end
|