mirror of
https://github.com/opf/openproject.git
synced 2026-06-14 03:30:14 +00:00
Remove more "titles only" logic and adopts specs
This commit is contained in:
@@ -86,25 +86,22 @@ module Redmine
|
||||
find_order = "#{searchable_options[:order_column]} " + (options[:before] ? 'DESC' : 'ASC')
|
||||
|
||||
columns = searchable_options[:columns]
|
||||
columns = columns[0..0] if options[:titles_only]
|
||||
|
||||
tsv_columns = searchable_options[:tsv_columns]
|
||||
|
||||
token_clauses = columns.map { |column| "(LOWER(#{column}) LIKE ?)" }
|
||||
|
||||
unless options[:titles_only]
|
||||
if EnterpriseToken.allows_to?(:attachment_filters) && OpenProject::Database.allows_tsv?
|
||||
tsv_clauses = tsv_columns.map do |tsv_column|
|
||||
OpenProject::FullTextSearch.tsv_where(tsv_column[:table_name],
|
||||
tsv_column[:column_name],
|
||||
tokens.join(' '),
|
||||
concatenation: :and,
|
||||
normalization: tsv_column[:normalization_type])
|
||||
end
|
||||
if EnterpriseToken.allows_to?(:attachment_filters) && OpenProject::Database.allows_tsv?
|
||||
tsv_clauses = tsv_columns.map do |tsv_column|
|
||||
OpenProject::FullTextSearch.tsv_where(tsv_column[:table_name],
|
||||
tsv_column[:column_name],
|
||||
tokens.join(' '),
|
||||
concatenation: :and,
|
||||
normalization: tsv_column[:normalization_type])
|
||||
end
|
||||
end
|
||||
|
||||
if !options[:titles_only] && searchable_options[:search_custom_fields]
|
||||
if searchable_options[:search_custom_fields]
|
||||
searchable_custom_field_ids = CustomField.where(type: "#{name}CustomField",
|
||||
searchable: true).pluck(:id)
|
||||
if searchable_custom_field_ids.any?
|
||||
|
||||
@@ -29,25 +29,73 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe SearchController, type: :controller do
|
||||
let!(:project) {
|
||||
let!(:project) do
|
||||
FactoryBot.create(:project,
|
||||
name: 'eCookbook')
|
||||
}
|
||||
let(:user) {
|
||||
name: 'eCookbook')
|
||||
end
|
||||
|
||||
let!(:other_project) do
|
||||
FactoryBot.create(:project,
|
||||
name: 'Other project')
|
||||
end
|
||||
|
||||
let!(:subproject) do
|
||||
FactoryBot.create(:project,
|
||||
name: 'Child project',
|
||||
parent: project)
|
||||
end
|
||||
|
||||
let(:role) do
|
||||
FactoryBot.create(:role, permissions: %i[view_wiki_pages view_work_packages])
|
||||
end
|
||||
|
||||
let(:user) do
|
||||
FactoryBot.create(:user,
|
||||
member_in_project: project)
|
||||
}
|
||||
member_in_projects: [project, subproject],
|
||||
member_through_role: role)
|
||||
end
|
||||
|
||||
let!(:wiki_page) do
|
||||
FactoryBot.create(:wiki_page,
|
||||
title: "How to solve an issue",
|
||||
wiki: project.wiki)
|
||||
end
|
||||
|
||||
let!(:work_package_1) do
|
||||
FactoryBot.create(:work_package,
|
||||
subject: 'This is a test issue',
|
||||
project: project)
|
||||
end
|
||||
|
||||
let!(:work_package_2) do
|
||||
FactoryBot.create(:work_package,
|
||||
subject: 'Issue test 2',
|
||||
project: project,
|
||||
status: FactoryBot.create(:closed_status))
|
||||
end
|
||||
|
||||
let!(:work_package_3) do
|
||||
FactoryBot.create(:work_package,
|
||||
subject: 'Issue test 3',
|
||||
project: subproject)
|
||||
end
|
||||
|
||||
let!(:work_package_4) do
|
||||
FactoryBot.create(:work_package,
|
||||
subject: 'Issue test 4',
|
||||
project: other_project)
|
||||
end
|
||||
|
||||
shared_examples_for 'successful search' do
|
||||
it { expect(response).to be_successful }
|
||||
it { expect(response).to render_template('index') }
|
||||
end
|
||||
|
||||
before do allow(User).to receive(:current).and_return user end
|
||||
before { allow(User).to receive(:current).and_return user }
|
||||
|
||||
describe 'project search' do
|
||||
context 'without a search parameter' do
|
||||
before do get :index end
|
||||
before { get :index }
|
||||
|
||||
it_behaves_like 'successful search'
|
||||
end
|
||||
@@ -72,66 +120,90 @@ describe SearchController, type: :controller do
|
||||
end
|
||||
|
||||
describe 'scoped project search' do
|
||||
before do get :index, params: { project_id: project.id } end
|
||||
before { get :index, params: { project_id: project.id } }
|
||||
|
||||
it_behaves_like 'successful search'
|
||||
|
||||
it { expect(assigns(:project).id).to be(project.id) }
|
||||
end
|
||||
|
||||
describe 'work package search' do
|
||||
let!(:work_package_1) {
|
||||
FactoryBot.create(:work_package,
|
||||
subject: 'This is a test issue',
|
||||
project: project)
|
||||
}
|
||||
let!(:work_package_2) {
|
||||
FactoryBot.create(:work_package,
|
||||
subject: 'Issue test 2',
|
||||
project: project,
|
||||
status: FactoryBot.create(:closed_status))
|
||||
}
|
||||
|
||||
context 'when not searching for a note' do
|
||||
before do get :index, params: { q: 'issue', work_packages: 1 } end
|
||||
describe 'searching in all modules' do
|
||||
context 'when searching in all projects' do
|
||||
before { get :index, params: { q: 'issue', scope: 'all' } }
|
||||
|
||||
it_behaves_like 'successful search'
|
||||
|
||||
describe '#result' do
|
||||
it { expect(assigns(:results).count).to be(2) }
|
||||
|
||||
it { expect(assigns(:results).count).to be(4) }
|
||||
it { expect(assigns(:results)).to include(work_package_1) }
|
||||
|
||||
it { expect(assigns(:results)).to include(work_package_2) }
|
||||
it { expect(assigns(:results)).to include(work_package_3) }
|
||||
it { expect(assigns(:results)).to include(wiki_page) }
|
||||
it { expect(assigns(:results)).to_not include(work_package_4) }
|
||||
end
|
||||
|
||||
describe '#view' do
|
||||
render_views
|
||||
describe '#results_by_type' do
|
||||
it { expect(assigns(:results_by_type)).to be_a(Hash) }
|
||||
it { expect(assigns(:results_by_type)['work_packages']).to eql(3) }
|
||||
end
|
||||
|
||||
it 'marks closed work packages' do
|
||||
assert_select 'dt.work_package-closed' do
|
||||
assert_select 'a', text: Regexp.new(work_package_2.status.name)
|
||||
end
|
||||
describe '#view' do
|
||||
render_views
|
||||
|
||||
it 'marks closed work packages' do
|
||||
assert_select 'dt.work_package-closed' do
|
||||
assert_select 'a', text: Regexp.new(work_package_2.status.name)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when searching in project and its subprojects' do
|
||||
before { get :index, params: { q: 'issue', project_id: project.id, scope: 'subprojects' } }
|
||||
|
||||
it_behaves_like 'successful search'
|
||||
|
||||
describe '#result' do
|
||||
it { expect(assigns(:results).count).to be(4) }
|
||||
it { expect(assigns(:results)).to include(work_package_1) }
|
||||
it { expect(assigns(:results)).to include(work_package_2) }
|
||||
it { expect(assigns(:results)).to include(work_package_3) }
|
||||
it { expect(assigns(:results)).to include(wiki_page) }
|
||||
it { expect(assigns(:results)).to_not include(work_package_4) }
|
||||
end
|
||||
end
|
||||
|
||||
context 'when searching in project without its subprojects' do
|
||||
before { get :index, params: { q: 'issue', project_id: project.id, scope: 'current_project' } }
|
||||
|
||||
it_behaves_like 'successful search'
|
||||
|
||||
describe '#result' do
|
||||
it { expect(assigns(:results).count).to be(3) }
|
||||
it { expect(assigns(:results)).to include(work_package_1) }
|
||||
it { expect(assigns(:results)).to include(work_package_2) }
|
||||
it { expect(assigns(:results)).to include(wiki_page) }
|
||||
it { expect(assigns(:results)).to_not include(work_package_3) }
|
||||
it { expect(assigns(:results)).to_not include(work_package_4) }
|
||||
end
|
||||
end
|
||||
|
||||
context 'when searching for a note' do
|
||||
let!(:note_1) {
|
||||
let!(:note_1) do
|
||||
FactoryBot.create :work_package_journal,
|
||||
journable_id: work_package_1.id,
|
||||
notes: 'Test note 1',
|
||||
version: 2
|
||||
}
|
||||
journable_id: work_package_1.id,
|
||||
notes: 'Test note 1',
|
||||
version: 2
|
||||
end
|
||||
|
||||
before do allow_any_instance_of(Journal).to receive_messages(predecessor: note_1) end
|
||||
before { allow_any_instance_of(Journal).to receive_messages(predecessor: note_1) }
|
||||
|
||||
let!(:note_2) {
|
||||
let!(:note_2) do
|
||||
FactoryBot.create :work_package_journal,
|
||||
journable_id: work_package_1.id,
|
||||
notes: 'Special note 2',
|
||||
version: 3
|
||||
}
|
||||
journable_id: work_package_1.id,
|
||||
notes: 'Special note 2',
|
||||
version: 3
|
||||
end
|
||||
|
||||
describe 'second note predecessor' do
|
||||
subject { note_2.send :predecessor }
|
||||
@@ -142,7 +214,7 @@ describe SearchController, type: :controller do
|
||||
end
|
||||
|
||||
before do
|
||||
get :index, params: { q: 'note', work_packages: 1 }
|
||||
get :index, params: { q: 'note'}
|
||||
end
|
||||
|
||||
it_behaves_like 'successful search'
|
||||
|
||||
@@ -29,93 +29,93 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe Project::Activity, type: :model do
|
||||
let(:project) {
|
||||
let(:project) do
|
||||
FactoryBot.create(:project)
|
||||
}
|
||||
end
|
||||
|
||||
let(:initial_time) { Time.now }
|
||||
|
||||
let(:work_package) {
|
||||
let(:work_package) do
|
||||
FactoryBot.create(:work_package,
|
||||
project: project)
|
||||
}
|
||||
project: project)
|
||||
end
|
||||
|
||||
let(:work_package2) {
|
||||
let(:work_package2) do
|
||||
FactoryBot.create(:work_package,
|
||||
project: project)
|
||||
}
|
||||
project: project)
|
||||
end
|
||||
|
||||
let(:wiki_content) {
|
||||
let(:wiki_content) do
|
||||
project.reload
|
||||
|
||||
page = FactoryBot.create(:wiki_page,
|
||||
wiki: project.wiki)
|
||||
wiki: project.wiki)
|
||||
|
||||
FactoryBot.create(:wiki_content,
|
||||
page: page)
|
||||
}
|
||||
page: page)
|
||||
end
|
||||
|
||||
let(:wiki_content2) {
|
||||
let(:wiki_content2) do
|
||||
project.reload
|
||||
|
||||
page = FactoryBot.create(:wiki_page,
|
||||
wiki: project.wiki)
|
||||
wiki: project.wiki)
|
||||
|
||||
FactoryBot.create(:wiki_content,
|
||||
page: page)
|
||||
}
|
||||
page: page)
|
||||
end
|
||||
|
||||
let(:news) {
|
||||
let(:news) do
|
||||
FactoryBot.create(:news,
|
||||
project: project)
|
||||
}
|
||||
project: project)
|
||||
end
|
||||
|
||||
let(:news2) {
|
||||
let(:news2) do
|
||||
FactoryBot.create(:news,
|
||||
project: project)
|
||||
}
|
||||
project: project)
|
||||
end
|
||||
|
||||
let(:repository) {
|
||||
let(:repository) do
|
||||
FactoryBot.create(:repository_git,
|
||||
project: project)
|
||||
}
|
||||
project: project)
|
||||
end
|
||||
|
||||
let(:changeset) {
|
||||
let(:changeset) do
|
||||
FactoryBot.create(:changeset,
|
||||
repository: repository)
|
||||
}
|
||||
repository: repository)
|
||||
end
|
||||
|
||||
let(:changeset2) {
|
||||
let(:changeset2) do
|
||||
FactoryBot.create(:changeset,
|
||||
repository: repository)
|
||||
}
|
||||
repository: repository)
|
||||
end
|
||||
|
||||
let(:board) {
|
||||
let(:board) do
|
||||
FactoryBot.create(:board,
|
||||
project: project)
|
||||
}
|
||||
project: project)
|
||||
end
|
||||
|
||||
let(:message) {
|
||||
let(:message) do
|
||||
FactoryBot.create(:message,
|
||||
board: board)
|
||||
}
|
||||
board: board)
|
||||
end
|
||||
|
||||
let(:message2) {
|
||||
let(:message2) do
|
||||
FactoryBot.create(:message,
|
||||
board: board)
|
||||
}
|
||||
board: board)
|
||||
end
|
||||
|
||||
let(:time_entry) {
|
||||
let(:time_entry) do
|
||||
FactoryBot.create(:time_entry,
|
||||
work_package: work_package,
|
||||
project: project)
|
||||
}
|
||||
work_package: work_package,
|
||||
project: project)
|
||||
end
|
||||
|
||||
let(:time_entry2) {
|
||||
let(:time_entry2) do
|
||||
FactoryBot.create(:time_entry,
|
||||
work_package: work_package,
|
||||
project: project)
|
||||
}
|
||||
work_package: work_package,
|
||||
project: project)
|
||||
end
|
||||
|
||||
def latest_activity
|
||||
Project.with_latest_activity.find(project.id).latest_activity_at
|
||||
|
||||
@@ -40,28 +40,6 @@ describe SearchController, type: :controller do
|
||||
User.current = nil
|
||||
end
|
||||
|
||||
it 'should search all projects' do
|
||||
get :index, params: { q: 'recipe subproject commit', submit: 'Search' }
|
||||
assert_response :success
|
||||
assert_template 'index'
|
||||
|
||||
assert assigns(:results).include?(WorkPackage.find(2))
|
||||
assert assigns(:results).include?(WorkPackage.find(5))
|
||||
assert assigns(:results).include?(Changeset.find(101))
|
||||
|
||||
assert assigns(:results_by_type).is_a?(Hash)
|
||||
assert_equal 5, assigns(:results_by_type)['changesets']
|
||||
assert_select 'a', content: 'Changesets (5)'
|
||||
end
|
||||
|
||||
it 'should search project and subprojects' do
|
||||
get :index, params: { project_id: 1, q: 'recipe subproject', scope: 'subprojects', submit: 'Search' }
|
||||
assert_response :success
|
||||
assert_template 'index'
|
||||
assert assigns(:results).include?(WorkPackage.find(1))
|
||||
assert assigns(:results).include?(WorkPackage.find(5))
|
||||
end
|
||||
|
||||
it 'should search without searchable custom fields' do
|
||||
CustomField.update_all "searchable = #{ActiveRecord::Base.connection.quoted_false}"
|
||||
|
||||
@@ -84,63 +62,15 @@ describe SearchController, type: :controller do
|
||||
assert results.include?(WorkPackage.find(7))
|
||||
end
|
||||
|
||||
it 'should search all words' do
|
||||
# 'all words' is on by default
|
||||
get :index, params: { project_id: 1, q: 'recipe updating saving' }
|
||||
results = assigns(:results)
|
||||
refute_nil results
|
||||
assert_equal 1, results.size
|
||||
assert results.include?(WorkPackage.find(3))
|
||||
end
|
||||
|
||||
it 'should search one of the words' do
|
||||
get :index, params: { project_id: 1, q: 'recipe updating saving', submit: 'Search' }
|
||||
results = assigns(:results)
|
||||
refute_nil results
|
||||
assert_equal 4, results.size
|
||||
assert results.include?(WorkPackage.find(3))
|
||||
end
|
||||
|
||||
it 'should search titles only without result' do
|
||||
get :index, params: { project_id: 1, q: 'recipe updating saving', all_words: '1', titles_only: '1', submit: 'Search' }
|
||||
results = assigns(:results)
|
||||
refute_nil results
|
||||
assert_equal 0, results.size
|
||||
end
|
||||
|
||||
it 'should search titles only' do
|
||||
get :index, params: { project_id: 1, q: 'recipe', titles_only: '1', submit: 'Search' }
|
||||
results = assigns(:results)
|
||||
refute_nil results
|
||||
assert_equal 2, results.size
|
||||
end
|
||||
|
||||
it 'should search with invalid project id' do
|
||||
get :index, params: { project_id: 195, q: 'recipe' }
|
||||
assert_response 404
|
||||
assert_nil assigns(:results)
|
||||
end
|
||||
|
||||
it 'should quick jump to work packages' do
|
||||
# work_package of a public project
|
||||
get :index, params: { q: '3' }
|
||||
assert_redirected_to '/work_packages/3'
|
||||
end
|
||||
|
||||
it 'should not jump to an invisible WP' do
|
||||
get :index, params: { q: '4' }
|
||||
assert_response :success
|
||||
assert_template 'index'
|
||||
end
|
||||
|
||||
it 'should large integer' do
|
||||
get :index, params: { q: '4615713488' }
|
||||
assert_response :success
|
||||
assert_template 'index'
|
||||
end
|
||||
|
||||
it 'should tokens with quotes' do
|
||||
get :index, params: { project_id: 1, q: '"good bye" hello "bye bye"' }
|
||||
assert_equal ['good bye', 'hello', 'bye bye'], assigns(:tokens)
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user