mirror of
https://github.com/opf/openproject.git
synced 2026-06-13 19:20:00 +00:00
Create page command and service
Wiring up actual page creation to the dialog that has been prepared beforehand. The commands are merely responsible for creating pages in the corresponding wiki provider. The new CreateLinkedPageService takes care of combining the two steps needed by the UI: 1. Creating the page 2. Linking it
This commit is contained in:
@@ -0,0 +1,50 @@
|
||||
# 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.
|
||||
#++
|
||||
|
||||
# Allows to use the service as a source for ActiveModel::Errors, i.e.
|
||||
#
|
||||
# ActiveModel::Errors.new(self)
|
||||
#
|
||||
# It adds neccessary translation and naming helpers to the service.
|
||||
module ServiceAsErrorSource
|
||||
def self.included(base)
|
||||
base.extend ActiveModel::Naming
|
||||
base.extend ActiveModel::Translation
|
||||
base.extend ClassMethods
|
||||
end
|
||||
|
||||
module ClassMethods
|
||||
def i18n_scope = "services"
|
||||
|
||||
def model_name = ActiveModel::Name.new(self)
|
||||
end
|
||||
|
||||
def read_attribute_for_validation(attr) = attr
|
||||
end
|
||||
@@ -0,0 +1,45 @@
|
||||
# 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 CreatePageContract < DryApplicationContract
|
||||
params do
|
||||
required(:title).filled(:string)
|
||||
|
||||
# TODO: This only works for pages as parents right now, we'll need to change some things around to support
|
||||
# creating "root" pages that are direct children of a wiki. E.g. right now there is no data type to represent a wiki
|
||||
required(:parent_identifier).filled(:string)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,49 @@
|
||||
# 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 Concerns
|
||||
module LinkableRedirect
|
||||
def turbo_redirect_for_linkable(linkable)
|
||||
path = derive_path_from_linkable(linkable)
|
||||
return redirect_to path, status: :see_other if path
|
||||
|
||||
head :no_content
|
||||
end
|
||||
|
||||
def derive_path_from_linkable(linkable)
|
||||
case linkable
|
||||
when WorkPackage
|
||||
project_work_package_wikis_tab_index_path(work_package_id: linkable.id, project_id: linkable.project_id)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -30,6 +30,7 @@
|
||||
|
||||
module Wikis
|
||||
class PagesController < ApplicationController
|
||||
include Concerns::LinkableRedirect
|
||||
include OpTurbo::ComponentStream
|
||||
include Dry::Monads[:result]
|
||||
|
||||
@@ -39,12 +40,23 @@ module Wikis
|
||||
# the permissions set in each wiki.
|
||||
no_authorization_required! :search
|
||||
|
||||
def create_and_link
|
||||
# TODO: implement service to create page and link
|
||||
render_error_flash_message_via_turbo_stream(
|
||||
message: "Not implemented yet. Trying to create a new page with #{create_new_page_params.to_h}"
|
||||
)
|
||||
respond_to_with_turbo_streams
|
||||
def create_and_link # rubocop:disable Metrics/AbcSize
|
||||
provider = Provider.visible.find(create_new_page_params[:provider_id])
|
||||
result = CreateLinkedPageService.new(provider:, user: current_user)
|
||||
.call(
|
||||
title: create_new_page_params[:page_title],
|
||||
parent_identifier: create_new_page_params[:parent_page_identifier],
|
||||
linkable_type: create_new_page_params[:linkable_type],
|
||||
linkable_id: create_new_page_params[:linkable_id]
|
||||
)
|
||||
|
||||
if result.success?
|
||||
turbo_redirect_for_linkable(result.result.linkable)
|
||||
else
|
||||
message = result.errors.full_messages.join(" ")
|
||||
render_error_flash_message_via_turbo_stream(message:)
|
||||
respond_to_with_turbo_streams
|
||||
end
|
||||
end
|
||||
|
||||
def create_new_page_dialog
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
|
||||
module Wikis
|
||||
class RelationPageLinksController < ApplicationController
|
||||
include Concerns::LinkableRedirect
|
||||
include OpTurbo::ComponentStream
|
||||
|
||||
before_action :authorize
|
||||
@@ -88,19 +89,5 @@ module Wikis
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
def turbo_redirect_for_linkable(linkable)
|
||||
path = derive_path_from_linkable(linkable)
|
||||
return redirect_to path, status: :see_other if path
|
||||
|
||||
head :no_content
|
||||
end
|
||||
|
||||
def derive_path_from_linkable(linkable)
|
||||
case linkable
|
||||
when WorkPackage
|
||||
project_work_package_wikis_tab_index_path(work_package_id: linkable.id, project_id: linkable.project_id)
|
||||
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
|
||||
CreatePage = Data.define(:title, :parent_identifier) do
|
||||
private_class_method :new
|
||||
|
||||
def self.build(title:, parent_identifier:, contract: CreatePageContract.new)
|
||||
contract.call(title:, parent_identifier:).to_monad.fmap { new(**it.to_h) }
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,55 @@
|
||||
# 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
|
||||
class BaseCommand
|
||||
include Dry::Monads[:result]
|
||||
|
||||
attr_reader :provider
|
||||
|
||||
def initialize(model:)
|
||||
@provider = model
|
||||
end
|
||||
|
||||
def call(input_data:, auth_strategy:) # rubocop:disable Lint/UnusedMethodArgument
|
||||
raise SubclassResponsibilityError
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def success(result)
|
||||
Success(result)
|
||||
end
|
||||
|
||||
def failure(code:)
|
||||
Failure(Results::Error.new(source: self.class, code:))
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,74 @@
|
||||
# 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 Commands
|
||||
class CreatePage < BaseCommand
|
||||
def call(input_data:, auth_strategy:)
|
||||
Adapters::Authentication[auth_strategy].call do |user|
|
||||
parent = find_parent(input_data.parent_identifier, user:)
|
||||
return failure(code: :not_found) if parent.nil?
|
||||
|
||||
service_result_to_monad(
|
||||
WikiPages::CreateService.new(user:).call(
|
||||
title: input_data.title,
|
||||
parent:,
|
||||
wiki: parent.wiki
|
||||
)
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def find_parent(identifier, user:)
|
||||
WikiPage.visible(user).find_by(id: identifier)
|
||||
end
|
||||
|
||||
def service_result_to_monad(result)
|
||||
if result.success?
|
||||
success(Queries::PageInfo.wiki_page_to_page_info(result.result, provider:))
|
||||
elsif result.errors.details.values.flatten.any? { |e| e.fetch(:error) == :error_unauthorized }
|
||||
failure(code: :forbidden)
|
||||
else
|
||||
# for now simplifying to a single error code, since there is not really any
|
||||
# error case expected to crop up during real usage, due to previous validations in upstream code
|
||||
failure(code: :invalid)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -38,15 +38,7 @@ module Wikis
|
||||
end
|
||||
|
||||
namespace("commands") do
|
||||
# ...
|
||||
end
|
||||
|
||||
namespace("components") do
|
||||
# ...
|
||||
end
|
||||
|
||||
namespace("contracts") do
|
||||
# ...
|
||||
register(:create_page, Commands::CreatePage)
|
||||
end
|
||||
|
||||
namespace("queries") do
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
# 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 Commands
|
||||
class CreatePage < BaseCommand
|
||||
include Concerns::XWikiRequest
|
||||
|
||||
class << self
|
||||
# We have to manually derive a useful ID from the title that's both valid, but also makes for a nice XWiki URL
|
||||
def derive_page_id(title)
|
||||
title.gsub(/[\\.:]/, { "\\" => "\\\\", ":" => "\\:", "." => "\\." })
|
||||
end
|
||||
end
|
||||
|
||||
def call(input_data:, auth_strategy:)
|
||||
parent_result = fetch_canonical_parent(identifier: input_data.parent_identifier, auth_strategy:)
|
||||
parent_result.bind do |canonical_parent|
|
||||
identifier = "#{canonical_parent}.#{self.class.derive_page_id(input_data.title)}.WebHome"
|
||||
|
||||
create_page_request(identifier, title: input_data.title, auth_strategy:) do |data|
|
||||
success(Queries::StablePageInfo.json_to_page_info(data, provider:))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def fetch_canonical_parent(identifier:, auth_strategy:)
|
||||
ref = StablePageReference.parse(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("#{fetch_json(data, 'wiki')}:#{fetch_json(data, 'space')}")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def create_page_request(reference, title:, auth_strategy:, &)
|
||||
authenticated(auth_strategy) do |http|
|
||||
handle_response(
|
||||
http.with(headers: { "Content-Type": "application/json" })
|
||||
.put(rest_url("openproject/documents", query: { docRef: reference.to_s }), body: { title: }.to_json),
|
||||
&
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -38,7 +38,7 @@ module Wikis
|
||||
end
|
||||
|
||||
namespace("commands") do
|
||||
# ...
|
||||
register(:create_page, Commands::CreatePage)
|
||||
end
|
||||
|
||||
namespace("components") do
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
# 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
|
||||
class CreateLinkedPageService
|
||||
include ServiceAsErrorSource
|
||||
include Dry::Monads[:result]
|
||||
|
||||
attr_reader :provider, :user
|
||||
|
||||
def initialize(provider:, user:)
|
||||
@provider = provider
|
||||
@user = user
|
||||
end
|
||||
|
||||
def call(title:, parent_identifier:, linkable_type:, linkable_id:)
|
||||
dry_result = create_page(title:, parent_identifier:).bind do |page_info|
|
||||
link_page(identifier: page_info.identifier, linkable_type:, linkable_id:)
|
||||
end
|
||||
|
||||
dry_result.value_or do |error|
|
||||
ServiceResult.failure(errors: ActiveModel::Errors.new(self)).tap do |result|
|
||||
error_target = error.code == :missing_token ? :base : :wiki_page
|
||||
result.errors.add(error_target, error.code)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def create_page(title:, parent_identifier:)
|
||||
provider.auth_strategy_for(user).bind do |auth_strategy|
|
||||
Adapters::Input::CreatePage.build(title:, parent_identifier:).bind do |input_data|
|
||||
provider.resolve("commands.create_page").call(input_data:, auth_strategy:)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def link_page(identifier:, linkable_type:, linkable_id:)
|
||||
create_service = RelationPageLinks::CreateService.new(user:)
|
||||
Success(
|
||||
create_service.call(
|
||||
provider_id: provider.id,
|
||||
linkable_type:,
|
||||
linkable_id:,
|
||||
author_id: user.id,
|
||||
identifier:
|
||||
)
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -38,6 +38,16 @@ en:
|
||||
wikis: "Wikis"
|
||||
permission_manage_wiki_page_links: Manage Wiki Page Links
|
||||
project_module_wiki_platforms: Wiki providers
|
||||
services:
|
||||
attributes:
|
||||
wikis/create_linked_page_service:
|
||||
wiki_page: Wiki page
|
||||
errors:
|
||||
models:
|
||||
wikis/create_linked_page_service:
|
||||
forbidden: was not allowed to be created.
|
||||
not_found: was not found.
|
||||
token_missing: Page creation not possible, user account is not connected to the wiki provider.
|
||||
wikis:
|
||||
admin:
|
||||
destroy_confirmation_dialog_component:
|
||||
|
||||
+109
@@ -0,0 +1,109 @@
|
||||
# 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::Internal::Commands::CreatePage do
|
||||
subject(:result) { described_class.new(model: provider).call(input_data:, auth_strategy:) }
|
||||
|
||||
let(:provider) { create(:internal_wiki_provider) }
|
||||
let(:auth_strategy) { Wikis::Adapters::Input::AuthStrategy.build(key: :internal, user:, provider:).value! }
|
||||
let(:input_data) { Wikis::Adapters::Input::CreatePage.build(title:, parent_identifier:).value! }
|
||||
let(:user) { create(:user) }
|
||||
|
||||
let(:title) { "A page automatically created during a create_page test" }
|
||||
let(:parent_identifier) { existing_page.id.to_s }
|
||||
|
||||
let(:existing_page) { create(:wiki_page) }
|
||||
let(:project) { existing_page.project }
|
||||
let(:permissions) { %i[view_wiki_pages edit_wiki_pages] }
|
||||
|
||||
before do
|
||||
create(:member, project:, user:, roles: [create(:project_role, permissions:)])
|
||||
end
|
||||
|
||||
it { is_expected.to be_success }
|
||||
|
||||
it "successfully creates a page" do
|
||||
expect { subject }.to change(WikiPage, :count).by(1)
|
||||
|
||||
expect(WikiPage.last.title).to eq(title)
|
||||
end
|
||||
|
||||
it "makes the page a child of the intended parent" do
|
||||
subject
|
||||
expect(WikiPage.last.parent).to eq(existing_page)
|
||||
end
|
||||
|
||||
it "returns the page info of the created page" do
|
||||
expect(subject.value!.identifier).to eq(WikiPage.last.id.to_s)
|
||||
expect(subject.value!.title).to eq(title)
|
||||
end
|
||||
|
||||
context "when the parent does not exist" do
|
||||
let(:parent_identifier) { (existing_page.id * 10).to_s }
|
||||
|
||||
it "returns a :not_found error" do
|
||||
expect(result).to be_failure
|
||||
expect(result.failure.code).to eq(:not_found)
|
||||
end
|
||||
|
||||
it "does not create a page" do
|
||||
expect { subject }.not_to change(WikiPage, :count)
|
||||
end
|
||||
end
|
||||
|
||||
context "when the parent is not visible to the user" do
|
||||
let(:permissions) { %i[edit_wiki_pages] }
|
||||
|
||||
it "returns a :not_found error" do
|
||||
expect(result).to be_failure
|
||||
expect(result.failure.code).to eq(:not_found)
|
||||
end
|
||||
|
||||
it "does not create a page" do
|
||||
expect { subject }.not_to change(WikiPage, :count)
|
||||
end
|
||||
end
|
||||
|
||||
context "when user is not allowed to create wiki pages" do
|
||||
let(:permissions) { %i[view_wiki_pages] }
|
||||
|
||||
it "returns a :forbidden error" do
|
||||
expect(result).to be_failure
|
||||
expect(result.failure.code).to eq(:forbidden)
|
||||
end
|
||||
|
||||
it "does not create a page" do
|
||||
expect { subject }.not_to change(WikiPage, :count)
|
||||
end
|
||||
end
|
||||
end
|
||||
+122
@@ -0,0 +1,122 @@
|
||||
# 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::Commands::CreatePage, :disable_ssrf_filter, :webmock do
|
||||
describe "#call" do
|
||||
subject(:result) { described_class.new(model: provider).call(input_data:, auth_strategy:) }
|
||||
|
||||
let(:provider) { create(:xwiki_provider, :for_local_connection, connected_user: user) }
|
||||
let(:auth_strategy) { Wikis::Adapters::Input::AuthStrategy.build(key: :bearer_token, user:, provider:).value! }
|
||||
let(:input_data) { Wikis::Adapters::Input::CreatePage.build(title:, parent_identifier:).value! }
|
||||
let(:user) { create(:user) }
|
||||
|
||||
let(:title) { "A page automatically created during a create_page test" }
|
||||
# To record a VCR cassette, make sure to set parent_identifier to the stable ID of an existing wiki page
|
||||
# and parent_title to that wiki page's title.
|
||||
# Pages created in the run of these tests should be deleted again afterwards for repeatability
|
||||
let(:parent_identifier) { "d65fa" }
|
||||
let(:parent_title) { "Test Page for RSpec" }
|
||||
|
||||
it "successfully creates a page", vcr: "xwiki/create_page_and_confirm" do
|
||||
expect(result).to be_success
|
||||
id = result.value!.identifier
|
||||
|
||||
input = Wikis::Adapters::Input::PageInfo.build(identifier: id).value!
|
||||
confirmation = provider.resolve("queries.page_info").call(input_data: input, auth_strategy:)
|
||||
|
||||
expect(confirmation).to be_success
|
||||
expect(confirmation.value!.title).to eq(title)
|
||||
|
||||
aggregate_failures "making the page a child of the intended parent" do
|
||||
expected_prefix = Regexp.new("^#{Regexp.escape("xwiki:#{parent_title}.")}")
|
||||
expect(WebMock).to have_requested(:put, "https://xwiki.local/rest/openproject/documents")
|
||||
.with(query: hash_including(docRef: expected_prefix))
|
||||
end
|
||||
|
||||
aggregate_failures "allowing the created page to have child pages" do
|
||||
expected_suffix = /\.WebHome$/
|
||||
expect(WebMock).to have_requested(:put, "https://xwiki.local/rest/openproject/documents")
|
||||
.with(query: hash_including(docRef: expected_suffix))
|
||||
end
|
||||
end
|
||||
|
||||
context "when the parent does not exist", vcr: "xwiki/create_page_not_found" do
|
||||
let(:parent_identifier) { "abc123" }
|
||||
|
||||
it "returns a :not_found error" do
|
||||
expect(result).to be_failure
|
||||
expect(result.failure.code).to eq(:not_found)
|
||||
end
|
||||
|
||||
it "does not create a page" do
|
||||
result
|
||||
|
||||
expect(WebMock).not_to have_requested(:put, %r{https://xwiki.local/rest/openproject/documents})
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe ".derive_page_id" do
|
||||
subject { described_class.derive_page_id(title) }
|
||||
|
||||
let(:title) { "My simple title" }
|
||||
|
||||
it "does not interfere with the title" do
|
||||
expect(subject).to eq(title)
|
||||
end
|
||||
|
||||
context "when the title contains emoji and umlauts" do
|
||||
let(:title) { "Mein schöner Titel 🐈" }
|
||||
|
||||
it "does not interfere with the title" do
|
||||
expect(subject).to eq(title)
|
||||
end
|
||||
end
|
||||
|
||||
context "when the title contains colons or dots" do
|
||||
let(:title) { "Release notes: 1.0.0" }
|
||||
|
||||
it "escapes colons and dots" do
|
||||
expect(subject).to eq("Release notes\\: 1\\.0\\.0")
|
||||
end
|
||||
end
|
||||
|
||||
context "when the title contains backslashes" do
|
||||
let(:title) { "C:\\Windows\\System32 is a windows-style path" }
|
||||
|
||||
it "escapes backslashes" do
|
||||
expect(subject).to eq("C\\:\\\\Windows\\\\System32 is a windows-style path")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,131 @@
|
||||
# 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
|
||||
|
||||
module Wikis
|
||||
RSpec.describe CreateLinkedPageService do
|
||||
include Dry::Monads[:result]
|
||||
|
||||
subject(:service_result) do
|
||||
described_class.new(provider:, user:).call(
|
||||
title:,
|
||||
parent_identifier:,
|
||||
linkable_type: linkable.class.name,
|
||||
linkable_id: linkable.id
|
||||
)
|
||||
end
|
||||
|
||||
let(:user) { build_stubbed(:user) }
|
||||
let(:linkable) { build_stubbed(:work_package) }
|
||||
let(:title) { "My Page" }
|
||||
let(:parent_identifier) { "MySpace.Parent" }
|
||||
let(:page_identifier) { "#{parent_identifier}.MyPage" }
|
||||
let(:provider) { instance_double(Provider, id: 1) }
|
||||
let(:auth_strategy) { instance_double(Adapters::AuthenticationStrategies::BearerToken) }
|
||||
let(:create_page_command) { instance_double(Adapters::Providers::XWiki::Commands::CreatePage) }
|
||||
let(:page_info) do
|
||||
Adapters::Results::PageInfo.new(identifier: page_identifier, title:,
|
||||
href: "https://wiki.example.com/MyPage", provider:)
|
||||
end
|
||||
let(:page_link) { build_stubbed(:relation_wiki_page_link) }
|
||||
let(:create_link_service) { instance_double(RelationPageLinks::CreateService) }
|
||||
let(:create_link_result) { ServiceResult.success(result: page_link) }
|
||||
|
||||
before do
|
||||
allow(provider).to receive(:auth_strategy_for).with(user).and_return(Success(auth_strategy))
|
||||
allow(provider).to receive(:resolve).with("commands.create_page").and_return(create_page_command)
|
||||
allow(create_page_command).to receive(:call)
|
||||
.with(input_data: anything, auth_strategy: auth_strategy)
|
||||
.and_return(Success(page_info))
|
||||
allow(RelationPageLinks::CreateService).to receive(:new).with(user:).and_return(create_link_service)
|
||||
allow(create_link_service).to receive(:call).and_return(create_link_result)
|
||||
end
|
||||
|
||||
context "when all steps succeed" do
|
||||
it "returns a successful service result" do
|
||||
expect(service_result).to be_success
|
||||
end
|
||||
|
||||
it "returns the created page link as the result" do
|
||||
expect(service_result.result).to eq(page_link)
|
||||
end
|
||||
|
||||
it "creates a page link with the page identifier from the command result" do
|
||||
service_result
|
||||
|
||||
expect(create_link_service).to have_received(:call).with(
|
||||
provider_id: provider.id,
|
||||
linkable_type: linkable.class.name,
|
||||
linkable_id: linkable.id,
|
||||
author_id: user.id,
|
||||
identifier: page_identifier
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
context "when the create link service fails" do
|
||||
let(:create_link_result) { ServiceResult.failure }
|
||||
|
||||
it "returns the failure" do
|
||||
expect(service_result).to eq(create_link_result)
|
||||
end
|
||||
end
|
||||
|
||||
context "when auth strategy fails" do
|
||||
before do
|
||||
allow(provider).to receive(:auth_strategy_for).with(user)
|
||||
.and_return(Failure(Adapters::Results::Error.new(source: self, code: :missing_token)))
|
||||
end
|
||||
|
||||
it "returns a failure service result with the auth error code" do
|
||||
expect(service_result).to be_failure
|
||||
expect(service_result.errors.where(:base).map(&:type)).to include(:missing_token)
|
||||
end
|
||||
end
|
||||
|
||||
context "when the create page command fails" do
|
||||
let(:command_error) { Adapters::Results::Error.new(source: Adapters::Providers::XWiki::Commands::CreatePage, code: :not_found) }
|
||||
|
||||
before do
|
||||
allow(create_page_command).to receive(:call).and_return(Failure(command_error))
|
||||
end
|
||||
|
||||
it "returns a failure service result" do
|
||||
expect(service_result).to be_failure
|
||||
end
|
||||
|
||||
it "adds the command error code to the wiki_page attribute" do
|
||||
expect(service_result.errors.where(:wiki_page).map(&:type)).to include(:not_found)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,152 @@
|
||||
---
|
||||
http_interactions:
|
||||
- request:
|
||||
method: get
|
||||
uri: https://xwiki.local/rest/openproject/documents/d65fa
|
||||
body:
|
||||
encoding: US-ASCII
|
||||
string: ''
|
||||
headers:
|
||||
User-Agent:
|
||||
- OpenProject 17.6.0 HTTPX Client
|
||||
Accept:
|
||||
- application/json
|
||||
Accept-Encoding:
|
||||
- gzip, deflate
|
||||
Authorization:
|
||||
- Bearer <SECRET>
|
||||
response:
|
||||
status:
|
||||
code: 200
|
||||
message: OK
|
||||
headers:
|
||||
Content-Language:
|
||||
- en
|
||||
Content-Script-Type:
|
||||
- text/javascript
|
||||
Content-Type:
|
||||
- application/json;charset=UTF-8
|
||||
Date:
|
||||
- Fri, 12 Jun 2026 07:01:29 GMT
|
||||
Set-Cookie:
|
||||
- JSESSIONID=6533D0723B8276B5E0C9F0DF53503F6D; Path=/; HttpOnly
|
||||
Xwiki-Form-Token:
|
||||
- Lgex3rjqeBxHH0hyu8cGBQ
|
||||
Xwiki-User:
|
||||
- xwiki:XWiki.admin
|
||||
Xwiki-Version:
|
||||
- 18.3.0
|
||||
Content-Length:
|
||||
- '2540'
|
||||
body:
|
||||
encoding: UTF-8
|
||||
string: '{"links":[{"href":"https://xwiki.local/rest/wikis/xwiki/spaces/Test%20Page%20for%20RSpec","rel":"http://www.xwiki.org/rel/space","type":null,"hrefLang":null},{"href":"https://xwiki.local/rest/wikis/xwiki/spaces/Test%20Page%20for%20RSpec/pages/WebHome","rel":"http://www.xwiki.org/rel/parent","type":null,"hrefLang":null},{"href":"https://xwiki.local/rest/wikis/xwiki/spaces/Test%20Page%20for%20RSpec/pages/WebHome/history","rel":"http://www.xwiki.org/rel/history","type":null,"hrefLang":null},{"href":"https://xwiki.local/rest/wikis/xwiki/spaces/Test%20Page%20for%20RSpec/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/d65fa","rel":"self","type":null,"hrefLang":null},{"href":"https://xwiki.local/rest/wikis/xwiki/classes/Test%20Page%20for%20RSpec.WebHome","rel":"http://www.xwiki.org/rel/class","type":null,"hrefLang":null}],"id":"d65fa","fullName":"Test
|
||||
Page for RSpec.WebHome","wiki":"xwiki","space":"Test Page for RSpec","name":"WebHome","title":"Test
|
||||
Page for RSpec","rawTitle":"Test Page for RSpec","parent":"Main.WebHome","parentId":"xwiki:Main.WebHome","version":"1.1","author":"XWiki.admin","authorName":null,"xwikiRelativeUrl":"https://xwiki.local/bin/view/Test%20Page%20for%20RSpec/","xwikiAbsoluteUrl":"https://xwiki.local/bin/view/Test%20Page%20for%20RSpec/","translations":{"links":[],"translations":[],"default":"en"},"syntax":"xwiki/2.1","language":"","majorVersion":1,"minorVersion":1,"hidden":false,"enforceRequiredRights":false,"created":1781247375000,"creator":"XWiki.admin","creatorName":null,"modified":1781247375000,"modifier":"XWiki.admin","modifierName":null,"originalMetadataAuthor":"xwiki:XWiki.admin","originalMetadataAuthorName":null,"comment":"Created
|
||||
URL Shortener.","content":"I recreated this page, but it is for RSpec still.","clazz":null,"objects":null,"attachments":null,"hierarchy":{"items":[{"label":"xwiki","name":"xwiki","type":"wiki","url":"https://xwiki.local/bin/view/Main/"},{"label":"Test
|
||||
Page for RSpec","name":"Test Page for RSpec","type":"space","url":"https://xwiki.local/bin/view/Test%20Page%20for%20RSpec/"},{"label":"WebHome","name":"WebHome","type":"document","url":"https://xwiki.local/bin/view/Test%20Page%20for%20RSpec/"}]},"rights":[],"renderedContent":null}'
|
||||
recorded_at: Fri, 12 Jun 2026 07:01:29 GMT
|
||||
- request:
|
||||
method: put
|
||||
uri: https://xwiki.local/rest/openproject/documents?docRef=xwiki:Test%20Page%20for%20RSpec.A%20page%20automatically%20created%20during%20a%20create_page%20test.WebHome
|
||||
body:
|
||||
encoding: UTF-8
|
||||
string: '{"title":"A page automatically created during a create_page test"}'
|
||||
headers:
|
||||
User-Agent:
|
||||
- OpenProject 17.6.0 HTTPX Client
|
||||
Accept:
|
||||
- application/json
|
||||
Accept-Encoding:
|
||||
- gzip, deflate
|
||||
Content-Type:
|
||||
- application/json
|
||||
Content-Length:
|
||||
- '66'
|
||||
Authorization:
|
||||
- Bearer <SECRET>
|
||||
response:
|
||||
status:
|
||||
code: 201
|
||||
message: Created
|
||||
headers:
|
||||
Content-Language:
|
||||
- en
|
||||
Content-Script-Type:
|
||||
- text/javascript
|
||||
Content-Type:
|
||||
- application/json;charset=UTF-8
|
||||
Date:
|
||||
- Fri, 12 Jun 2026 07:01:29 GMT
|
||||
Set-Cookie:
|
||||
- JSESSIONID=ADC41F7E6B022B280D38635BE03C2FF1; Path=/; HttpOnly
|
||||
Xwiki-Form-Token:
|
||||
- Lgex3rjqeBxHH0hyu8cGBQ
|
||||
Xwiki-User:
|
||||
- xwiki:XWiki.admin
|
||||
Xwiki-Version:
|
||||
- 18.3.0
|
||||
Content-Length:
|
||||
- '2974'
|
||||
body:
|
||||
encoding: UTF-8
|
||||
string: '{"links":[{"href":"https://xwiki.local/rest/wikis/xwiki/spaces/Test%20Page%20for%20RSpec/spaces/A%20page%20automatically%20created%20during%20a%20create_page%20test","rel":"http://www.xwiki.org/rel/space","type":null,"hrefLang":null},{"href":"https://xwiki.local/rest/wikis/xwiki/spaces/Test%20Page%20for%20RSpec/spaces/A%20page%20automatically%20created%20during%20a%20create_page%20test/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/openproject/documents","rel":"self","type":null,"hrefLang":null},{"href":"https://xwiki.local/rest/wikis/xwiki/classes/Test%20Page%20for%20RSpec.A%20page%20automatically%20created%20during%20a%20create_page%20test.WebHome","rel":"http://www.xwiki.org/rel/class","type":null,"hrefLang":null}],"id":"91d8c","fullName":"Test
|
||||
Page for RSpec.A page automatically created during a create_page test.WebHome","wiki":"xwiki","space":"Test
|
||||
Page for RSpec.A page automatically created during a create_page test","name":"WebHome","title":"A
|
||||
page automatically created during a create_page test","rawTitle":"A page automatically
|
||||
created during a create_page test","parent":"","parentId":"","version":"1.1","author":"XWiki.admin","authorName":null,"xwikiRelativeUrl":"https://xwiki.local/bin/view/Test%20Page%20for%20RSpec/A%20page%20automatically%20created%20during%20a%20create_page%20test/","xwikiAbsoluteUrl":"https://xwiki.local/bin/view/Test%20Page%20for%20RSpec/A%20page%20automatically%20created%20during%20a%20create_page%20test/","translations":{"links":[],"translations":[],"default":""},"syntax":"xwiki/2.1","language":"","majorVersion":1,"minorVersion":1,"hidden":false,"enforceRequiredRights":false,"created":1781247689000,"creator":"XWiki.admin","creatorName":null,"modified":1781247689000,"modifier":"XWiki.admin","modifierName":null,"originalMetadataAuthor":"xwiki:XWiki.admin","originalMetadataAuthorName":null,"comment":"","content":"","clazz":null,"objects":null,"attachments":null,"hierarchy":{"items":[{"label":"xwiki","name":"xwiki","type":"wiki","url":"https://xwiki.local/bin/view/Main/"},{"label":"Test
|
||||
Page for RSpec","name":"Test Page for RSpec","type":"space","url":"https://xwiki.local/bin/view/Test%20Page%20for%20RSpec/"},{"label":"A
|
||||
page automatically created during a create_page test","name":"A page automatically
|
||||
created during a create_page test","type":"space","url":"https://xwiki.local/bin/view/Test%20Page%20for%20RSpec/A%20page%20automatically%20created%20during%20a%20create_page%20test/"},{"label":"WebHome","name":"WebHome","type":"document","url":"https://xwiki.local/bin/view/Test%20Page%20for%20RSpec/A%20page%20automatically%20created%20during%20a%20create_page%20test/"}]},"rights":[],"renderedContent":null}'
|
||||
recorded_at: Fri, 12 Jun 2026 07:01:29 GMT
|
||||
- request:
|
||||
method: get
|
||||
uri: https://xwiki.local/rest/openproject/documents/91d8c
|
||||
body:
|
||||
encoding: US-ASCII
|
||||
string: ''
|
||||
headers:
|
||||
User-Agent:
|
||||
- OpenProject 17.6.0 HTTPX Client
|
||||
Accept:
|
||||
- application/json
|
||||
Accept-Encoding:
|
||||
- gzip, deflate
|
||||
Authorization:
|
||||
- Bearer <SECRET>
|
||||
response:
|
||||
status:
|
||||
code: 200
|
||||
message: OK
|
||||
headers:
|
||||
Content-Language:
|
||||
- en
|
||||
Content-Script-Type:
|
||||
- text/javascript
|
||||
Content-Type:
|
||||
- application/json;charset=UTF-8
|
||||
Date:
|
||||
- Fri, 12 Jun 2026 07:01:29 GMT
|
||||
Set-Cookie:
|
||||
- JSESSIONID=D0A3382830FA89629B3D86592A6FF515; Path=/; HttpOnly
|
||||
Xwiki-Form-Token:
|
||||
- Lgex3rjqeBxHH0hyu8cGBQ
|
||||
Xwiki-User:
|
||||
- xwiki:XWiki.admin
|
||||
Xwiki-Version:
|
||||
- 18.3.0
|
||||
Content-Length:
|
||||
- '3259'
|
||||
body:
|
||||
encoding: UTF-8
|
||||
string: '{"links":[{"href":"https://xwiki.local/rest/wikis/xwiki/spaces/Test%20Page%20for%20RSpec/spaces/A%20page%20automatically%20created%20during%20a%20create_page%20test","rel":"http://www.xwiki.org/rel/space","type":null,"hrefLang":null},{"href":"https://xwiki.local/rest/wikis/xwiki/spaces/Test%20Page%20for%20RSpec/spaces/A%20page%20automatically%20created%20during%20a%20create_page%20test/pages/WebHome/history","rel":"http://www.xwiki.org/rel/history","type":null,"hrefLang":null},{"href":"https://xwiki.local/rest/wikis/xwiki/spaces/Test%20Page%20for%20RSpec/spaces/A%20page%20automatically%20created%20during%20a%20create_page%20test/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/91d8c","rel":"self","type":null,"hrefLang":null},{"href":"https://xwiki.local/rest/wikis/xwiki/classes/Test%20Page%20for%20RSpec.A%20page%20automatically%20created%20during%20a%20create_page%20test.WebHome","rel":"http://www.xwiki.org/rel/class","type":null,"hrefLang":null}],"id":"91d8c","fullName":"Test
|
||||
Page for RSpec.A page automatically created during a create_page test.WebHome","wiki":"xwiki","space":"Test
|
||||
Page for RSpec.A page automatically created during a create_page test","name":"WebHome","title":"A
|
||||
page automatically created during a create_page test","rawTitle":"A page automatically
|
||||
created during a create_page test","parent":"","parentId":"","version":"1.1","author":"XWiki.admin","authorName":null,"xwikiRelativeUrl":"https://xwiki.local/bin/view/Test%20Page%20for%20RSpec/A%20page%20automatically%20created%20during%20a%20create_page%20test/","xwikiAbsoluteUrl":"https://xwiki.local/bin/view/Test%20Page%20for%20RSpec/A%20page%20automatically%20created%20during%20a%20create_page%20test/","translations":{"links":[],"translations":[],"default":""},"syntax":"xwiki/2.1","language":"","majorVersion":1,"minorVersion":1,"hidden":false,"enforceRequiredRights":false,"created":1781247689000,"creator":"XWiki.admin","creatorName":null,"modified":1781247689000,"modifier":"XWiki.admin","modifierName":null,"originalMetadataAuthor":"xwiki:XWiki.admin","originalMetadataAuthorName":null,"comment":"Created
|
||||
URL Shortener.","content":"","clazz":null,"objects":null,"attachments":null,"hierarchy":{"items":[{"label":"xwiki","name":"xwiki","type":"wiki","url":"https://xwiki.local/bin/view/Main/"},{"label":"Test
|
||||
Page for RSpec","name":"Test Page for RSpec","type":"space","url":"https://xwiki.local/bin/view/Test%20Page%20for%20RSpec/"},{"label":"A
|
||||
page automatically created during a create_page test","name":"A page automatically
|
||||
created during a create_page test","type":"space","url":"https://xwiki.local/bin/view/Test%20Page%20for%20RSpec/A%20page%20automatically%20created%20during%20a%20create_page%20test/"},{"label":"WebHome","name":"WebHome","type":"document","url":"https://xwiki.local/bin/view/Test%20Page%20for%20RSpec/A%20page%20automatically%20created%20during%20a%20create_page%20test/"}]},"rights":[],"renderedContent":null}'
|
||||
recorded_at: Fri, 12 Jun 2026 07:01:29 GMT
|
||||
recorded_with: VCR 6.4.0
|
||||
@@ -0,0 +1,52 @@
|
||||
---
|
||||
http_interactions:
|
||||
- request:
|
||||
method: get
|
||||
uri: https://xwiki.local/rest/openproject/documents/abc123
|
||||
body:
|
||||
encoding: US-ASCII
|
||||
string: ''
|
||||
headers:
|
||||
User-Agent:
|
||||
- OpenProject 17.6.0 HTTPX Client
|
||||
Accept:
|
||||
- application/json
|
||||
Accept-Encoding:
|
||||
- gzip, deflate
|
||||
Authorization:
|
||||
- Bearer <SECRET>
|
||||
response:
|
||||
status:
|
||||
code: 404
|
||||
message: Not Found
|
||||
headers:
|
||||
Content-Language:
|
||||
- en
|
||||
Content-Script-Type:
|
||||
- text/javascript
|
||||
Content-Type:
|
||||
- text/html;charset=utf-8
|
||||
Date:
|
||||
- Thu, 11 Jun 2026 14:40:01 GMT
|
||||
Set-Cookie:
|
||||
- JSESSIONID=D9B95B99F5C18BBBF0957992EE0CBD09; Path=/; HttpOnly
|
||||
Xwiki-Form-Token:
|
||||
- 1FHSxxmCi5SpcFuCzBbysA
|
||||
Xwiki-User:
|
||||
- xwiki:XWiki.admin
|
||||
Xwiki-Version:
|
||||
- 18.3.0
|
||||
Content-Length:
|
||||
- '714'
|
||||
body:
|
||||
encoding: UTF-8
|
||||
string: <!doctype html><html lang="en"><head><title>HTTP Status 404 – Not Found</title><style
|
||||
type="text/css">body {font-family:Tahoma,Arial,sans-serif;} h1, h2, h3, b
|
||||
{color:white;background-color:#525D76;} h1 {font-size:22px;} h2 {font-size:16px;}
|
||||
h3 {font-size:14px;} p {font-size:12px;} a {color:black;} .line {height:1px;background-color:#525D76;border:none;}</style></head><body><h1>HTTP
|
||||
Status 404 – Not Found</h1><hr class="line" /><p><b>Type</b> Status Report</p><p><b>Message</b>
|
||||
Not Found</p><p><b>Description</b> The origin server did not find a current
|
||||
representation for the target resource or is not willing to disclose that
|
||||
one exists.</p><hr class="line" /><h3>Apache Tomcat/10.1.55</h3></body></html>
|
||||
recorded_at: Thu, 11 Jun 2026 14:40:01 GMT
|
||||
recorded_with: VCR 6.4.0
|
||||
Reference in New Issue
Block a user