mirror of
https://github.com/opf/openproject.git
synced 2026-06-13 19:20:00 +00:00
Merge pull request #23393 from opf/wiki-page-search
Search pages query (for internal wiki)
This commit is contained in:
@@ -0,0 +1,41 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
#-- copyright
|
||||
# OpenProject is an open source project management software.
|
||||
# Copyright (C) the OpenProject GmbH
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License version 3.
|
||||
#
|
||||
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
|
||||
# Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
# Copyright (C) 2010-2013 the ChiliProject Team
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#
|
||||
# See COPYRIGHT and LICENSE files for more details.
|
||||
#++
|
||||
|
||||
module Wikis
|
||||
module Adapters
|
||||
module Input
|
||||
class SearchPagesContract < DryApplicationContract
|
||||
params do
|
||||
required(:query).filled(:string)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,39 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
#-- copyright
|
||||
# OpenProject is an open source project management software.
|
||||
# Copyright (C) the OpenProject GmbH
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License version 3.
|
||||
#
|
||||
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
|
||||
# Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
# Copyright (C) 2010-2013 the ChiliProject Team
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#
|
||||
# See COPYRIGHT and LICENSE files for more details.
|
||||
#++
|
||||
|
||||
module Wikis::Adapters::Input
|
||||
SearchPages = Data.define(:query) do
|
||||
private_class_method :new
|
||||
|
||||
def self.build(query:, contract: SearchPagesContract.new)
|
||||
contract.call(query:).to_monad.fmap { new(**it.to_h) }
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -34,33 +34,37 @@ module Wikis
|
||||
module Internal
|
||||
module Queries
|
||||
class PageInfo < BaseQuery
|
||||
class << self
|
||||
def wiki_page_to_page_info(wiki_page, provider:)
|
||||
Results::PageInfo.new(
|
||||
identifier: wiki_page.id.to_s,
|
||||
title: wiki_page.title,
|
||||
provider:,
|
||||
href: url_for(only_path: true,
|
||||
controller: "/wiki",
|
||||
action: "show",
|
||||
project_id: wiki_page.project.identifier,
|
||||
id: wiki_page.slug)
|
||||
)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
delegate :url_for, to: :url_helpers
|
||||
|
||||
def url_helpers
|
||||
@url_helpers ||= OpenProject::StaticRouting::StaticRouter.new.url_helpers
|
||||
end
|
||||
end
|
||||
|
||||
def call(input_data:, auth_strategy:)
|
||||
Adapters::Authentication[auth_strategy].call do |user|
|
||||
wiki_page = WikiPage.visible(user).find_by(id: input_data.identifier)
|
||||
return failure(code: :not_found) if wiki_page.nil?
|
||||
|
||||
success(
|
||||
Results::PageInfo.new(
|
||||
identifier: input_data.identifier,
|
||||
title: wiki_page.title,
|
||||
provider:,
|
||||
href: url_for(only_path: true,
|
||||
controller: "/wiki",
|
||||
action: "show",
|
||||
project_id: wiki_page.project.identifier,
|
||||
id: wiki_page.slug)
|
||||
)
|
||||
)
|
||||
success(self.class.wiki_page_to_page_info(wiki_page, provider:))
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
delegate :url_for, to: :url_helpers
|
||||
|
||||
def url_helpers
|
||||
OpenProject::StaticRouting::StaticRouter.new.url_helpers
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
#-- copyright
|
||||
# OpenProject is an open source project management software.
|
||||
# Copyright (C) the OpenProject GmbH
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License version 3.
|
||||
#
|
||||
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
|
||||
# Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
# Copyright (C) 2010-2013 the ChiliProject Team
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#
|
||||
# See COPYRIGHT and LICENSE files for more details.
|
||||
#++
|
||||
|
||||
module Wikis
|
||||
module Adapters
|
||||
module Providers
|
||||
module Internal
|
||||
module Queries
|
||||
class SearchPages < BaseQuery
|
||||
MAXIMUM_RESULTS = 50
|
||||
|
||||
def call(input_data:, auth_strategy:)
|
||||
success(
|
||||
WikiPage.visible(auth_strategy.user)
|
||||
.where("title ILIKE ?", "%#{input_data.query}%")
|
||||
.limit(MAXIMUM_RESULTS)
|
||||
.map { PageInfo.wiki_page_to_page_info(it, provider:) }
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -53,6 +53,7 @@ module Wikis
|
||||
register(:page_info, Queries::PageInfo)
|
||||
register(:referencing_pages, Queries::ReferencingPages)
|
||||
register(:relation_page_links, Queries::RelationPageLinks)
|
||||
register(:search_pages, Queries::SearchPages)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
#-- copyright
|
||||
# OpenProject is an open source project management software.
|
||||
# Copyright (C) the OpenProject GmbH
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License version 3.
|
||||
#
|
||||
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
|
||||
# Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
# Copyright (C) 2010-2013 the ChiliProject Team
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#
|
||||
# See COPYRIGHT and LICENSE files for more details.
|
||||
#++
|
||||
|
||||
module Wikis
|
||||
module Adapters
|
||||
module Providers
|
||||
module XWiki
|
||||
module Queries
|
||||
class SearchPages < BaseQuery
|
||||
def call(input_data:, **)
|
||||
# TODO: use real API endpoints once available
|
||||
|
||||
titles = [
|
||||
"#{input_data.query} makes XWiki special",
|
||||
"API documentation of #{input_data.query}",
|
||||
"A brief introduction on configuring your own #{input_data.query}."
|
||||
]
|
||||
|
||||
success(titles.map { Results::PageInfo.new(identifier: "1338", title: it, href: "#", provider:) })
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -64,6 +64,7 @@ module Wikis
|
||||
register(:page_info, Queries::PageInfo)
|
||||
register(:referencing_pages, Queries::ReferencingPages)
|
||||
register(:relation_page_links, Queries::RelationPageLinks)
|
||||
register(:search_pages, Queries::SearchPages)
|
||||
end
|
||||
|
||||
namespace("validators") do
|
||||
|
||||
+3
-3
@@ -35,7 +35,7 @@ RSpec.describe Wikis::Adapters::Providers::Internal::Queries::PageInfo do
|
||||
|
||||
let(:provider) { create(:internal_wiki_provider) }
|
||||
let(:input_data) { Wikis::Adapters::Input::PageInfo.build(identifier:).value! }
|
||||
let(:auth_strategy) { provider.auth_strategy_for(current_user).value! }
|
||||
let(:auth_strategy) { provider.auth_strategy_for(user).value! }
|
||||
let(:identifier) { wiki_page.id.to_s }
|
||||
|
||||
let(:wiki_page) { create(:wiki_page) }
|
||||
@@ -43,10 +43,10 @@ RSpec.describe Wikis::Adapters::Providers::Internal::Queries::PageInfo do
|
||||
let(:other_wiki_page) { create(:wiki_page) }
|
||||
let(:permissions) { %i[view_work_packages view_wiki_pages] }
|
||||
|
||||
current_user { create(:user) }
|
||||
let(:user) { create(:user) }
|
||||
|
||||
before do
|
||||
create(:member, project:, user: current_user, roles: [create(:project_role, permissions:)])
|
||||
create(:member, project:, user:, roles: [create(:project_role, permissions:)])
|
||||
end
|
||||
|
||||
it { is_expected.to be_success }
|
||||
|
||||
+3
-3
@@ -35,7 +35,7 @@ RSpec.describe Wikis::Adapters::Providers::Internal::Queries::ReferencingPages d
|
||||
|
||||
let(:provider) { create(:internal_wiki_provider) }
|
||||
let(:input_data) { Wikis::Adapters::Input::ReferencingPages.build(linkable:).value! }
|
||||
let(:auth_strategy) { provider.auth_strategy_for(current_user).value! }
|
||||
let(:auth_strategy) { provider.auth_strategy_for(user).value! }
|
||||
let(:linkable) { create(:work_package) }
|
||||
|
||||
let(:wiki_page) { create(:wiki_page) }
|
||||
@@ -48,11 +48,11 @@ RSpec.describe Wikis::Adapters::Providers::Internal::Queries::ReferencingPages d
|
||||
]
|
||||
end
|
||||
|
||||
current_user { create(:user) }
|
||||
let(:user) { create(:user) }
|
||||
|
||||
before do
|
||||
create(:member, project: wiki_project,
|
||||
user: current_user,
|
||||
user:,
|
||||
roles: [create(:project_role, permissions: wiki_project_permissions)])
|
||||
|
||||
reverse_page_links.each(&:save!)
|
||||
|
||||
+3
-3
@@ -35,7 +35,7 @@ RSpec.describe Wikis::Adapters::Providers::Internal::Queries::RelationPageLinks
|
||||
|
||||
let(:provider) { create(:internal_wiki_provider) }
|
||||
let(:input_data) { Wikis::Adapters::Input::RelationPageLinks.build(linkable: work_package).value! }
|
||||
let(:auth_strategy) { provider.auth_strategy_for(current_user).value! }
|
||||
let(:auth_strategy) { provider.auth_strategy_for(user).value! }
|
||||
|
||||
let(:wiki_page) { create(:wiki_page) }
|
||||
let(:project) { wiki_page.project }
|
||||
@@ -48,10 +48,10 @@ RSpec.describe Wikis::Adapters::Providers::Internal::Queries::RelationPageLinks
|
||||
create(:relation_wiki_page_link, provider:, linkable: work_package, identifier: "THIS IS NO MOON")
|
||||
end
|
||||
|
||||
current_user { create(:user) }
|
||||
let(:user) { create(:user) }
|
||||
|
||||
before do
|
||||
create(:member, project:, user: current_user, roles: [create(:project_role, permissions:)])
|
||||
create(:member, project:, user:, roles: [create(:project_role, permissions:)])
|
||||
|
||||
link_to_existing_page
|
||||
link_to_non_existing_page
|
||||
|
||||
+103
@@ -0,0 +1,103 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
#-- copyright
|
||||
# OpenProject is an open source project management software.
|
||||
# Copyright (C) the OpenProject GmbH
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License version 3.
|
||||
#
|
||||
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
|
||||
# Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
# Copyright (C) 2010-2013 the ChiliProject Team
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#
|
||||
# See COPYRIGHT and LICENSE files for more details.
|
||||
#++
|
||||
|
||||
require "spec_helper"
|
||||
|
||||
RSpec.describe Wikis::Adapters::Providers::Internal::Queries::SearchPages do
|
||||
subject { described_class.new(model: provider).call(input_data:, auth_strategy:) }
|
||||
|
||||
let(:provider) { create(:internal_wiki_provider) }
|
||||
let(:input_data) { Wikis::Adapters::Input::SearchPages.build(query:).value! }
|
||||
let(:auth_strategy) { provider.auth_strategy_for(user).value! }
|
||||
let(:query) { wiki_page.title }
|
||||
|
||||
let(:wiki_page) { create(:wiki_page, title: "Wiki Page with a Title you will love") }
|
||||
let(:wiki_project) { wiki_page.project }
|
||||
let(:wiki_project_permissions) { %i[view_wiki_pages] }
|
||||
|
||||
let(:user) { create(:user) }
|
||||
|
||||
before do
|
||||
create(:member, project: wiki_project,
|
||||
user:,
|
||||
roles: [create(:project_role, permissions: wiki_project_permissions)])
|
||||
|
||||
wiki_page
|
||||
end
|
||||
|
||||
it { is_expected.to be_success }
|
||||
|
||||
it "returns pages matching the search term exactly" do
|
||||
expect(subject.value!).not_to be_empty
|
||||
expect(subject.value!.first.title).to eq(wiki_page.title)
|
||||
end
|
||||
|
||||
context "when the search term only matches partially" do
|
||||
let(:query) { "a Title" }
|
||||
|
||||
it { is_expected.to be_success }
|
||||
|
||||
it "returns matching pages" do
|
||||
expect(subject.value!).not_to be_empty
|
||||
expect(subject.value!.first.title).to eq(wiki_page.title)
|
||||
end
|
||||
end
|
||||
|
||||
context "when the search term has wrong casing" do
|
||||
let(:query) { wiki_page.title.downcase }
|
||||
|
||||
it { is_expected.to be_success }
|
||||
|
||||
it "returns matching pages" do
|
||||
expect(subject.value!).not_to be_empty
|
||||
expect(subject.value!.first.title).to eq(wiki_page.title)
|
||||
end
|
||||
end
|
||||
|
||||
context "when there are no matching pages" do
|
||||
let(:query) { "the title" }
|
||||
|
||||
it { is_expected.to be_success }
|
||||
|
||||
it "returns an empty result" do
|
||||
expect(subject.value!).to eq([])
|
||||
end
|
||||
end
|
||||
|
||||
context "when user can't see a matching wiki page" do
|
||||
let(:wiki_project_permissions) { %i[] }
|
||||
|
||||
it { is_expected.to be_success }
|
||||
|
||||
it "returns an empty result" do
|
||||
expect(subject.value!).to eq([])
|
||||
end
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user