diff --git a/app/models/attachment.rb b/app/models/attachment.rb index 08a9c58b63d..d75648ca2f0 100644 --- a/app/models/attachment.rb +++ b/app/models/attachment.rb @@ -198,21 +198,21 @@ class Attachment < ActiveRecord::Base end def extract_fulltext - return unless OpenProject::Database.allows_tsv? + return unless OpenProject::Database.allows_tsv? && (!container || container.class.attachment_tsv_extracted?) ExtractFulltextJob.perform_later(id) end # Extract the fulltext of any attachments where fulltext is still nil. - # This runs inline and not in a asynchronous worker. + # This runs inline and not in an asynchronous worker. def self.extract_fulltext_where_missing(run_now: true) return unless OpenProject::Database.allows_tsv? Attachment .where(fulltext: nil) + .where(container_type: tsv_extracted_containers) .pluck(:id) .each do |id| - if run_now ExtractFulltextJob.perform_now(id) else @@ -229,6 +229,17 @@ class Attachment < ActiveRecord::Base end end + def tsv_extracted_containers + Attachment + .select(:container_type) + .distinct + .pluck(:container_type) + .compact + .select do |container_class| + container_class.constantize.attachment_tsv_extracted? + end + end + private def schedule_cleanup_uncontainered_job diff --git a/app/models/work_package.rb b/app/models/work_package.rb index 535031997d0..530157b7957 100644 --- a/app/models/work_package.rb +++ b/app/models/work_package.rb @@ -158,7 +158,8 @@ class WorkPackage < ActiveRecord::Base order: "#{Attachment.table_name}.file", add_on_new_permission: :add_work_packages, add_on_persisted_permission: :edit_work_packages, - modification_blocked: ->(*) { readonly_status? } + modification_blocked: ->(*) { readonly_status? }, + extract_tsv: true after_validation :set_attachments_error_details, if: lambda { |work_package| work_package.errors.messages.has_key? :attachments } diff --git a/lib/plugins/acts_as_attachable/lib/acts_as_attachable.rb b/lib/plugins/acts_as_attachable/lib/acts_as_attachable.rb index 1fa728c5692..f26d088f6b8 100644 --- a/lib/plugins/acts_as_attachable/lib/acts_as_attachable.rb +++ b/lib/plugins/acts_as_attachable/lib/acts_as_attachable.rb @@ -62,7 +62,8 @@ module Redmine add_on_new_permission: add_on_new_permission(options), add_on_persisted_permission: add_on_persisted_permission(options), only_user_allowed: only_user_allowed(options), - modification_blocked: options[:modification_blocked] + modification_blocked: options[:modification_blocked], + extract_tsv: attachable_extract_tsv_option(options) } options.except!(:view_permission, @@ -71,7 +72,8 @@ module Redmine :add_on_persisted_permission, :add_permission, :only_user_allowed, - :modification_blocked) + :modification_blocked, + :extract_tsv) end def view_permission(options) @@ -101,6 +103,10 @@ module Redmine def edit_permission_default "edit_#{name.pluralize.underscore}".to_sym end + + def attachable_extract_tsv_option(options) + options.fetch(:extract_tsv, false) + end end module InstanceMethods @@ -119,6 +125,10 @@ module Redmine user.allowed_to_globally?(attachable_options[:add_on_new_permission]) || user.allowed_to_globally?(attachable_options[:add_on_persisted_permission]) end + + def attachment_tsv_extracted? + attachable_options[:extract_tsv] + end end module InstanceMethods diff --git a/spec/models/attachment_spec.rb b/spec/models/attachment_spec.rb index 126e875094e..8c3c039ec00 100644 --- a/spec/models/attachment_spec.rb +++ b/spec/models/attachment_spec.rb @@ -310,4 +310,76 @@ describe Attachment, type: :model do end end end + + describe 'full text extraction job on commit' do + let(:created_attachment) do + FactoryBot.create(:attachment, + author: author, + container: container) + end + + shared_examples_for 'runs extraction' do + it 'runs extraction' do + extraction_with_id = nil + + allow(ExtractFulltextJob) + .to receive(:perform_later) do |id| + extraction_with_id = id + end + + attachment.save + + expect(extraction_with_id).to eql attachment.id + end + end + + shared_examples_for 'does not run extraction' do + it 'does not run extraction' do + created_attachment + + expect(ExtractFulltextJob) + .not_to receive(:perform_later) + + created_attachment.save + end + end + + context 'for a work package' do + let(:work_package) { FactoryBot.create(:work_package) } + let(:container) { work_package } + + context 'on create' do + it_behaves_like 'runs extraction' + end + + context 'on update' do + it_behaves_like 'does not run extraction' + end + end + + context 'for a wiki page' do + let(:wiki_page) { FactoryBot.create(:wiki_page) } + let(:container) { wiki_page } + + context 'on create' do + it_behaves_like 'does not run extraction' + end + + context 'on update' do + it_behaves_like 'does not run extraction' + end + end + + context 'without a container' do + let(:container) { nil } + + context 'on create' do + it_behaves_like 'runs extraction' + end + + context 'on update' do + it_behaves_like 'does not run extraction' + end + end + end end