diff --git a/modules/wikis/app/services/wikis/adapters/providers/xwiki/canonical_page_reference.rb b/modules/wikis/app/services/wikis/adapters/providers/xwiki/canonical_page_reference.rb index 431360280c5..6ff8767b2e1 100644 --- a/modules/wikis/app/services/wikis/adapters/providers/xwiki/canonical_page_reference.rb +++ b/modules/wikis/app/services/wikis/adapters/providers/xwiki/canonical_page_reference.rb @@ -51,6 +51,10 @@ module Wikis spaces_path = spaces.map { "/spaces/#{CGI.escapeURIComponent(it)}" }.join "/wikis/#{CGI.escapeURIComponent(wiki)}#{spaces_path}/pages/#{CGI.escapeURIComponent(page)}" end + + def to_s + "#{wiki}:#{spaces.join('.')}.#{page}" + end end end end diff --git a/modules/wikis/app/services/wikis/adapters/providers/xwiki/queries/canonical_page_info.rb b/modules/wikis/app/services/wikis/adapters/providers/xwiki/queries/canonical_page_info.rb new file mode 100644 index 00000000000..1274ddf8f39 --- /dev/null +++ b/modules/wikis/app/services/wikis/adapters/providers/xwiki/queries/canonical_page_info.rb @@ -0,0 +1,76 @@ +# 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 + # Fetch page information using a canonical XWiki identifier + class CanonicalPageInfo < BaseQuery + include Concerns::XWikiQuery + + def call(input_data:, auth_strategy:) + ref = CanonicalPageReference.parse(input_data.identifier) + return failure(code: :not_found) unless ref + + perform_request(ref, auth_strategy:) do |data| + success( + Results::PageInfo.new( + identifier: StablePageReference.parse(data.fetch("id")).to_s, + title: data.fetch("title"), + href: data.fetch("xwikiAbsoluteUrl"), + provider: + ) + ) + end + end + + def perform_request(reference, auth_strategy:, &) + authenticated(auth_strategy) do |http| + handle_response( + # This query is implemented as a PUT on the XWiki side, because it dynamically creates the + # stable identifier that it returns. Passing an empty JSON body is also required for the + # endpoint to not raise an error 🤷 + http.with(headers: { "Content-Type": "application/json" }) + .put( + rest_url("openproject/documents", query: { docRef: reference.to_s }), + body: "{}" + ), + & + ) + end + end + end + end + end + end + end +end diff --git a/modules/wikis/app/services/wikis/adapters/providers/xwiki/queries/search_pages.rb b/modules/wikis/app/services/wikis/adapters/providers/xwiki/queries/search_pages.rb index 5c09cabb327..c8a7e5122d5 100644 --- a/modules/wikis/app/services/wikis/adapters/providers/xwiki/queries/search_pages.rb +++ b/modules/wikis/app/services/wikis/adapters/providers/xwiki/queries/search_pages.rb @@ -47,7 +47,7 @@ module Wikis json.fetch("searchResults") .uniq { |r| r.fetch("id") } .map do |r| - result = page_info(identifier: r.fetch("id"), auth_strategy:) + result = canonical_page_info(identifier: r.fetch("id"), auth_strategy:) return result if result.failure? result.value! @@ -62,6 +62,12 @@ module Wikis def escape_quotes(string) string.gsub("\\", "\\\\").gsub('"', '\"') end + + def canonical_page_info(identifier:, auth_strategy:) + Input::PageInfo.build(identifier:).bind do |input_data| + CanonicalPageInfo.new(model: provider).call(input_data:, auth_strategy:) + end + end end end end diff --git a/modules/wikis/app/services/wikis/adapters/providers/xwiki/queries/page_info.rb b/modules/wikis/app/services/wikis/adapters/providers/xwiki/queries/stable_page_info.rb similarity index 84% rename from modules/wikis/app/services/wikis/adapters/providers/xwiki/queries/page_info.rb rename to modules/wikis/app/services/wikis/adapters/providers/xwiki/queries/stable_page_info.rb index db320cefd8e..51d2adbff3a 100644 --- a/modules/wikis/app/services/wikis/adapters/providers/xwiki/queries/page_info.rb +++ b/modules/wikis/app/services/wikis/adapters/providers/xwiki/queries/stable_page_info.rb @@ -33,20 +33,21 @@ module Wikis module Providers module XWiki module Queries - class PageInfo < BaseQuery + # Fetch page information using a stable XWiki identifier + class StablePageInfo < BaseQuery include Concerns::XWikiQuery def call(input_data:, auth_strategy:) - ref = CanonicalPageReference.parse(input_data.identifier) + ref = StablePageReference.parse(input_data.identifier) return failure(code: :not_found) unless ref authenticated(auth_strategy) do |http| handle_response(http.get(rest_url(ref.rest_path))) do |data| success( Results::PageInfo.new( - identifier: input_data.identifier, - title: data["title"], - href: data["xwikiAbsoluteUrl"], + identifier: ref.to_s, + title: data.fetch("title"), + href: data.fetch("xwikiAbsoluteUrl"), provider: ) ) diff --git a/modules/wikis/app/services/wikis/adapters/providers/xwiki/registry.rb b/modules/wikis/app/services/wikis/adapters/providers/xwiki/registry.rb index 534328ecf15..057136c3ade 100644 --- a/modules/wikis/app/services/wikis/adapters/providers/xwiki/registry.rb +++ b/modules/wikis/app/services/wikis/adapters/providers/xwiki/registry.rb @@ -61,7 +61,7 @@ module Wikis namespace("queries") do register(:user, Queries::User) - register(:page_info, Queries::PageInfo) + register(:page_info, Queries::StablePageInfo) register(:referencing_pages, Queries::ReferencingPages) register(:relation_page_links, Queries::RelationPageLinks) register(:search_pages, Queries::SearchPages) diff --git a/modules/wikis/app/services/wikis/adapters/providers/xwiki/stable_page_reference.rb b/modules/wikis/app/services/wikis/adapters/providers/xwiki/stable_page_reference.rb new file mode 100644 index 00000000000..d92675cf8cc --- /dev/null +++ b/modules/wikis/app/services/wikis/adapters/providers/xwiki/stable_page_reference.rb @@ -0,0 +1,60 @@ +# 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 + # Represents an XWiki page identifier using the "stable" page identifier format: e.g. 0b89a + StablePageReference = Data.define(:uid) do + class << self + private :new + + def parse(uid) + return nil if uid.nil? + + new(uid:) + end + end + + # Maps the reference to the REST API path, excluding the `/rest` prefix, e.g. + # /openproject/documents/0b89a + def rest_path + "/openproject/documents/#{CGI.escapeURIComponent(uid)}" + end + + def to_s + uid + end + end + end + end + end +end diff --git a/modules/wikis/spec/requests/api/v3/page_links/page_links_api_spec.rb b/modules/wikis/spec/requests/api/v3/page_links/page_links_api_spec.rb index 3ba6cb3f773..9f16d377916 100644 --- a/modules/wikis/spec/requests/api/v3/page_links/page_links_api_spec.rb +++ b/modules/wikis/spec/requests/api/v3/page_links/page_links_api_spec.rb @@ -168,10 +168,10 @@ RSpec.describe "API v3 wiki page links resource", content_type: :json do def stub_provider_queries internal_class = class_double(Wikis::Adapters::Providers::Internal::Queries::PageInfo) - xwiki_class = class_double(Wikis::Adapters::Providers::XWiki::Queries::PageInfo) + xwiki_class = class_double(Wikis::Adapters::Providers::XWiki::Queries::StablePageInfo) internal_query = instance_double(Wikis::Adapters::Providers::Internal::Queries::PageInfo) - xwiki_query = instance_double(Wikis::Adapters::Providers::XWiki::Queries::PageInfo) + xwiki_query = instance_double(Wikis::Adapters::Providers::XWiki::Queries::StablePageInfo) Wikis::Adapters::Registry.stub("internal.queries.page_info", internal_class) Wikis::Adapters::Registry.stub("xwiki.queries.page_info", xwiki_class) diff --git a/modules/wikis/spec/services/wikis/adapters/providers/xwiki/canonical_page_reference_spec.rb b/modules/wikis/spec/services/wikis/adapters/providers/xwiki/canonical_page_reference_spec.rb index 5ecbf7daa0f..8c7d29619a2 100644 --- a/modules/wikis/spec/services/wikis/adapters/providers/xwiki/canonical_page_reference_spec.rb +++ b/modules/wikis/spec/services/wikis/adapters/providers/xwiki/canonical_page_reference_spec.rb @@ -87,4 +87,24 @@ RSpec.describe Wikis::Adapters::Providers::XWiki::CanonicalPageReference do it { is_expected.to eq("/wikis/xwiki/spaces/My%20Space/pages/My%20Page") } end end + + describe "#to_s" do + subject { described_class.parse(identifier).to_s } + + context "with a standard identifier" do + let(:identifier) { "xwiki:Main.WebHome" } + + it "roundtrips" do + expect(subject).to eq(identifier) + end + end + + context "with a nested space identifier" do + let(:identifier) { "xwiki:MySpace.SubSpace.PageName" } + + it "roundtrips" do + expect(subject).to eq(identifier) + end + end + end end diff --git a/modules/wikis/spec/services/wikis/adapters/providers/xwiki/queries/page_info_spec.rb b/modules/wikis/spec/services/wikis/adapters/providers/xwiki/queries/canonical_page_info_spec.rb similarity index 71% rename from modules/wikis/spec/services/wikis/adapters/providers/xwiki/queries/page_info_spec.rb rename to modules/wikis/spec/services/wikis/adapters/providers/xwiki/queries/canonical_page_info_spec.rb index e9be445be71..27e913c3a2b 100644 --- a/modules/wikis/spec/services/wikis/adapters/providers/xwiki/queries/page_info_spec.rb +++ b/modules/wikis/spec/services/wikis/adapters/providers/xwiki/queries/canonical_page_info_spec.rb @@ -31,52 +31,46 @@ require "spec_helper" require_module_spec_helper -RSpec.describe Wikis::Adapters::Providers::XWiki::Queries::PageInfo, :webmock do - it "is registered" do - expect(Wikis::Adapters::Registry.resolve("xwiki.queries.page_info")).to eq(described_class) +RSpec.describe Wikis::Adapters::Providers::XWiki::Queries::CanonicalPageInfo, :webmock do + it "is not registered" do + expect(Wikis::Adapters::Registry.resolve("xwiki.queries.page_info")).not_to eq(described_class) end describe "#call" do let(:user) { create(:user) } - let(:wiki_provider) { create(:xwiki_provider, :with_connected_user, url: "https://xwiki.example.com/", connected_user: user) } + let(:wiki_provider) { create(:xwiki_provider, :for_local_connection, connected_user: user) } let(:identifier) { "xwiki:Main.WebHome" } - let(:page_url) { "https://xwiki.example.com/rest/wikis/xwiki/spaces/Main/pages/WebHome" } + let(:page_url) { "https://xwiki.local/rest/openproject/documents?docRef=xwiki:Main.WebHome" } let(:auth_strategy) { Wikis::Adapters::Input::AuthStrategy.build(key: :bearer_token, user:, provider: wiki_provider).value! } let(:input_data) { Wikis::Adapters::Input::PageInfo.build(identifier:).value! } let(:query) { described_class.new(model: wiki_provider) } subject(:result) { query.call(input_data:, auth_strategy:) } - context "when the page exists" do - let(:page_response) do - { "title" => "Home", "xwikiAbsoluteUrl" => "https://xwiki.example.com/bin/view/Main/" }.to_json - end - - before do - stub_request(:get, page_url) - .with(headers: { "Authorization" => "Bearer user-bearer-token" }) - .to_return(status: 200, body: page_response, headers: { "Content-Type" => "application/json" }) - end + context "when the page exists", vcr: "xwiki/canonical_page_info" do + # Set the expected identifier according to the stable identifier returned by XWiki (or update the VCR cassette accordingly) + let(:expected_identifier) { "484f4" } it "returns Success with title and href" do expect(result).to be_success expect(result.value!).to have_attributes( - identifier:, + identifier: expected_identifier, title: "Home", - href: "https://xwiki.example.com/bin/view/Main/" + href: "https://xwiki.local/bin/view/Main/" ) end end context "with a nested space identifier" do let(:identifier) { "xwiki:MySpace.SubSpace.PageName" } - let(:page_url) { "https://xwiki.example.com/rest/wikis/xwiki/spaces/MySpace/spaces/SubSpace/pages/PageName" } - let(:absolute_url) { "https://xwiki.example.com/bin/view/MySpace/SubSpace/PageName" } + let(:page_url) do + "https://xwiki.local/rest/openproject/documents?docRef=xwiki:MySpace.SubSpace.PageName" + end + let(:absolute_url) { "https://xwiki.local/bin/view/MySpace/SubSpace/PageName" } before do - stub_request(:get, page_url) - .to_return(status: 200, body: { "title" => "Nested Page", - "xwikiAbsoluteUrl" => absolute_url }.to_json, + stub_request(:put, page_url) + .to_return(status: 200, body: { id: "foo", title: "Nested Page", xwikiAbsoluteUrl: absolute_url }.to_json, headers: { "Content-Type" => "application/json" }) end @@ -93,44 +87,44 @@ RSpec.describe Wikis::Adapters::Providers::XWiki::Queries::PageInfo, :webmock do end context "when no OAuth token exists for the user" do - let(:wiki_provider) { create(:xwiki_provider, :with_oauth_client, url: "https://xwiki.example.com/") } + let(:wiki_provider) { create(:xwiki_provider, :with_oauth_client, url: "https://xwiki.local/") } it { is_expected.to be_failure.and have_attributes(failure: have_attributes(code: :missing_token)) } end context "when the page is not found" do - before { stub_request(:get, page_url).to_return(status: 404, body: "") } + before { stub_request(:put, page_url).to_return(status: 404, body: "") } it { is_expected.to be_failure.and have_attributes(failure: have_attributes(code: :not_found)) } end context "when access is unauthorized" do - before { stub_request(:get, page_url).to_return(status: 401, body: "") } + before { stub_request(:put, page_url).to_return(status: 401, body: "") } it { is_expected.to be_failure.and have_attributes(failure: have_attributes(code: :unauthorized)) } end context "when access is forbidden" do - before { stub_request(:get, page_url).to_return(status: 403, body: "") } + before { stub_request(:put, page_url).to_return(status: 403, body: "") } it { is_expected.to be_failure.and have_attributes(failure: have_attributes(code: :unauthorized)) } end context "when XWiki returns a non-2xx status" do - before { stub_request(:get, page_url).to_return(status: 500, body: "Internal Server Error") } + before { stub_request(:put, page_url).to_return(status: 500, body: "Internal Server Error") } it { is_expected.to be_failure.and have_attributes(failure: have_attributes(code: :request_failed)) } end context "when a network error occurs" do - before { stub_request(:get, page_url).to_timeout } + before { stub_request(:put, page_url).to_timeout } it { is_expected.to be_failure.and have_attributes(failure: have_attributes(code: :connection_error)) } end context "when the response body is not valid JSON" do before do - stub_request(:get, page_url) + stub_request(:put, page_url) .to_return(status: 200, body: "not json", headers: { "Content-Type" => "application/json" }) end diff --git a/modules/wikis/spec/services/wikis/adapters/providers/xwiki/queries/search_pages_spec.rb b/modules/wikis/spec/services/wikis/adapters/providers/xwiki/queries/search_pages_spec.rb index 9ae5ed65751..590fb2625f6 100644 --- a/modules/wikis/spec/services/wikis/adapters/providers/xwiki/queries/search_pages_spec.rb +++ b/modules/wikis/spec/services/wikis/adapters/providers/xwiki/queries/search_pages_spec.rb @@ -53,6 +53,13 @@ RSpec.describe Wikis::Adapters::Providers::XWiki::Queries::SearchPages, :disable expect(subject.value!.first.title).to eq("Test Page for RSpec") end + it "returns a complete PageInfo result" do + page_info = subject.value!.first + page_info.to_h.each do |attribute, value| + expect(value).not_to be_nil, "#{attribute} was expected to be non-nil, but was nil" + end + end + it "returns no other random results" do expect(subject.value!.count).to eq(1) end diff --git a/modules/wikis/spec/services/wikis/adapters/providers/xwiki/queries/stable_page_info_spec.rb b/modules/wikis/spec/services/wikis/adapters/providers/xwiki/queries/stable_page_info_spec.rb new file mode 100644 index 00000000000..85814a11e1b --- /dev/null +++ b/modules/wikis/spec/services/wikis/adapters/providers/xwiki/queries/stable_page_info_spec.rb @@ -0,0 +1,110 @@ +# 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" +require_module_spec_helper + +RSpec.describe Wikis::Adapters::Providers::XWiki::Queries::StablePageInfo, :webmock do + it "is registered" do + expect(Wikis::Adapters::Registry.resolve("xwiki.queries.page_info")).to eq(described_class) + end + + describe "#call" do + let(:user) { create(:user) } + let(:wiki_provider) { create(:xwiki_provider, :for_local_connection, connected_user: user) } + let(:identifier) { "123abc" } + let(:page_url) { "https://xwiki.local/rest/openproject/documents/123abc" } + let(:auth_strategy) { Wikis::Adapters::Input::AuthStrategy.build(key: :bearer_token, user:, provider: wiki_provider).value! } + let(:input_data) { Wikis::Adapters::Input::PageInfo.build(identifier:).value! } + let(:query) { described_class.new(model: wiki_provider) } + + subject(:result) { query.call(input_data:, auth_strategy:) } + + context "when the page exists", vcr: "xwiki/stable_page_info" do + # Before recording cassette make sure a wiki page with title "Test Page for RSpec" exists + # Set the according identifier of that test page below + let(:identifier) { "d70f1" } + + it "returns Success with title and href" do + expect(result).to be_success + expect(result.value!).to have_attributes( + identifier: "d70f1", + title: "Test Page for RSpec", + href: "https://xwiki.local/bin/view/Test%20Page/" + ) + end + end + + context "when no OAuth token exists for the user" do + let(:wiki_provider) { create(:xwiki_provider, :with_oauth_client, url: "https://xwiki.local/") } + + it { is_expected.to be_failure.and have_attributes(failure: have_attributes(code: :missing_token)) } + end + + context "when the page is not found" do + before { stub_request(:get, page_url).to_return(status: 404, body: "") } + + it { is_expected.to be_failure.and have_attributes(failure: have_attributes(code: :not_found)) } + end + + context "when access is unauthorized" do + before { stub_request(:get, page_url).to_return(status: 401, body: "") } + + it { is_expected.to be_failure.and have_attributes(failure: have_attributes(code: :unauthorized)) } + end + + context "when access is forbidden" do + before { stub_request(:get, page_url).to_return(status: 403, body: "") } + + it { is_expected.to be_failure.and have_attributes(failure: have_attributes(code: :unauthorized)) } + end + + context "when XWiki returns a non-2xx status" do + before { stub_request(:get, page_url).to_return(status: 500, body: "Internal Server Error") } + + it { is_expected.to be_failure.and have_attributes(failure: have_attributes(code: :request_failed)) } + end + + context "when a network error occurs" do + before { stub_request(:get, page_url).to_timeout } + + it { is_expected.to be_failure.and have_attributes(failure: have_attributes(code: :connection_error)) } + end + + context "when the response body is not valid JSON" do + before do + stub_request(:get, page_url) + .to_return(status: 200, body: "not json", headers: { "Content-Type" => "application/json" }) + end + + it { is_expected.to be_failure.and have_attributes(failure: have_attributes(code: :invalid_response)) } + end + end +end diff --git a/modules/wikis/spec/services/wikis/adapters/providers/xwiki/stable_page_reference_spec.rb b/modules/wikis/spec/services/wikis/adapters/providers/xwiki/stable_page_reference_spec.rb new file mode 100644 index 00000000000..ee223d4af85 --- /dev/null +++ b/modules/wikis/spec/services/wikis/adapters/providers/xwiki/stable_page_reference_spec.rb @@ -0,0 +1,66 @@ +# 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" +require_module_spec_helper + +RSpec.describe Wikis::Adapters::Providers::XWiki::StablePageReference do + describe ".parse" do + subject { described_class.parse(identifier) } + + let(:identifier) { "123abc" } + + it { is_expected.to have_attributes(uid: "123abc") } + + context "when passing nil" do + let(:identifier) { nil } + + it { is_expected.to be_nil } + end + end + + describe "#rest_path" do + subject { described_class.parse(identifier).rest_path } + + let(:identifier) { "123abc" } + + it { is_expected.to eq("/openproject/documents/123abc") } + end + + describe "#to_s" do + subject { described_class.parse(identifier).to_s } + + let(:identifier) { "123abc" } + + it "roundtrips" do + expect(subject).to eq(identifier) + end + end +end diff --git a/spec/support/fixtures/vcr_cassettes/xwiki/canonical_page_info.yml b/spec/support/fixtures/vcr_cassettes/xwiki/canonical_page_info.yml new file mode 100644 index 00000000000..85549582438 --- /dev/null +++ b/spec/support/fixtures/vcr_cassettes/xwiki/canonical_page_info.yml @@ -0,0 +1,73 @@ +--- +http_interactions: +- request: + method: put + uri: https://xwiki.local/rest/openproject/documents?docRef=xwiki:Main.WebHome + body: + encoding: UTF-8 + string: "{}" + headers: + User-Agent: + - OpenProject 17.6.0 HTTPX Client + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Content-Type: + - application/json + Content-Length: + - '2' + Authorization: + - Bearer + response: + status: + code: 202 + message: Accepted + headers: + Content-Language: + - en + Content-Script-Type: + - text/javascript + Content-Type: + - application/json;charset=UTF-8 + Date: + - Fri, 05 Jun 2026 06:30:56 GMT + Set-Cookie: + - JSESSIONID=E1711FFA64B3AFE5CBB3FA5881A7138D; Path=/; HttpOnly + Xwiki-Form-Token: + - ON8xsHlEpixyujzpUPNupg + Xwiki-User: + - xwiki:XWiki.admin + Xwiki-Version: + - 18.3.0 + body: + encoding: UTF-8 + string: '{"links":[{"href":"https://xwiki.local/rest/wikis/xwiki/spaces/Main","rel":"http://www.xwiki.org/rel/space","type":null,"hrefLang":null},{"href":"https://xwiki.local/rest/wikis/xwiki/spaces/Main/pages/WebHome/history","rel":"http://www.xwiki.org/rel/history","type":null,"hrefLang":null},{"href":"https://xwiki.local/rest/wikis/xwiki/spaces/Main/pages/WebHome/children","rel":"http://www.xwiki.org/rel/children","type":null,"hrefLang":null},{"href":"https://xwiki.local/rest/wikis/xwiki/spaces/Main/pages/WebHome/objects","rel":"http://www.xwiki.org/rel/objects","type":null,"hrefLang":null},{"href":"https://xwiki.local/rest/syntaxes","rel":"http://www.xwiki.org/rel/syntaxes","type":null,"hrefLang":null},{"href":"https://xwiki.local/rest/openproject/documents","rel":"self","type":null,"hrefLang":null},{"href":"https://xwiki.local/rest/wikis/xwiki/classes/Main.WebHome","rel":"http://www.xwiki.org/rel/class","type":null,"hrefLang":null}],"id":"484f4","fullName":"Main.WebHome","wiki":"xwiki","space":"Main","name":"WebHome","title":"Home","rawTitle":"Home","parent":"","parentId":"","version":"1.1","author":"XWiki.admin","authorName":null,"xwikiRelativeUrl":"https://xwiki.local/bin/view/Main/","xwikiAbsoluteUrl":"https://xwiki.local/bin/view/Main/","translations":{"links":[],"translations":[{"links":[{"href":"https://xwiki.local/rest/wikis/xwiki/spaces/Main/pages/WebHome","rel":"http://www.xwiki.org/rel/page","type":null,"hrefLang":null},{"href":"https://xwiki.local/rest/wikis/xwiki/spaces/Main/pages/WebHome/history","rel":"http://www.xwiki.org/rel/history","type":null,"hrefLang":null}],"language":"en"},{"links":[{"href":"https://xwiki.local/rest/wikis/xwiki/spaces/Main/pages/WebHome/translations/pt_BR","rel":"http://www.xwiki.org/rel/page","type":null,"hrefLang":null},{"href":"https://xwiki.local/rest/wikis/xwiki/spaces/Main/pages/WebHome/translations/pt_BR/history","rel":"http://www.xwiki.org/rel/history","type":null,"hrefLang":null}],"language":"pt_BR"},{"links":[{"href":"https://xwiki.local/rest/wikis/xwiki/spaces/Main/pages/WebHome/translations/ru","rel":"http://www.xwiki.org/rel/page","type":null,"hrefLang":null},{"href":"https://xwiki.local/rest/wikis/xwiki/spaces/Main/pages/WebHome/translations/ru/history","rel":"http://www.xwiki.org/rel/history","type":null,"hrefLang":null}],"language":"ru"},{"links":[{"href":"https://xwiki.local/rest/wikis/xwiki/spaces/Main/pages/WebHome/translations/fr","rel":"http://www.xwiki.org/rel/page","type":null,"hrefLang":null},{"href":"https://xwiki.local/rest/wikis/xwiki/spaces/Main/pages/WebHome/translations/fr/history","rel":"http://www.xwiki.org/rel/history","type":null,"hrefLang":null}],"language":"fr"},{"links":[{"href":"https://xwiki.local/rest/wikis/xwiki/spaces/Main/pages/WebHome/translations/no","rel":"http://www.xwiki.org/rel/page","type":null,"hrefLang":null},{"href":"https://xwiki.local/rest/wikis/xwiki/spaces/Main/pages/WebHome/translations/no/history","rel":"http://www.xwiki.org/rel/history","type":null,"hrefLang":null}],"language":"no"},{"links":[{"href":"https://xwiki.local/rest/wikis/xwiki/spaces/Main/pages/WebHome/translations/da","rel":"http://www.xwiki.org/rel/page","type":null,"hrefLang":null},{"href":"https://xwiki.local/rest/wikis/xwiki/spaces/Main/pages/WebHome/translations/da/history","rel":"http://www.xwiki.org/rel/history","type":null,"hrefLang":null}],"language":"da"},{"links":[{"href":"https://xwiki.local/rest/wikis/xwiki/spaces/Main/pages/WebHome/translations/de","rel":"http://www.xwiki.org/rel/page","type":null,"hrefLang":null},{"href":"https://xwiki.local/rest/wikis/xwiki/spaces/Main/pages/WebHome/translations/de/history","rel":"http://www.xwiki.org/rel/history","type":null,"hrefLang":null}],"language":"de"},{"links":[{"href":"https://xwiki.local/rest/wikis/xwiki/spaces/Main/pages/WebHome/translations/en_GB","rel":"http://www.xwiki.org/rel/page","type":null,"hrefLang":null},{"href":"https://xwiki.local/rest/wikis/xwiki/spaces/Main/pages/WebHome/translations/en_GB/history","rel":"http://www.xwiki.org/rel/history","type":null,"hrefLang":null}],"language":"en_GB"},{"links":[{"href":"https://xwiki.local/rest/wikis/xwiki/spaces/Main/pages/WebHome/translations/es","rel":"http://www.xwiki.org/rel/page","type":null,"hrefLang":null},{"href":"https://xwiki.local/rest/wikis/xwiki/spaces/Main/pages/WebHome/translations/es/history","rel":"http://www.xwiki.org/rel/history","type":null,"hrefLang":null}],"language":"es"},{"links":[{"href":"https://xwiki.local/rest/wikis/xwiki/spaces/Main/pages/WebHome/translations/ca","rel":"http://www.xwiki.org/rel/page","type":null,"hrefLang":null},{"href":"https://xwiki.local/rest/wikis/xwiki/spaces/Main/pages/WebHome/translations/ca/history","rel":"http://www.xwiki.org/rel/history","type":null,"hrefLang":null}],"language":"ca"},{"links":[{"href":"https://xwiki.local/rest/wikis/xwiki/spaces/Main/pages/WebHome/translations/ko","rel":"http://www.xwiki.org/rel/page","type":null,"hrefLang":null},{"href":"https://xwiki.local/rest/wikis/xwiki/spaces/Main/pages/WebHome/translations/ko/history","rel":"http://www.xwiki.org/rel/history","type":null,"hrefLang":null}],"language":"ko"},{"links":[{"href":"https://xwiki.local/rest/wikis/xwiki/spaces/Main/pages/WebHome/translations/ja","rel":"http://www.xwiki.org/rel/page","type":null,"hrefLang":null},{"href":"https://xwiki.local/rest/wikis/xwiki/spaces/Main/pages/WebHome/translations/ja/history","rel":"http://www.xwiki.org/rel/history","type":null,"hrefLang":null}],"language":"ja"},{"links":[{"href":"https://xwiki.local/rest/wikis/xwiki/spaces/Main/pages/WebHome/translations/uk","rel":"http://www.xwiki.org/rel/page","type":null,"hrefLang":null},{"href":"https://xwiki.local/rest/wikis/xwiki/spaces/Main/pages/WebHome/translations/uk/history","rel":"http://www.xwiki.org/rel/history","type":null,"hrefLang":null}],"language":"uk"}],"default":"en"},"syntax":"xwiki/2.1","language":"","majorVersion":1,"minorVersion":1,"hidden":false,"enforceRequiredRights":false,"created":1773821175000,"creator":"XWiki.admin","creatorName":null,"modified":1773821175000,"modifier":"XWiki.admin","modifierName":null,"originalMetadataAuthor":"xwiki:XWiki.admin","originalMetadataAuthorName":null,"comment":"Created + URL Shortener.","content":"== Welcome to your wiki ==\n\nXWiki is the best + tool to organize your knowledge. A //wiki// is organized in a hierarchy of + //pages//. You can create multiple wikis, each with its own set of pages.\n\nXWiki + can be used as a knowledge base (support, documentation, sales, etc.), for + collaborative workspaces or even as a complete intranet.\n\n== The basics + ==\n\nTo make the most out of your wiki, log-in and:\n\nUse the {{displayIcon + name=\"pencil\"/}} button above to //edit// this page and start customizing + your wiki to your needs.\n\nUse the {{displayIcon name=\"add\"/}} button above + to //add// more pages to your wiki and create the //hierarchy// that best + organizes your content.\n\nUse the {{displayIcon name=\"home\"/}} breadcrumbs + located above the title to //navigate// inside your pages. It''s easy to get + lost in a big wiki without them.\n\nYou can also use the [[Sandbox>>Sandbox.WebHome]] + for more demo content and generally a place to experiment with your wiki''s + features. \n\n {{box}}Learn more on how to use XWiki with the [[Getting Started + Guide>>https://www.xwiki.org/xwiki/bin/view/Documentation/UserGuide/GettingStarted/WebHome]].{{/box}}\n\n(% + class=\"row\" %)\n(((\n(% class=\"col-xs-12 col-sm-6\" %)\n(((\n== Extend + your wiki ==\n\nTo extend the power and functionalities of your wiki with + the features that //you// need, head over to the [[Extension Manager>>XWiki.XWikiPreferences||queryString=\"editor=globaladmin§ion=XWiki.Extensions\"]] + where you can search for and install extensions.\n\nTo browse through the + 900+ community contributed extensions available for XWiki, head over to the + [[Extensions Repository>>https://extensions.xwiki.org]].\n)))\n\n(% class=\"col-xs-12 + col-sm-6\" %)\n(((\n== Create your application ==\n\nGo beyond the available + extensions and define the //structure// of your data based on //your// needs, + creating //your// own applications with [[App Within Minutes>>AppWithinMinutes]] + (AWM). \n\nAWM will take care of making it easy for you and your users to + create and manage the data.\n)))\n)))","clazz":null,"objects":null,"attachments":null,"hierarchy":{"items":[{"label":"xwiki","name":"xwiki","type":"wiki","url":"https://xwiki.local/bin/view/Main/"},{"label":"Main","name":"Main","type":"space","url":"https://xwiki.local/bin/view/Main/"},{"label":"WebHome","name":"WebHome","type":"document","url":"https://xwiki.local/bin/view/Main/"}]},"rights":[],"renderedContent":null}' + recorded_at: Fri, 05 Jun 2026 06:30:56 GMT +recorded_with: VCR 6.4.0 diff --git a/spec/support/fixtures/vcr_cassettes/xwiki/query_exact_match.yml b/spec/support/fixtures/vcr_cassettes/xwiki/query_exact_match.yml index 18637472313..8791bef049a 100644 --- a/spec/support/fixtures/vcr_cassettes/xwiki/query_exact_match.yml +++ b/spec/support/fixtures/vcr_cassettes/xwiki/query_exact_match.yml @@ -27,29 +27,29 @@ http_interactions: Content-Type: - application/json;charset=UTF-8 Date: - - Tue, 02 Jun 2026 08:17:22 GMT + - Fri, 05 Jun 2026 06:39:19 GMT Set-Cookie: - - JSESSIONID=A90934AE8F68AA76D0E0970863A314F8; Path=/; HttpOnly + - JSESSIONID=EF2A09F6E0681B4B0B3E44D639CB89D9; Path=/; HttpOnly Xwiki-Form-Token: - - 2XZUUfWArYhRgLYx4nHjhQ + - ON8xsHlEpixyujzpUPNupg Xwiki-User: - xwiki:XWiki.admin Xwiki-Version: - 18.3.0 Content-Length: - - '790' + - '789' body: encoding: UTF-8 string: '{"links":[],"searchResults":[{"links":[{"href":"https://xwiki.local/rest/wikis/xwiki/spaces/Test%20Page/pages/WebHome","rel":"http://www.xwiki.org/rel/page","type":null,"hrefLang":null}],"type":"page","id":"xwiki:Test Page.WebHome","pageFullName":"Test Page.WebHome","title":"Test Page for RSpec","wiki":"xwiki","space":"Test - Page","pageName":"WebHome","modified":1780386902000,"author":"xwiki:XWiki.admin","authorName":null,"version":"4.1","language":null,"className":null,"objectNumber":null,"filename":null,"score":30.283539,"object":null,"hierarchy":null}],"template":"https://xwiki.local/rest/?q={solrquery}(&number={number})(&start={start})(&orderField={fieldname}(&order={asc|desc}))(&distinct=1)(&prettyNames={false|true})(&wikis={wikis})(&className={classname})"}' - recorded_at: Tue, 02 Jun 2026 08:17:22 GMT + Page","pageName":"WebHome","modified":1780386902000,"author":"xwiki:XWiki.admin","authorName":null,"version":"4.1","language":null,"className":null,"objectNumber":null,"filename":null,"score":32.03692,"object":null,"hierarchy":null}],"template":"https://xwiki.local/rest/?q={solrquery}(&number={number})(&start={start})(&orderField={fieldname}(&order={asc|desc}))(&distinct=1)(&prettyNames={false|true})(&wikis={wikis})(&className={classname})"}' + recorded_at: Fri, 05 Jun 2026 06:39:19 GMT - request: - method: get - uri: https://xwiki.local/rest/wikis/xwiki/spaces/Test%20Page/pages/WebHome + method: put + uri: https://xwiki.local/rest/openproject/documents?docRef=xwiki:Test%20Page.WebHome body: - encoding: US-ASCII - string: '' + encoding: UTF-8 + string: "{}" headers: User-Agent: - OpenProject 17.6.0 HTTPX Client @@ -57,12 +57,16 @@ http_interactions: - application/json Accept-Encoding: - gzip, deflate + Content-Type: + - application/json + Content-Length: + - '2' Authorization: - Bearer response: status: - code: 200 - message: OK + code: 202 + message: Accepted headers: Content-Language: - en @@ -71,24 +75,24 @@ http_interactions: Content-Type: - application/json;charset=UTF-8 Date: - - Tue, 02 Jun 2026 08:17:22 GMT + - Fri, 05 Jun 2026 06:39:19 GMT Set-Cookie: - - JSESSIONID=6D38F35499AE562F0EEE91795F9951CF; Path=/; HttpOnly + - JSESSIONID=CD75D58F42FA2FF29480F0AA679975CB; Path=/; HttpOnly Xwiki-Form-Token: - - 2XZUUfWArYhRgLYx4nHjhQ + - ON8xsHlEpixyujzpUPNupg Xwiki-User: - xwiki:XWiki.admin Xwiki-Version: - 18.3.0 Content-Length: - - '2224' + - '2372' body: encoding: UTF-8 - string: '{"links":[{"href":"https://xwiki.local/rest/wikis/xwiki/spaces/Test%20Page","rel":"http://www.xwiki.org/rel/space","type":null,"hrefLang":null},{"href":"https://xwiki.local/rest/wikis/xwiki/spaces/Test%20Page/pages/WebHome","rel":"http://www.xwiki.org/rel/parent","type":null,"hrefLang":null},{"href":"https://xwiki.local/rest/wikis/xwiki/spaces/Test%20Page/pages/WebHome/history","rel":"http://www.xwiki.org/rel/history","type":null,"hrefLang":null},{"href":"https://xwiki.local/rest/syntaxes","rel":"http://www.xwiki.org/rel/syntaxes","type":null,"hrefLang":null},{"href":"https://xwiki.local/rest/wikis/xwiki/spaces/Test%20Page/pages/WebHome","rel":"self","type":null,"hrefLang":null},{"href":"https://xwiki.local/rest/wikis/xwiki/classes/Test%20Page.WebHome","rel":"http://www.xwiki.org/rel/class","type":null,"hrefLang":null}],"id":"xwiki:Test - Page.WebHome","fullName":"Test Page.WebHome","wiki":"xwiki","space":"Test - Page","name":"WebHome","title":"Test Page for RSpec","rawTitle":"Test Page - for RSpec","parent":"Main.WebHome","parentId":"xwiki:Main.WebHome","version":"4.1","author":"XWiki.admin","authorName":null,"xwikiRelativeUrl":"https://xwiki.local/bin/view/Test%20Page/","xwikiAbsoluteUrl":"https://xwiki.local/bin/view/Test%20Page/","translations":{"links":[],"translations":[],"default":"en"},"syntax":"xwiki/2.1","language":"","majorVersion":4,"minorVersion":1,"hidden":false,"enforceRequiredRights":false,"created":1780383689000,"creator":"XWiki.admin","creatorName":null,"modified":1780386902000,"modifier":"XWiki.admin","modifierName":null,"originalMetadataAuthor":"xwiki:XWiki.admin","originalMetadataAuthorName":null,"comment":"","content":"This - is a test page that I created with my own hands.","clazz":null,"objects":null,"attachments":null,"hierarchy":{"items":[{"label":"xwiki","name":"xwiki","type":"wiki","url":"https://xwiki.local/bin/view/Main/"},{"label":"Test + string: '{"links":[{"href":"https://xwiki.local/rest/wikis/xwiki/spaces/Test%20Page","rel":"http://www.xwiki.org/rel/space","type":null,"hrefLang":null},{"href":"https://xwiki.local/rest/wikis/xwiki/spaces/Test%20Page/pages/WebHome","rel":"http://www.xwiki.org/rel/parent","type":null,"hrefLang":null},{"href":"https://xwiki.local/rest/wikis/xwiki/spaces/Test%20Page/pages/WebHome/history","rel":"http://www.xwiki.org/rel/history","type":null,"hrefLang":null},{"href":"https://xwiki.local/rest/wikis/xwiki/spaces/Test%20Page/pages/WebHome/objects","rel":"http://www.xwiki.org/rel/objects","type":null,"hrefLang":null},{"href":"https://xwiki.local/rest/syntaxes","rel":"http://www.xwiki.org/rel/syntaxes","type":null,"hrefLang":null},{"href":"https://xwiki.local/rest/openproject/documents","rel":"self","type":null,"hrefLang":null},{"href":"https://xwiki.local/rest/wikis/xwiki/classes/Test%20Page.WebHome","rel":"http://www.xwiki.org/rel/class","type":null,"hrefLang":null}],"id":"d70f1","fullName":"Test + Page.WebHome","wiki":"xwiki","space":"Test Page","name":"WebHome","title":"Test + Page for RSpec","rawTitle":"Test Page for RSpec","parent":"Main.WebHome","parentId":"xwiki:Main.WebHome","version":"4.1","author":"XWiki.admin","authorName":null,"xwikiRelativeUrl":"https://xwiki.local/bin/view/Test%20Page/","xwikiAbsoluteUrl":"https://xwiki.local/bin/view/Test%20Page/","translations":{"links":[],"translations":[],"default":"en"},"syntax":"xwiki/2.1","language":"","majorVersion":4,"minorVersion":1,"hidden":false,"enforceRequiredRights":false,"created":1780383689000,"creator":"XWiki.admin","creatorName":null,"modified":1780386902000,"modifier":"XWiki.admin","modifierName":null,"originalMetadataAuthor":"xwiki:XWiki.admin","originalMetadataAuthorName":null,"comment":"Created + URL Shortener.","content":"This is a test page that I created with my own + hands.","clazz":null,"objects":null,"attachments":null,"hierarchy":{"items":[{"label":"xwiki","name":"xwiki","type":"wiki","url":"https://xwiki.local/bin/view/Main/"},{"label":"Test Page","name":"Test Page","type":"space","url":"https://xwiki.local/bin/view/Test%20Page/"},{"label":"WebHome","name":"WebHome","type":"document","url":"https://xwiki.local/bin/view/Test%20Page/"}]},"rights":[],"renderedContent":null}' - recorded_at: Tue, 02 Jun 2026 08:17:22 GMT + recorded_at: Fri, 05 Jun 2026 06:39:19 GMT recorded_with: VCR 6.4.0 diff --git a/spec/support/fixtures/vcr_cassettes/xwiki/query_no_match.yml b/spec/support/fixtures/vcr_cassettes/xwiki/query_no_match.yml index 21d38b10029..c1158559d9d 100644 --- a/spec/support/fixtures/vcr_cassettes/xwiki/query_no_match.yml +++ b/spec/support/fixtures/vcr_cassettes/xwiki/query_no_match.yml @@ -27,11 +27,11 @@ http_interactions: Content-Type: - application/json;charset=UTF-8 Date: - - Tue, 02 Jun 2026 08:17:23 GMT + - Fri, 05 Jun 2026 06:39:20 GMT Set-Cookie: - - JSESSIONID=9D417B4F0A9D4C117C903A54394DAD6C; Path=/; HttpOnly + - JSESSIONID=D1B7C7CFA5520362BCB9E2DB63EFCE00; Path=/; HttpOnly Xwiki-Form-Token: - - 2XZUUfWArYhRgLYx4nHjhQ + - ON8xsHlEpixyujzpUPNupg Xwiki-User: - xwiki:XWiki.admin Xwiki-Version: @@ -41,5 +41,5 @@ http_interactions: body: encoding: UTF-8 string: '{"links":[],"searchResults":[],"template":"https://xwiki.local/rest/?q={solrquery}(&number={number})(&start={start})(&orderField={fieldname}(&order={asc|desc}))(&distinct=1)(&prettyNames={false|true})(&wikis={wikis})(&className={classname})"}' - recorded_at: Tue, 02 Jun 2026 08:17:23 GMT + recorded_at: Fri, 05 Jun 2026 06:39:20 GMT recorded_with: VCR 6.4.0 diff --git a/spec/support/fixtures/vcr_cassettes/xwiki/query_partial_match.yml b/spec/support/fixtures/vcr_cassettes/xwiki/query_partial_match.yml index 86708b6d8f9..a78c9afd3d3 100644 --- a/spec/support/fixtures/vcr_cassettes/xwiki/query_partial_match.yml +++ b/spec/support/fixtures/vcr_cassettes/xwiki/query_partial_match.yml @@ -27,11 +27,11 @@ http_interactions: Content-Type: - application/json;charset=UTF-8 Date: - - Tue, 02 Jun 2026 08:17:22 GMT + - Fri, 05 Jun 2026 06:39:19 GMT Set-Cookie: - - JSESSIONID=4570EBB986F92482503F494102024098; Path=/; HttpOnly + - JSESSIONID=689FB3235B4E5A8C46683A1331BD9EB2; Path=/; HttpOnly Xwiki-Form-Token: - - 2XZUUfWArYhRgLYx4nHjhQ + - ON8xsHlEpixyujzpUPNupg Xwiki-User: - xwiki:XWiki.admin Xwiki-Version: @@ -42,14 +42,14 @@ http_interactions: encoding: UTF-8 string: '{"links":[],"searchResults":[{"links":[{"href":"https://xwiki.local/rest/wikis/xwiki/spaces/Test%20Page/pages/WebHome","rel":"http://www.xwiki.org/rel/page","type":null,"hrefLang":null}],"type":"page","id":"xwiki:Test Page.WebHome","pageFullName":"Test Page.WebHome","title":"Test Page for RSpec","wiki":"xwiki","space":"Test - Page","pageName":"WebHome","modified":1780386902000,"author":"xwiki:XWiki.admin","authorName":null,"version":"4.1","language":null,"className":null,"objectNumber":null,"filename":null,"score":14.608791,"object":null,"hierarchy":null}],"template":"https://xwiki.local/rest/?q={solrquery}(&number={number})(&start={start})(&orderField={fieldname}(&order={asc|desc}))(&distinct=1)(&prettyNames={false|true})(&wikis={wikis})(&className={classname})"}' - recorded_at: Tue, 02 Jun 2026 08:17:22 GMT + Page","pageName":"WebHome","modified":1780386902000,"author":"xwiki:XWiki.admin","authorName":null,"version":"4.1","language":null,"className":null,"objectNumber":null,"filename":null,"score":14.085169,"object":null,"hierarchy":null}],"template":"https://xwiki.local/rest/?q={solrquery}(&number={number})(&start={start})(&orderField={fieldname}(&order={asc|desc}))(&distinct=1)(&prettyNames={false|true})(&wikis={wikis})(&className={classname})"}' + recorded_at: Fri, 05 Jun 2026 06:39:19 GMT - request: - method: get - uri: https://xwiki.local/rest/wikis/xwiki/spaces/Test%20Page/pages/WebHome + method: put + uri: https://xwiki.local/rest/openproject/documents?docRef=xwiki:Test%20Page.WebHome body: - encoding: US-ASCII - string: '' + encoding: UTF-8 + string: "{}" headers: User-Agent: - OpenProject 17.6.0 HTTPX Client @@ -57,12 +57,16 @@ http_interactions: - application/json Accept-Encoding: - gzip, deflate + Content-Type: + - application/json + Content-Length: + - '2' Authorization: - Bearer response: status: - code: 200 - message: OK + code: 202 + message: Accepted headers: Content-Language: - en @@ -71,24 +75,24 @@ http_interactions: Content-Type: - application/json;charset=UTF-8 Date: - - Tue, 02 Jun 2026 08:17:22 GMT + - Fri, 05 Jun 2026 06:39:19 GMT Set-Cookie: - - JSESSIONID=36828A84C85C858E144AA581B1A1F138; Path=/; HttpOnly + - JSESSIONID=41BB94B7774F3AAF5872EC50FF78C37B; Path=/; HttpOnly Xwiki-Form-Token: - - 2XZUUfWArYhRgLYx4nHjhQ + - ON8xsHlEpixyujzpUPNupg Xwiki-User: - xwiki:XWiki.admin Xwiki-Version: - 18.3.0 Content-Length: - - '2224' + - '2372' body: encoding: UTF-8 - string: '{"links":[{"href":"https://xwiki.local/rest/wikis/xwiki/spaces/Test%20Page","rel":"http://www.xwiki.org/rel/space","type":null,"hrefLang":null},{"href":"https://xwiki.local/rest/wikis/xwiki/spaces/Test%20Page/pages/WebHome","rel":"http://www.xwiki.org/rel/parent","type":null,"hrefLang":null},{"href":"https://xwiki.local/rest/wikis/xwiki/spaces/Test%20Page/pages/WebHome/history","rel":"http://www.xwiki.org/rel/history","type":null,"hrefLang":null},{"href":"https://xwiki.local/rest/syntaxes","rel":"http://www.xwiki.org/rel/syntaxes","type":null,"hrefLang":null},{"href":"https://xwiki.local/rest/wikis/xwiki/spaces/Test%20Page/pages/WebHome","rel":"self","type":null,"hrefLang":null},{"href":"https://xwiki.local/rest/wikis/xwiki/classes/Test%20Page.WebHome","rel":"http://www.xwiki.org/rel/class","type":null,"hrefLang":null}],"id":"xwiki:Test - Page.WebHome","fullName":"Test Page.WebHome","wiki":"xwiki","space":"Test - Page","name":"WebHome","title":"Test Page for RSpec","rawTitle":"Test Page - for RSpec","parent":"Main.WebHome","parentId":"xwiki:Main.WebHome","version":"4.1","author":"XWiki.admin","authorName":null,"xwikiRelativeUrl":"https://xwiki.local/bin/view/Test%20Page/","xwikiAbsoluteUrl":"https://xwiki.local/bin/view/Test%20Page/","translations":{"links":[],"translations":[],"default":"en"},"syntax":"xwiki/2.1","language":"","majorVersion":4,"minorVersion":1,"hidden":false,"enforceRequiredRights":false,"created":1780383689000,"creator":"XWiki.admin","creatorName":null,"modified":1780386902000,"modifier":"XWiki.admin","modifierName":null,"originalMetadataAuthor":"xwiki:XWiki.admin","originalMetadataAuthorName":null,"comment":"","content":"This - is a test page that I created with my own hands.","clazz":null,"objects":null,"attachments":null,"hierarchy":{"items":[{"label":"xwiki","name":"xwiki","type":"wiki","url":"https://xwiki.local/bin/view/Main/"},{"label":"Test + string: '{"links":[{"href":"https://xwiki.local/rest/wikis/xwiki/spaces/Test%20Page","rel":"http://www.xwiki.org/rel/space","type":null,"hrefLang":null},{"href":"https://xwiki.local/rest/wikis/xwiki/spaces/Test%20Page/pages/WebHome","rel":"http://www.xwiki.org/rel/parent","type":null,"hrefLang":null},{"href":"https://xwiki.local/rest/wikis/xwiki/spaces/Test%20Page/pages/WebHome/history","rel":"http://www.xwiki.org/rel/history","type":null,"hrefLang":null},{"href":"https://xwiki.local/rest/wikis/xwiki/spaces/Test%20Page/pages/WebHome/objects","rel":"http://www.xwiki.org/rel/objects","type":null,"hrefLang":null},{"href":"https://xwiki.local/rest/syntaxes","rel":"http://www.xwiki.org/rel/syntaxes","type":null,"hrefLang":null},{"href":"https://xwiki.local/rest/openproject/documents","rel":"self","type":null,"hrefLang":null},{"href":"https://xwiki.local/rest/wikis/xwiki/classes/Test%20Page.WebHome","rel":"http://www.xwiki.org/rel/class","type":null,"hrefLang":null}],"id":"d70f1","fullName":"Test + Page.WebHome","wiki":"xwiki","space":"Test Page","name":"WebHome","title":"Test + Page for RSpec","rawTitle":"Test Page for RSpec","parent":"Main.WebHome","parentId":"xwiki:Main.WebHome","version":"4.1","author":"XWiki.admin","authorName":null,"xwikiRelativeUrl":"https://xwiki.local/bin/view/Test%20Page/","xwikiAbsoluteUrl":"https://xwiki.local/bin/view/Test%20Page/","translations":{"links":[],"translations":[],"default":"en"},"syntax":"xwiki/2.1","language":"","majorVersion":4,"minorVersion":1,"hidden":false,"enforceRequiredRights":false,"created":1780383689000,"creator":"XWiki.admin","creatorName":null,"modified":1780386902000,"modifier":"XWiki.admin","modifierName":null,"originalMetadataAuthor":"xwiki:XWiki.admin","originalMetadataAuthorName":null,"comment":"Created + URL Shortener.","content":"This is a test page that I created with my own + hands.","clazz":null,"objects":null,"attachments":null,"hierarchy":{"items":[{"label":"xwiki","name":"xwiki","type":"wiki","url":"https://xwiki.local/bin/view/Main/"},{"label":"Test Page","name":"Test Page","type":"space","url":"https://xwiki.local/bin/view/Test%20Page/"},{"label":"WebHome","name":"WebHome","type":"document","url":"https://xwiki.local/bin/view/Test%20Page/"}]},"rights":[],"renderedContent":null}' - recorded_at: Tue, 02 Jun 2026 08:17:22 GMT + recorded_at: Fri, 05 Jun 2026 06:39:19 GMT recorded_with: VCR 6.4.0 diff --git a/spec/support/fixtures/vcr_cassettes/xwiki/query_quoted_match.yml b/spec/support/fixtures/vcr_cassettes/xwiki/query_quoted_match.yml index bc3063416a4..b1238e1edde 100644 --- a/spec/support/fixtures/vcr_cassettes/xwiki/query_quoted_match.yml +++ b/spec/support/fixtures/vcr_cassettes/xwiki/query_quoted_match.yml @@ -27,11 +27,11 @@ http_interactions: Content-Type: - application/json;charset=UTF-8 Date: - - Tue, 02 Jun 2026 08:17:22 GMT + - Fri, 05 Jun 2026 06:39:20 GMT Set-Cookie: - - JSESSIONID=C28E0999BF663CA702569EE1C5C696E2; Path=/; HttpOnly + - JSESSIONID=A1B5B0EFF5FD5E7B4F6E4CB0D185B065; Path=/; HttpOnly Xwiki-Form-Token: - - 2XZUUfWArYhRgLYx4nHjhQ + - ON8xsHlEpixyujzpUPNupg Xwiki-User: - xwiki:XWiki.admin Xwiki-Version: @@ -42,14 +42,14 @@ http_interactions: encoding: UTF-8 string: '{"links":[],"searchResults":[{"links":[{"href":"https://xwiki.local/rest/wikis/xwiki/spaces/%22Quoted%22%20pages%20can%20be%20tricky/pages/WebHome","rel":"http://www.xwiki.org/rel/page","type":null,"hrefLang":null}],"type":"page","id":"xwiki:\"Quoted\" pages can be tricky.WebHome","pageFullName":"\"Quoted\" pages can be tricky.WebHome","title":"\"Quoted\" - pages can be tricky","wiki":"xwiki","space":"\"Quoted\" pages can be tricky","pageName":"WebHome","modified":1780387197000,"author":"xwiki:XWiki.admin","authorName":null,"version":"1.1","language":null,"className":null,"objectNumber":null,"filename":null,"score":42.605682,"object":null,"hierarchy":null}],"template":"https://xwiki.local/rest/?q={solrquery}(&number={number})(&start={start})(&orderField={fieldname}(&order={asc|desc}))(&distinct=1)(&prettyNames={false|true})(&wikis={wikis})(&className={classname})"}' - recorded_at: Tue, 02 Jun 2026 08:17:22 GMT + pages can be tricky","wiki":"xwiki","space":"\"Quoted\" pages can be tricky","pageName":"WebHome","modified":1780387197000,"author":"xwiki:XWiki.admin","authorName":null,"version":"1.1","language":null,"className":null,"objectNumber":null,"filename":null,"score":41.692856,"object":null,"hierarchy":null}],"template":"https://xwiki.local/rest/?q={solrquery}(&number={number})(&start={start})(&orderField={fieldname}(&order={asc|desc}))(&distinct=1)(&prettyNames={false|true})(&wikis={wikis})(&className={classname})"}' + recorded_at: Fri, 05 Jun 2026 06:39:20 GMT - request: - method: get - uri: https://xwiki.local/rest/wikis/xwiki/spaces/%22Quoted%22%20pages%20can%20be%20tricky/pages/WebHome + method: put + uri: https://xwiki.local/rest/openproject/documents?docRef=xwiki:%22Quoted%22%20pages%20can%20be%20tricky.WebHome body: - encoding: US-ASCII - string: '' + encoding: UTF-8 + string: "{}" headers: User-Agent: - OpenProject 17.6.0 HTTPX Client @@ -57,12 +57,16 @@ http_interactions: - application/json Accept-Encoding: - gzip, deflate + Content-Type: + - application/json + Content-Length: + - '2' Authorization: - Bearer response: status: - code: 200 - message: OK + code: 202 + message: Accepted headers: Content-Language: - en @@ -71,24 +75,25 @@ http_interactions: Content-Type: - application/json;charset=UTF-8 Date: - - Tue, 02 Jun 2026 08:17:22 GMT + - Fri, 05 Jun 2026 06:39:20 GMT Set-Cookie: - - JSESSIONID=EC142E0079C91196143B051273FDA2FD; Path=/; HttpOnly + - JSESSIONID=9F577E6A3744F626EDDD3668B5F9EE9D; Path=/; HttpOnly Xwiki-Form-Token: - - 2XZUUfWArYhRgLYx4nHjhQ + - ON8xsHlEpixyujzpUPNupg Xwiki-User: - xwiki:XWiki.admin Xwiki-Version: - 18.3.0 Content-Length: - - '2642' + - '2769' body: encoding: UTF-8 - string: '{"links":[{"href":"https://xwiki.local/rest/wikis/xwiki/spaces/%22Quoted%22%20pages%20can%20be%20tricky","rel":"http://www.xwiki.org/rel/space","type":null,"hrefLang":null},{"href":"https://xwiki.local/rest/wikis/xwiki/spaces/%22Quoted%22%20pages%20can%20be%20tricky/pages/WebHome","rel":"http://www.xwiki.org/rel/parent","type":null,"hrefLang":null},{"href":"https://xwiki.local/rest/wikis/xwiki/spaces/%22Quoted%22%20pages%20can%20be%20tricky/pages/WebHome/history","rel":"http://www.xwiki.org/rel/history","type":null,"hrefLang":null},{"href":"https://xwiki.local/rest/syntaxes","rel":"http://www.xwiki.org/rel/syntaxes","type":null,"hrefLang":null},{"href":"https://xwiki.local/rest/wikis/xwiki/spaces/%22Quoted%22%20pages%20can%20be%20tricky/pages/WebHome","rel":"self","type":null,"hrefLang":null},{"href":"https://xwiki.local/rest/wikis/xwiki/classes/%22Quoted%22%20pages%20can%20be%20tricky.WebHome","rel":"http://www.xwiki.org/rel/class","type":null,"hrefLang":null}],"id":"xwiki:\"Quoted\" - pages can be tricky.WebHome","fullName":"\"Quoted\" pages can be tricky.WebHome","wiki":"xwiki","space":"\"Quoted\" - pages can be tricky","name":"WebHome","title":"\"Quoted\" pages can be tricky","rawTitle":"\"Quoted\" - pages can be tricky","parent":"Main.WebHome","parentId":"xwiki:Main.WebHome","version":"1.1","author":"XWiki.admin","authorName":null,"xwikiRelativeUrl":"https://xwiki.local/bin/view/%22Quoted%22%20pages%20can%20be%20tricky/","xwikiAbsoluteUrl":"https://xwiki.local/bin/view/%22Quoted%22%20pages%20can%20be%20tricky/","translations":{"links":[],"translations":[],"default":"en"},"syntax":"xwiki/2.1","language":"","majorVersion":1,"minorVersion":1,"hidden":false,"enforceRequiredRights":false,"created":1780387197000,"creator":"XWiki.admin","creatorName":null,"modified":1780387197000,"modifier":"XWiki.admin","modifierName":null,"originalMetadataAuthor":"xwiki:XWiki.admin","originalMetadataAuthorName":null,"comment":"","content":"When - the page title contains quotes, it''s harder to exactly match their page title.","clazz":null,"objects":null,"attachments":null,"hierarchy":{"items":[{"label":"xwiki","name":"xwiki","type":"wiki","url":"https://xwiki.local/bin/view/Main/"},{"label":"\"Quoted\" + string: '{"links":[{"href":"https://xwiki.local/rest/wikis/xwiki/spaces/%22Quoted%22%20pages%20can%20be%20tricky","rel":"http://www.xwiki.org/rel/space","type":null,"hrefLang":null},{"href":"https://xwiki.local/rest/wikis/xwiki/spaces/%22Quoted%22%20pages%20can%20be%20tricky/pages/WebHome","rel":"http://www.xwiki.org/rel/parent","type":null,"hrefLang":null},{"href":"https://xwiki.local/rest/wikis/xwiki/spaces/%22Quoted%22%20pages%20can%20be%20tricky/pages/WebHome/history","rel":"http://www.xwiki.org/rel/history","type":null,"hrefLang":null},{"href":"https://xwiki.local/rest/wikis/xwiki/spaces/%22Quoted%22%20pages%20can%20be%20tricky/pages/WebHome/objects","rel":"http://www.xwiki.org/rel/objects","type":null,"hrefLang":null},{"href":"https://xwiki.local/rest/syntaxes","rel":"http://www.xwiki.org/rel/syntaxes","type":null,"hrefLang":null},{"href":"https://xwiki.local/rest/openproject/documents","rel":"self","type":null,"hrefLang":null},{"href":"https://xwiki.local/rest/wikis/xwiki/classes/%22Quoted%22%20pages%20can%20be%20tricky.WebHome","rel":"http://www.xwiki.org/rel/class","type":null,"hrefLang":null}],"id":"1a013","fullName":"\"Quoted\" + pages can be tricky.WebHome","wiki":"xwiki","space":"\"Quoted\" pages can + be tricky","name":"WebHome","title":"\"Quoted\" pages can be tricky","rawTitle":"\"Quoted\" + pages can be tricky","parent":"Main.WebHome","parentId":"xwiki:Main.WebHome","version":"1.1","author":"XWiki.admin","authorName":null,"xwikiRelativeUrl":"https://xwiki.local/bin/view/%22Quoted%22%20pages%20can%20be%20tricky/","xwikiAbsoluteUrl":"https://xwiki.local/bin/view/%22Quoted%22%20pages%20can%20be%20tricky/","translations":{"links":[],"translations":[],"default":"en"},"syntax":"xwiki/2.1","language":"","majorVersion":1,"minorVersion":1,"hidden":false,"enforceRequiredRights":false,"created":1780387197000,"creator":"XWiki.admin","creatorName":null,"modified":1780387197000,"modifier":"XWiki.admin","modifierName":null,"originalMetadataAuthor":"xwiki:XWiki.admin","originalMetadataAuthorName":null,"comment":"Created + URL Shortener.","content":"When the page title contains quotes, it''s harder + to exactly match their page title.","clazz":null,"objects":null,"attachments":null,"hierarchy":{"items":[{"label":"xwiki","name":"xwiki","type":"wiki","url":"https://xwiki.local/bin/view/Main/"},{"label":"\"Quoted\" pages can be tricky","name":"\"Quoted\" pages can be tricky","type":"space","url":"https://xwiki.local/bin/view/%22Quoted%22%20pages%20can%20be%20tricky/"},{"label":"WebHome","name":"WebHome","type":"document","url":"https://xwiki.local/bin/view/%22Quoted%22%20pages%20can%20be%20tricky/"}]},"rights":[],"renderedContent":null}' - recorded_at: Tue, 02 Jun 2026 08:17:22 GMT + recorded_at: Fri, 05 Jun 2026 06:39:20 GMT recorded_with: VCR 6.4.0 diff --git a/spec/support/fixtures/vcr_cassettes/xwiki/query_unquoted_match.yml b/spec/support/fixtures/vcr_cassettes/xwiki/query_unquoted_match.yml index db53a2fc824..c46c68fc370 100644 --- a/spec/support/fixtures/vcr_cassettes/xwiki/query_unquoted_match.yml +++ b/spec/support/fixtures/vcr_cassettes/xwiki/query_unquoted_match.yml @@ -27,11 +27,11 @@ http_interactions: Content-Type: - application/json;charset=UTF-8 Date: - - Tue, 02 Jun 2026 08:17:23 GMT + - Fri, 05 Jun 2026 06:39:20 GMT Set-Cookie: - - JSESSIONID=10D557C0A4C7D3C599B80C2FA01F5FF5; Path=/; HttpOnly + - JSESSIONID=B47446E1E06E6D2A73FC512CEAB8083D; Path=/; HttpOnly Xwiki-Form-Token: - - 2XZUUfWArYhRgLYx4nHjhQ + - ON8xsHlEpixyujzpUPNupg Xwiki-User: - xwiki:XWiki.admin Xwiki-Version: @@ -42,14 +42,14 @@ http_interactions: encoding: UTF-8 string: '{"links":[],"searchResults":[{"links":[{"href":"https://xwiki.local/rest/wikis/xwiki/spaces/%22Quoted%22%20pages%20can%20be%20tricky/pages/WebHome","rel":"http://www.xwiki.org/rel/page","type":null,"hrefLang":null}],"type":"page","id":"xwiki:\"Quoted\" pages can be tricky.WebHome","pageFullName":"\"Quoted\" pages can be tricky.WebHome","title":"\"Quoted\" - pages can be tricky","wiki":"xwiki","space":"\"Quoted\" pages can be tricky","pageName":"WebHome","modified":1780387197000,"author":"xwiki:XWiki.admin","authorName":null,"version":"1.1","language":null,"className":null,"objectNumber":null,"filename":null,"score":42.605682,"object":null,"hierarchy":null}],"template":"https://xwiki.local/rest/?q={solrquery}(&number={number})(&start={start})(&orderField={fieldname}(&order={asc|desc}))(&distinct=1)(&prettyNames={false|true})(&wikis={wikis})(&className={classname})"}' - recorded_at: Tue, 02 Jun 2026 08:17:23 GMT + pages can be tricky","wiki":"xwiki","space":"\"Quoted\" pages can be tricky","pageName":"WebHome","modified":1780387197000,"author":"xwiki:XWiki.admin","authorName":null,"version":"1.1","language":null,"className":null,"objectNumber":null,"filename":null,"score":41.692856,"object":null,"hierarchy":null}],"template":"https://xwiki.local/rest/?q={solrquery}(&number={number})(&start={start})(&orderField={fieldname}(&order={asc|desc}))(&distinct=1)(&prettyNames={false|true})(&wikis={wikis})(&className={classname})"}' + recorded_at: Fri, 05 Jun 2026 06:39:20 GMT - request: - method: get - uri: https://xwiki.local/rest/wikis/xwiki/spaces/%22Quoted%22%20pages%20can%20be%20tricky/pages/WebHome + method: put + uri: https://xwiki.local/rest/openproject/documents?docRef=xwiki:%22Quoted%22%20pages%20can%20be%20tricky.WebHome body: - encoding: US-ASCII - string: '' + encoding: UTF-8 + string: "{}" headers: User-Agent: - OpenProject 17.6.0 HTTPX Client @@ -57,12 +57,16 @@ http_interactions: - application/json Accept-Encoding: - gzip, deflate + Content-Type: + - application/json + Content-Length: + - '2' Authorization: - Bearer response: status: - code: 200 - message: OK + code: 202 + message: Accepted headers: Content-Language: - en @@ -71,24 +75,25 @@ http_interactions: Content-Type: - application/json;charset=UTF-8 Date: - - Tue, 02 Jun 2026 08:17:23 GMT + - Fri, 05 Jun 2026 06:39:20 GMT Set-Cookie: - - JSESSIONID=85112D2673FA7F3B99AEC6BF0A182372; Path=/; HttpOnly + - JSESSIONID=2B1297828F8D8887496627F7356421D5; Path=/; HttpOnly Xwiki-Form-Token: - - 2XZUUfWArYhRgLYx4nHjhQ + - ON8xsHlEpixyujzpUPNupg Xwiki-User: - xwiki:XWiki.admin Xwiki-Version: - 18.3.0 Content-Length: - - '2642' + - '2769' body: encoding: UTF-8 - string: '{"links":[{"href":"https://xwiki.local/rest/wikis/xwiki/spaces/%22Quoted%22%20pages%20can%20be%20tricky","rel":"http://www.xwiki.org/rel/space","type":null,"hrefLang":null},{"href":"https://xwiki.local/rest/wikis/xwiki/spaces/%22Quoted%22%20pages%20can%20be%20tricky/pages/WebHome","rel":"http://www.xwiki.org/rel/parent","type":null,"hrefLang":null},{"href":"https://xwiki.local/rest/wikis/xwiki/spaces/%22Quoted%22%20pages%20can%20be%20tricky/pages/WebHome/history","rel":"http://www.xwiki.org/rel/history","type":null,"hrefLang":null},{"href":"https://xwiki.local/rest/syntaxes","rel":"http://www.xwiki.org/rel/syntaxes","type":null,"hrefLang":null},{"href":"https://xwiki.local/rest/wikis/xwiki/spaces/%22Quoted%22%20pages%20can%20be%20tricky/pages/WebHome","rel":"self","type":null,"hrefLang":null},{"href":"https://xwiki.local/rest/wikis/xwiki/classes/%22Quoted%22%20pages%20can%20be%20tricky.WebHome","rel":"http://www.xwiki.org/rel/class","type":null,"hrefLang":null}],"id":"xwiki:\"Quoted\" - pages can be tricky.WebHome","fullName":"\"Quoted\" pages can be tricky.WebHome","wiki":"xwiki","space":"\"Quoted\" - pages can be tricky","name":"WebHome","title":"\"Quoted\" pages can be tricky","rawTitle":"\"Quoted\" - pages can be tricky","parent":"Main.WebHome","parentId":"xwiki:Main.WebHome","version":"1.1","author":"XWiki.admin","authorName":null,"xwikiRelativeUrl":"https://xwiki.local/bin/view/%22Quoted%22%20pages%20can%20be%20tricky/","xwikiAbsoluteUrl":"https://xwiki.local/bin/view/%22Quoted%22%20pages%20can%20be%20tricky/","translations":{"links":[],"translations":[],"default":"en"},"syntax":"xwiki/2.1","language":"","majorVersion":1,"minorVersion":1,"hidden":false,"enforceRequiredRights":false,"created":1780387197000,"creator":"XWiki.admin","creatorName":null,"modified":1780387197000,"modifier":"XWiki.admin","modifierName":null,"originalMetadataAuthor":"xwiki:XWiki.admin","originalMetadataAuthorName":null,"comment":"","content":"When - the page title contains quotes, it''s harder to exactly match their page title.","clazz":null,"objects":null,"attachments":null,"hierarchy":{"items":[{"label":"xwiki","name":"xwiki","type":"wiki","url":"https://xwiki.local/bin/view/Main/"},{"label":"\"Quoted\" + string: '{"links":[{"href":"https://xwiki.local/rest/wikis/xwiki/spaces/%22Quoted%22%20pages%20can%20be%20tricky","rel":"http://www.xwiki.org/rel/space","type":null,"hrefLang":null},{"href":"https://xwiki.local/rest/wikis/xwiki/spaces/%22Quoted%22%20pages%20can%20be%20tricky/pages/WebHome","rel":"http://www.xwiki.org/rel/parent","type":null,"hrefLang":null},{"href":"https://xwiki.local/rest/wikis/xwiki/spaces/%22Quoted%22%20pages%20can%20be%20tricky/pages/WebHome/history","rel":"http://www.xwiki.org/rel/history","type":null,"hrefLang":null},{"href":"https://xwiki.local/rest/wikis/xwiki/spaces/%22Quoted%22%20pages%20can%20be%20tricky/pages/WebHome/objects","rel":"http://www.xwiki.org/rel/objects","type":null,"hrefLang":null},{"href":"https://xwiki.local/rest/syntaxes","rel":"http://www.xwiki.org/rel/syntaxes","type":null,"hrefLang":null},{"href":"https://xwiki.local/rest/openproject/documents","rel":"self","type":null,"hrefLang":null},{"href":"https://xwiki.local/rest/wikis/xwiki/classes/%22Quoted%22%20pages%20can%20be%20tricky.WebHome","rel":"http://www.xwiki.org/rel/class","type":null,"hrefLang":null}],"id":"1a013","fullName":"\"Quoted\" + pages can be tricky.WebHome","wiki":"xwiki","space":"\"Quoted\" pages can + be tricky","name":"WebHome","title":"\"Quoted\" pages can be tricky","rawTitle":"\"Quoted\" + pages can be tricky","parent":"Main.WebHome","parentId":"xwiki:Main.WebHome","version":"1.1","author":"XWiki.admin","authorName":null,"xwikiRelativeUrl":"https://xwiki.local/bin/view/%22Quoted%22%20pages%20can%20be%20tricky/","xwikiAbsoluteUrl":"https://xwiki.local/bin/view/%22Quoted%22%20pages%20can%20be%20tricky/","translations":{"links":[],"translations":[],"default":"en"},"syntax":"xwiki/2.1","language":"","majorVersion":1,"minorVersion":1,"hidden":false,"enforceRequiredRights":false,"created":1780387197000,"creator":"XWiki.admin","creatorName":null,"modified":1780387197000,"modifier":"XWiki.admin","modifierName":null,"originalMetadataAuthor":"xwiki:XWiki.admin","originalMetadataAuthorName":null,"comment":"Created + URL Shortener.","content":"When the page title contains quotes, it''s harder + to exactly match their page title.","clazz":null,"objects":null,"attachments":null,"hierarchy":{"items":[{"label":"xwiki","name":"xwiki","type":"wiki","url":"https://xwiki.local/bin/view/Main/"},{"label":"\"Quoted\" pages can be tricky","name":"\"Quoted\" pages can be tricky","type":"space","url":"https://xwiki.local/bin/view/%22Quoted%22%20pages%20can%20be%20tricky/"},{"label":"WebHome","name":"WebHome","type":"document","url":"https://xwiki.local/bin/view/%22Quoted%22%20pages%20can%20be%20tricky/"}]},"rights":[],"renderedContent":null}' - recorded_at: Tue, 02 Jun 2026 08:17:23 GMT + recorded_at: Fri, 05 Jun 2026 06:39:20 GMT recorded_with: VCR 6.4.0 diff --git a/spec/support/fixtures/vcr_cassettes/xwiki/stable_page_info.yml b/spec/support/fixtures/vcr_cassettes/xwiki/stable_page_info.yml new file mode 100644 index 00000000000..0d7cd62208a --- /dev/null +++ b/spec/support/fixtures/vcr_cassettes/xwiki/stable_page_info.yml @@ -0,0 +1,50 @@ +--- +http_interactions: +- request: + method: get + uri: https://xwiki.local/rest/openproject/documents/d70f1 + body: + encoding: US-ASCII + string: '' + headers: + User-Agent: + - OpenProject 17.6.0 HTTPX Client + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Authorization: + - Bearer + response: + status: + code: 200 + message: OK + headers: + Content-Language: + - en + Content-Script-Type: + - text/javascript + Content-Type: + - application/json;charset=UTF-8 + Date: + - Fri, 05 Jun 2026 06:33:33 GMT + Set-Cookie: + - JSESSIONID=20FFAE29A62BFE6CEC0152BB7FC0ADB6; Path=/; HttpOnly + Xwiki-Form-Token: + - ON8xsHlEpixyujzpUPNupg + Xwiki-User: + - xwiki:XWiki.admin + Xwiki-Version: + - 18.3.0 + Content-Length: + - '2378' + body: + encoding: UTF-8 + string: '{"links":[{"href":"https://xwiki.local/rest/wikis/xwiki/spaces/Test%20Page","rel":"http://www.xwiki.org/rel/space","type":null,"hrefLang":null},{"href":"https://xwiki.local/rest/wikis/xwiki/spaces/Test%20Page/pages/WebHome","rel":"http://www.xwiki.org/rel/parent","type":null,"hrefLang":null},{"href":"https://xwiki.local/rest/wikis/xwiki/spaces/Test%20Page/pages/WebHome/history","rel":"http://www.xwiki.org/rel/history","type":null,"hrefLang":null},{"href":"https://xwiki.local/rest/wikis/xwiki/spaces/Test%20Page/pages/WebHome/objects","rel":"http://www.xwiki.org/rel/objects","type":null,"hrefLang":null},{"href":"https://xwiki.local/rest/syntaxes","rel":"http://www.xwiki.org/rel/syntaxes","type":null,"hrefLang":null},{"href":"https://xwiki.local/rest/openproject/documents/d70f1","rel":"self","type":null,"hrefLang":null},{"href":"https://xwiki.local/rest/wikis/xwiki/classes/Test%20Page.WebHome","rel":"http://www.xwiki.org/rel/class","type":null,"hrefLang":null}],"id":"d70f1","fullName":"Test + Page.WebHome","wiki":"xwiki","space":"Test Page","name":"WebHome","title":"Test + Page for RSpec","rawTitle":"Test Page for RSpec","parent":"Main.WebHome","parentId":"xwiki:Main.WebHome","version":"4.1","author":"XWiki.admin","authorName":null,"xwikiRelativeUrl":"https://xwiki.local/bin/view/Test%20Page/","xwikiAbsoluteUrl":"https://xwiki.local/bin/view/Test%20Page/","translations":{"links":[],"translations":[],"default":"en"},"syntax":"xwiki/2.1","language":"","majorVersion":4,"minorVersion":1,"hidden":false,"enforceRequiredRights":false,"created":1780383689000,"creator":"XWiki.admin","creatorName":null,"modified":1780386902000,"modifier":"XWiki.admin","modifierName":null,"originalMetadataAuthor":"xwiki:XWiki.admin","originalMetadataAuthorName":null,"comment":"Created + URL Shortener.","content":"This is a test page that I created with my own + hands.","clazz":null,"objects":null,"attachments":null,"hierarchy":{"items":[{"label":"xwiki","name":"xwiki","type":"wiki","url":"https://xwiki.local/bin/view/Main/"},{"label":"Test + Page","name":"Test Page","type":"space","url":"https://xwiki.local/bin/view/Test%20Page/"},{"label":"WebHome","name":"WebHome","type":"document","url":"https://xwiki.local/bin/view/Test%20Page/"}]},"rights":[],"renderedContent":null}' + recorded_at: Fri, 05 Jun 2026 06:33:33 GMT +recorded_with: VCR 6.4.0