Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions modules/wikis/app/models/wikis/page_link.rb
Original file line number Diff line number Diff line change
Expand Up @@ -34,5 +34,7 @@ class PageLink < ApplicationRecord

belongs_to :provider
belongs_to :linkable, polymorphic: true

def render_author? = false
end
end
2 changes: 2 additions & 0 deletions modules/wikis/app/models/wikis/relation_page_link.rb
Original file line number Diff line number Diff line change
Expand Up @@ -31,5 +31,7 @@
module Wikis
class RelationPageLink < PageLink
belongs_to :author, class_name: "User"

def render_author? = true
end
end
2 changes: 2 additions & 0 deletions modules/wikis/config/locales/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ en:
one: Relation page link
other: Relation page links
wikis/xwiki_provider: XWiki provider
permission_manage_wiki_page_links: Manage Wiki Page Links
permission_view_wiki_page_links: View Wiki Page Links
Comment thread
NobodysNightmare marked this conversation as resolved.
project_module_wiki_platforms: Wiki providers
wikis:
buttons:
Expand Down
86 changes: 86 additions & 0 deletions modules/wikis/lib/api/v3/page_links/page_link_representer.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
# 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 API
module V3
module PageLinks
class PageLinkRepresenter < Decorators::Single
include Decorators::LinkedResource
include Decorators::DateProperty
include Caching::CachedRepresenter

property :id
property :identifier

date_time_property :created_at
date_time_property :updated_at

# Title being the identifier is kind of a placeholder until we have actual page names
Comment thread
NobodysNightmare marked this conversation as resolved.
self_link(path: :wiki_page_link, title_getter: ->(*) { represented.identifier })
Comment thread
NobodysNightmare marked this conversation as resolved.

link :delete, cache_if: ->(*) { user_allowed_to_manage?(represented) } do
{
href: api_v3_paths.wiki_page_link(represented.id),
method: :delete
}
end

link :author do
next unless represented.render_author?

{
href: api_v3_paths.user(represented.author_id),
title: represented.author.name
}
end

associated_resource :provider, v3_path: :wiki_provider

# TODO: Make this truly polymorphic - @mereghost 2026-04-13
associated_resource :linkable,
v3_path: :work_package,
representer: ::API::V3::WorkPackages::WorkPackageRepresenter,
skip_render: ->(*) { represented.linkable_id.nil? || represented.linkable_type != "WorkPackage" }

def _type = represented.class.name.demodulize

private

def user_allowed_to_manage?(model)
if model.linkable.present?
current_user.allowed_in_project?(:manage_wiki_page_links, model.linkable.project)
else
current_user == model.author
end
end
end
end
end
end
48 changes: 48 additions & 0 deletions modules/wikis/lib/api/v3/providers/provider_representer.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# 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 API
module V3
module Providers
class ProviderRepresenter < Decorators::Single
include Decorators::LinkedResource
include Decorators::DateProperty

property :id
property :name

date_time_property :created_at
date_time_property :updated_at

self_link(path: :wiki_provider)
end
end
end
end
17 changes: 17 additions & 0 deletions modules/wikis/lib/open_project/wikis/engine.rb
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,20 @@ class Engine < ::Rails::Engine
replace_principal_references "Wikis::PageLink" => %i[author_id]

register "openproject-wikis", author_url: "https://openproject.org" do
project_module :work_package_tracking do
permission :view_wiki_page_links,
Comment thread
NobodysNightmare marked this conversation as resolved.
{},
permissible_on: :project,
dependencies: %i[view_work_packages],
contract_actions: { wiki_page_links: %i[view] }

permission :manage_wiki_page_links,
{},
permissible_on: :project,
dependencies: %i[view_work_packages],
contract_actions: { wiki_page_links: %i[manage] }
end

menu :work_package_split_view,
:wikis,
{ tab: :wikis },
Expand All @@ -81,5 +95,8 @@ class Engine < ::Rails::Engine
caption: :project_module_wiki_platforms,
icon: "browser"
end

add_api_path(:wiki_page_link) { |page_link_id| "#{root}/wiki_page_links/#{page_link_id}" }
add_api_path(:wiki_provider) { |provider_id| "#{root}/wiki_providers/#{provider_id}" }
end
end
147 changes: 147 additions & 0 deletions modules/wikis/spec/lib/api/v3/page_links/page_link_representer_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
# 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"

module API
module V3
module PageLinks
RSpec.describe PageLinkRepresenter, :rendering do
include Utilities::PathHelper

let(:inline_page_link) { build_stubbed(:inline_wiki_page_link) }
let(:relation_page_link) { build_stubbed(:relation_wiki_page_link) }
let(:current_user) { build_stubbed(:user) }

let(:represented) { relation_page_link }
let(:project) { represented.linkable.project }

let(:embed_links) { false }
let(:representer) { described_class.new(represented, current_user:, embed_links:) }

subject(:resulting_json) { representer.to_json }

describe "_links" do
describe "self" do
it_behaves_like "has a titled link" do
let(:link) { "self" }
let(:href) { "/api/v3/wiki_page_links/#{represented.id}" }
let(:title) { represented.identifier }
end
end

describe "provider" do
it_behaves_like "has a titled link" do
let(:link) { "provider" }
let(:href) { "/api/v3/wiki_providers/#{represented.provider_id}" }
let(:title) { represented.provider.name }
end
end

describe "delete" do
let(:permission) { :manage_wiki_page_links }

let(:link) { "delete" }
let(:href) { "/api/v3/wiki_page_links/#{represented.id}" }
let(:method) { :delete }

it_behaves_like "has an untitled action link"

context "when there is no associated linkable" do
before { represented.linkable = nil }

it_behaves_like "has no link"

context "and the current user is creator of the file link" do
let(:current_user) { represented.author }

it { is_expected.to have_json_path("_links/#{link}") }
end
end
end

describe "author" do
context "when the page link is an InlinePageLink" do
let(:represented) { inline_page_link }

it "does not render the author link" do
expect(resulting_json).not_to have_json_path("author")
end
end

it_behaves_like "has a titled link" do
let(:link) { "author" }
let(:href) { "/api/v3/users/#{represented.author_id}" }
let(:title) { represented.author.name }
end
end

describe "linkable" do
it_behaves_like "has a titled link" do
let(:link) { "linkable" }
let(:href) { "/api/v3/work_packages/#{represented.linkable_id}" }
let(:title) { represented.linkable.name }
end
end
end

describe "properties" do
describe "_type" do
context "when InlinePageLink" do
let(:represented) { inline_page_link }

it_behaves_like "property", :_type do
let(:value) { "InlinePageLink" }
end
end

context "when RelationPageLink" do
it_behaves_like "property", :_type do
let(:value) { "RelationPageLink" }
end
end
end

it_behaves_like "property", :identifier do
let(:value) { represented.identifier }
end

it_behaves_like "datetime property", :createdAt do
let(:value) { represented.created_at }
end

it_behaves_like "datetime property", :updatedAt do
let(:value) { represented.updated_at }
end
end
end
end
end
end
Loading
Loading