From 51251aefb0c9256a4b394801ea7c68e5190e1a51 Mon Sep 17 00:00:00 2001 From: Jamie Little Date: Fri, 8 Nov 2019 14:43:17 -0600 Subject: [PATCH] Basic file status This adds a PreIngestWork controller that allows you to get the thumbnail URLs for a work based on the deduplication_key. This is used by some JS that checks the thumbnail URLs by only requesting headers from the URL. If the work's files have been characterized the requests will return 200. That's used to change change the icon from a question mark to a green check in the 'Works and Files' page. This kind of status checking can't be used for individual files right now because there isn't any unique information being saved on the `FileSet` that would be present when the `PreIngestFile` is created. Connected to https://github.com/curationexperts/in-house/issues/423 --- .rubocop.yml | 1 + app/assets/javascripts/zizia/zizia.js | 44 ++++++++++++++- .../zizia/pre_ingest_works_controller.rb | 32 +++++++++++ app/models/zizia/ability.rb | 15 +++++ app/models/zizia/pre_ingest_file.rb | 3 + app/models/zizia/pre_ingest_work.rb | 15 +++++ .../zizia/csv_import_details/show.html.erb | 9 +++ config/routes.rb | 1 + .../pre_ingest_works_controller_spec.rb | 56 +++++++++++++++++++ .../system/csv_import_details_page_spec.rb | 21 +++++++ spec/factories/file_sets.rb | 36 ++++++++++++ spec/factories/pre_ingest_file.rb | 2 +- spec/models/zizia/pre_ingest_file_spec.rb | 10 +++- spec/rails_helper.rb | 3 + 14 files changed, 244 insertions(+), 4 deletions(-) create mode 100644 app/controllers/zizia/pre_ingest_works_controller.rb create mode 100644 app/models/zizia/ability.rb create mode 100644 spec/controllers/pre_ingest_works_controller_spec.rb create mode 100644 spec/factories/file_sets.rb diff --git a/.rubocop.yml b/.rubocop.yml index e2e8472..c60b001 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -62,6 +62,7 @@ RSpec/DescribeClass: RSpec/ExampleLength: Exclude: + - 'spec/controllers/pre_ingest_works_controller_spec.rb' - 'spec/zizia/hyrax/hyrax_basic_metadata_mapper_spec.rb' - 'spec/integration/import_hyrax_csv.rb' - 'spec/integration/csv_import_detail_spec.rb' diff --git a/app/assets/javascripts/zizia/zizia.js b/app/assets/javascripts/zizia/zizia.js index 465937d..69a094f 100644 --- a/app/assets/javascripts/zizia/zizia.js +++ b/app/assets/javascripts/zizia/zizia.js @@ -1,6 +1,48 @@ var Zizia = { - displayUploadedFile: function() { + displayUploadedFile: function () { var DisplayUploadedFile = require('zizia/DisplayUploadedFile') new DisplayUploadedFile().display() + }, + checkStatuses: function (options) { + var results = [] + // Go through the list of thumbnails for the work based + // on the deduplicationKey + options.thumbnails.forEach(function (thumbnail) { + $.ajax({ + type: 'HEAD', + url: thumbnail, + complete: function (xhr) { + // Request only the headers from the thumbnail url + // push the statuses into an array + results.push(xhr.getResponseHeader('status')) + // See how many urls are not returning 200 + var missingThumbnailCount = results.filter( + function (status) { + if (status !== '200 OK') { return true } + }).length + // If there are any not returning 200, the work is still being processed + if (missingThumbnailCount > 0) { + + } else { + Zizia.addSuccessClasses(options) + } + } + }) + }) + }, + displayWorkStatus: function () { + $('[id^=work-status]').each(function () { + var deduplicationKey = $(this)[0].id.split('work-status-')[1] + $.get('/pre_ingest_works/thumbnails/' + deduplicationKey, function (data) { + data.deduplicationKey = deduplicationKey + Zizia.checkStatuses(data) + }) + }) + }, + addSuccessClasses: function (options) { + $('#work-status-' + options.deduplicationKey + ' > span').removeClass('status-unknown') + $('#work-status-' + options.deduplicationKey + ' > span').removeClass('glyphicon-question-sign') + $('#work-status-' + options.deduplicationKey + ' > span').addClass('text-success') + $('#work-status-' + options.deduplicationKey + ' > span').addClass('glyphicon-ok-sign') } } diff --git a/app/controllers/zizia/pre_ingest_works_controller.rb b/app/controllers/zizia/pre_ingest_works_controller.rb new file mode 100644 index 0000000..3e6f323 --- /dev/null +++ b/app/controllers/zizia/pre_ingest_works_controller.rb @@ -0,0 +1,32 @@ +# frozen_string_literal: true + +module Zizia + class PreIngestWorksController < ::ApplicationController + before_action :merge_abilities + load_and_authorize_resource + + def thumbnails + pre_ingest_work = Zizia::PreIngestWork.where(deduplication_key: pre_ingest_works_params[:deduplication_key]).first + + @thumbnails = if pre_ingest_work + pre_ingest_work.thumbnails + else + [] + end + + respond_to do |format| + format.json { render json: { thumbnails: @thumbnails } } + end + end + + private + + def pre_ingest_works_params + params.permit(:deduplication_key, :format) + end + + def merge_abilities + current_ability.merge(Zizia::Ability.new(current_user)) + end + end +end diff --git a/app/models/zizia/ability.rb b/app/models/zizia/ability.rb new file mode 100644 index 0000000..8fdb2ea --- /dev/null +++ b/app/models/zizia/ability.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true +module Zizia + class Ability + include Hydra::Ability + include Hyrax::Ability + self.ability_logic += [:everyone_can_create_curation_concerns] + + # Define any customized permissions here. + def custom_permissions + can :manage, Zizia::CsvImport if current_user.admin? + can :manage, Zizia::CsvImportDetail if current_user.admin? + can :manage, Zizia::PreIngestWork if current_user.admin? + end + end +end diff --git a/app/models/zizia/pre_ingest_file.rb b/app/models/zizia/pre_ingest_file.rb index c23f79f..11e0509 100644 --- a/app/models/zizia/pre_ingest_file.rb +++ b/app/models/zizia/pre_ingest_file.rb @@ -1,8 +1,11 @@ # frozen_string_literal: true + module Zizia class PreIngestFile < ::ApplicationRecord belongs_to :pre_ingest_work + attr_reader :checksum, :ingest_status + def basename File.basename(filename) end diff --git a/app/models/zizia/pre_ingest_work.rb b/app/models/zizia/pre_ingest_work.rb index f417dc1..8fcc599 100644 --- a/app/models/zizia/pre_ingest_work.rb +++ b/app/models/zizia/pre_ingest_work.rb @@ -12,5 +12,20 @@ def title return solr_title unless solr_title.nil? 'This work\'s metadata has not been indexed yet.' end + + # Returns thumbnail urls based on the work's deduplication_key + # @return [Array] the work's thumbnail urls + def thumbnails + thumbnail_urls = [] + return thumbnail_urls if deduplication_key.nil? + file_sets = ActiveFedora::SolrService.get("deduplication_key_tesim:#{deduplication_key}") + .dig('response', 'docs', 0, 'file_set_ids_ssim') + return thumbnail_urls unless file_sets + file_sets.each do |file_set_id| + thumbnail_urls.push(ActiveFedora::SolrService.get("id:#{file_set_id}") + .dig('response', 'docs', 0, 'thumbnail_path_ss')) + end + thumbnail_urls + end end end diff --git a/app/views/zizia/csv_import_details/show.html.erb b/app/views/zizia/csv_import_details/show.html.erb index 002c128..b0f1ecd 100644 --- a/app/views/zizia/csv_import_details/show.html.erb +++ b/app/views/zizia/csv_import_details/show.html.erb @@ -15,6 +15,7 @@ Title Files Date + Status <% @pre_ingest_works.each do |pre_ingest_work| %> @@ -30,8 +31,16 @@ <%= pre_ingest_work.created_at.strftime("%B %-d, %Y %H:%M") %> + "> + + <% end %> <%= paginate @pre_ingest_works %> + diff --git a/config/routes.rb b/config/routes.rb index 831d927..7b70c96 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -10,4 +10,5 @@ get 'csv_import_details/index' get 'csv_import_details/show/:id', to: 'csv_import_details#show', as: 'csv_import_detail' + get 'pre_ingest_works/thumbnails/:deduplication_key', to: 'pre_ingest_works#thumbnails' end diff --git a/spec/controllers/pre_ingest_works_controller_spec.rb b/spec/controllers/pre_ingest_works_controller_spec.rb new file mode 100644 index 0000000..caa3ad8 --- /dev/null +++ b/spec/controllers/pre_ingest_works_controller_spec.rb @@ -0,0 +1,56 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe Zizia::PreIngestWorksController, :clean, type: :controller do + routes { Zizia::Engine.routes } + let(:admin_user) { FactoryBot.create(:admin) } + let(:pre_ingest_work) { FactoryBot.create(:pre_ingest_work) } + let(:pre_ingest_file) { FactoryBot.create(:pre_ingest_file, pre_ingest_work_id: pre_ingest_work.id) } + let(:pre_ingest_file_without_file) { FactoryBot.create(:pre_ingest_file, pre_ingest_work_id: pre_ingest_work.id, filename: File.open([Zizia::Engine.root, '/', 'spec/fixtures/dog.jpg'].join)) } + let(:work) { Work.new(title: ['a title'], deduplication_key: pre_ingest_work.deduplication_key) } + let(:file_set) do + FactoryBot.create(:file_set, + title: ['zizia.png'], + content: File.open([Zizia::Engine.root, '/', 'spec/fixtures/zizia.png'].join)) + end + let(:basename) { 'zizia.png' } + before do + work.ordered_members << file_set + work.save + end + + describe 'GET thumbnails' do + context 'as a logged in user' do + it 'returns 200' do + allow(controller).to receive(:current_user).and_return(admin_user) + get :thumbnails, params: { deduplication_key: pre_ingest_work.deduplication_key, format: :json } + expect(response.status).to eq(200) + end + + it 'returns an array of thumbail paths' do + file_set.save + allow(controller).to receive(:current_user).and_return(admin_user) + get :thumbnails, params: { deduplication_key: pre_ingest_work.deduplication_key, format: :json } + parsed_json = JSON.parse(response.body) + expect(parsed_json['thumbnails']).to be_an(Array) + expect(parsed_json['thumbnails'].empty?).to eq(false) + end + + it 'returns an empty array if there aren\'t any thumbnails' do + allow(controller).to receive(:current_user).and_return(admin_user) + get :thumbnails, params: { deduplication_key: 'abc/1234', format: :json } + parsed_json = JSON.parse(response.body) + expect(parsed_json['thumbnails']).to be_an(Array) + expect(parsed_json['thumbnails'].empty?).to eq(true) + end + end + + context 'as someone not logged in' do + it 'returns 401' do + get :thumbnails, params: { deduplication_key: pre_ingest_work.deduplication_key, format: :json } + expect(response.status).to eq(401) + end + end + end +end diff --git a/spec/dummy/spec/system/csv_import_details_page_spec.rb b/spec/dummy/spec/system/csv_import_details_page_spec.rb index 0e0d525..991b78b 100644 --- a/spec/dummy/spec/system/csv_import_details_page_spec.rb +++ b/spec/dummy/spec/system/csv_import_details_page_spec.rb @@ -11,6 +11,14 @@ let(:csv_import_detail_third) { FactoryBot.create(:csv_import_detail, created_at: Time.parse('Wed, 30 Oct 2019 14:20:02 UTC +00:00').utc, depositor_id: second_user.id, csv_import_id: 2) } let(:csv_pre_ingest_works) { FactoryBot.create_list(:pre_ingest_work, 12, csv_import_detail_id: 4) } let(:csv_pre_ingest_work_second) { FactoryBot.create(:pre_ingest_work, csv_import_detail_id: 5, created_at: Time.parse('Thur, 31 Oct 2019 14:20:02 UTC +00:00').utc) } + let(:pre_ingest_file) { FactoryBot.create(:pre_ingest_file, pre_ingest_work_id: csv_pre_ingest_work_second.id) } + let(:pre_ingest_file_without_file) { FactoryBot.create(:pre_ingest_file, pre_ingest_work_id: csv_pre_ingest_work_second.id, filename: File.open([Zizia::Engine.root, '/', 'spec/fixtures/dog.jpg'].join)) } + let(:file_set) do + FactoryBot.create(:file_set, + title: ['zizia.png'], + content: File.open([Zizia::Engine.root, '/', 'spec/fixtures/zizia.png'].join)) + end + before do user.save @@ -27,6 +35,8 @@ csv_import_detail_third.save csv_pre_ingest_works.each(&:save) csv_pre_ingest_work_second.save + pre_ingest_file.save + pre_ingest_file_without_file.save login_as user end @@ -134,4 +144,15 @@ click_on 'View Files' expect(page).to have_content 'Row Number' end + + it 'can show a status for a file' do + file_set + visit('/csv_import_details/index') + click_on '5' + expect(page).to have_content 'View Files' + expect(page).to have_content 'Status' + click_on 'View Files' + #expect(page.html).to match(/glyphicon-ok-sign status-success/) + expect(page.html).to match(/glyphicon-question-sign/) + end end diff --git a/spec/factories/file_sets.rb b/spec/factories/file_sets.rb new file mode 100644 index 0000000..5517b10 --- /dev/null +++ b/spec/factories/file_sets.rb @@ -0,0 +1,36 @@ +# frozen_string_literal: true +FactoryBot.define do + factory :file_set do + transient do + user { build(:user) } + title { nil } + content { nil } + end + after(:build) do |fs, evaluator| + fs.apply_depositor_metadata evaluator.user.user_key + fs.title = evaluator.title + end + + after(:create) do |file, evaluator| + Hydra::Works::UploadFileToFileSet.call(file, evaluator.content) if evaluator.content + end + + trait :public do + read_groups { ["public"] } + end + + trait :registered do + read_groups { ["registered"] } + end + + factory :file_with_work do + after(:build) do |file, _evaluator| + file.title = ['testfile'] + end + after(:create) do |file, evaluator| + Hydra::Works::UploadFileToFileSet.call(file, evaluator.content) if evaluator.content + create(:work, user: evaluator.user).members << file + end + end + end +end diff --git a/spec/factories/pre_ingest_file.rb b/spec/factories/pre_ingest_file.rb index bc29afa..24cb715 100644 --- a/spec/factories/pre_ingest_file.rb +++ b/spec/factories/pre_ingest_file.rb @@ -7,7 +7,7 @@ updated_at { Time.current } row_number { 1 } row { 'sample,row' } - filename { '/a/path/to/my.csv' } + filename { [Zizia::Engine.root, '/', 'spec/fixtures/zizia.png'].join } size { 100_203_424 } end end diff --git a/spec/models/zizia/pre_ingest_file_spec.rb b/spec/models/zizia/pre_ingest_file_spec.rb index c5e9840..b6469fb 100644 --- a/spec/models/zizia/pre_ingest_file_spec.rb +++ b/spec/models/zizia/pre_ingest_file_spec.rb @@ -4,9 +4,15 @@ RSpec.describe Zizia::PreIngestFile do let(:pre_ingest_work) { FactoryBot.create(:pre_ingest_work) } let(:pre_ingest_file) { FactoryBot.create(:pre_ingest_file, pre_ingest_work_id: pre_ingest_work.id) } - let(:basename) { 'my.csv' } + let(:pre_ingest_file_without_file) { FactoryBot.create(:pre_ingest_file, pre_ingest_work_id: pre_ingest_work.id, filename: File.open([Zizia::Engine.root, '/', 'spec/fixtures/dog.jpg'].join)) } + let(:file_set) do + FactoryBot.create(:file_set, + title: ['zizia.png'], + content: File.open([Zizia::Engine.root, '/', 'spec/fixtures/zizia.png'].join)) + end + let(:basename) { 'zizia.png' } it 'can get the basename for the file' do - expect(pre_ingest_file.basename).to eq(basename) + expect(pre_ingest_file.basename).to eq basename end end diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb index cfb10e5..457a0e9 100644 --- a/spec/rails_helper.rb +++ b/spec/rails_helper.rb @@ -12,6 +12,7 @@ require 'byebug' require 'rails-controller-testing' require 'selenium-webdriver' +require 'devise' # Add additional requires below this line. Rails is not loaded until this point! # Requires supporting ruby files with custom matchers and macros, etc, in @@ -38,6 +39,8 @@ exit 1 end RSpec.configure do |config| + config.include Devise::Test::ControllerHelpers, type: :controller + # Remove this line if you're not using ActiveRecord or ActiveRecord fixtures config.fixture_path = "#{::Rails.root}/spec/fixtures"