Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix/merge wiki content into page #12333

Merged
merged 8 commits into from
May 11, 2023
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
17 changes: 1 addition & 16 deletions app/contracts/wiki_pages/base_contract.rb
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ class BaseContract < ::ModelContract

validate :validate_author_is_set
validate :validate_wiki_is_set
validate :validate_content_is_set
validate :validate_user_edit_allowed
validate :validate_user_protect_permission

Expand All @@ -53,31 +52,17 @@ def validate_user_edit_allowed
end

def validate_author_is_set
errors.add :author, :blank if model.content&.author.nil?
errors.add :author, :blank if model.author.nil?
end

def validate_wiki_is_set
errors.add :wiki, :blank if model.wiki.nil?
end

def validate_content_is_set
errors.add :content, :blank if model.content.nil?
end

def validate_user_protect_permission
if model.protected_changed? && !user.allowed_to?(:protect_wiki_pages, model.project)
errors.add :protected, :error_unauthorized
end
end

def changed_by_user
content_changed = if model.content
model.content.respond_to?(:changed_by_user) ? model.content.changed_by_user : model.content.changed
else
[]
end

super + content_changed
end
end
end
2 changes: 1 addition & 1 deletion app/contracts/wiki_pages/create_contract.rb
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ class CreateContract < BaseContract
private

def validate_user_current_user
errors.add :author, :not_current_user if model.content&.author != user
errors.add :author, :not_current_user if model.author != user
end
end
end
52 changes: 21 additions & 31 deletions app/controllers/wiki_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ class WikiController < ApplicationController
destroy]
before_action :find_wiki_page, only: %i[show]
before_action :handle_new_wiki_page, only: %i[show]
before_action :build_wiki_page_and_content, only: %i[new create]
before_action :build_wiki_page, only: %i[new]

include AttachableServiceCall
include AttachmentsHelper
Expand Down Expand Up @@ -88,16 +88,15 @@ def show
# Set the related page ID to make it the parent of new links
flash[:_related_wiki_page_id] = @page.id

if params[:version] && !User.current.allowed_to?(:view_wiki_edits, @project)
# Redirects user to the current version if he's not allowed to view previous versions
redirect_to version: nil
return
end
@content = @page.content_for_version(params[:version])
version = params[:version] if User.current.allowed_to?(:view_wiki_edits, @project)

@page = ::WikiPages::AtVersion.new(@page, version)

if params[:format] == 'markdown' && User.current.allowed_to?(:export_wiki_pages, @project)
send_data(@content.text, type: 'text/plain', filename: "#{@page.title}.md")
send_data(@page.text, type: 'text/plain', filename: "#{@page.title}.md")
return
end

@editable = editable?
end

Expand All @@ -109,34 +108,31 @@ def new_child

old_page = @page

build_wiki_page_and_content
build_wiki_page

@page.parent = old_page
render action: 'new'
end

# edit an existing page or a new one
def edit
@page = @wiki.find_or_new_page(wiki_page_title)
return render_403 unless editable?
page = @wiki.find_or_new_page(wiki_page_title)
return render_403 unless editable?(page)

if @page.new_record?
@page.parent_id = flash[:_related_wiki_page_id] if flash[:_related_wiki_page_id]
@page.content = WikiContent.new(page: @page)
if page.new_record? && flash[:_related_wiki_page_id]
page.parent_id = flash[:_related_wiki_page_id]
end

@content = @page.content_for_version(params[:version])
version = params[:version] if User.current.allowed_to?(:view_wiki_edits, @project)
dombesz marked this conversation as resolved.
Show resolved Hide resolved

# To prevent StaleObjectError exception when reverting to a previous version
@content.lock_version = @page.content.lock_version
@page = ::WikiPages::AtVersion.new(page, version)
end

def create
call = attachable_create_call ::WikiPages::CreateService,
args: permitted_params.wiki_page_with_content.to_h.merge(wiki: @wiki)
args: permitted_params.wiki_page.to_h.merge(wiki: @wiki)

@page = call.result
@content = @page.content

if call.success?
call_hook(:controller_wiki_edit_after_save, params:, page: @page)
Expand All @@ -161,10 +157,9 @@ def update

call = attachable_update_call ::WikiPages::UpdateService,
model: @page,
args: permitted_params.wiki_page_with_content.to_h
args: permitted_params.wiki_page.to_h

@page = call.result
@content = @page.content

if call.success?
call_hook(:controller_wiki_edit_after_save, params:, page: @page)
Expand Down Expand Up @@ -252,7 +247,6 @@ def protect
def history
# don't load text
@versions = @page
.content
.journals
.select(:id, :user_id, :notes, :created_at, :version)
.order(Arel.sql('version DESC'))
Expand Down Expand Up @@ -401,15 +395,11 @@ def find_existing_page
render_404 if @page.nil?
end

def build_wiki_page_and_content
@page = WikiPage.new wiki: @wiki, title: wiki_page_title.presence
@page.content = WikiContent.new page: @page

if flash[:_related_wiki_page_id]
@page.parent_id = flash[:_related_wiki_page_id]
end

@content = @page.content_for_version nil
def build_wiki_page
@page = WikiPages::SetAttributesService
.new(model: WikiPage.new, user: current_user, contract_class: WikiPages::CreateContract)
.call(wiki: @wiki, title: wiki_page_title.presence, parent_id: flash[:_related_wiki_page_id])
.result
end

# Returns true if the current user is allowed to edit the page, otherwise false
Expand Down
103 changes: 103 additions & 0 deletions app/helpers/wiki_pages/at_version.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
# -- copyright
# OpenProject is an open source project management software.
# Copyright (C) 2010-2023 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.
# ++

# The class represents a wiki page at a specific version.
# It is implemented as somewhat of a mix between a decorator and a view model. It simplifies
# both the controller as well as the view. The controller will only have to provide a single object
# to the view and the view can serve all it's data needs from that one object.
#
# In case more objects like this are generated, a separate folder under e.g. app/view_models or app/decorators
# should be introduced.
class WikiPages::AtVersion < SimpleDelegator
attr_reader :latest_version,
:version

def initialize(wiki_page, version = nil)
super(wiki_page)
self.latest_version = wiki_page.version
self.version = (version || wiki_page.version).to_i.clamp(0, latest_version)
end

delegate :text,
to: :data

delegate :updated_at,
to: :last_journal,
allow_nil: true

# The form_for helper will call the #to_model method on the object it is passed otherwise
# which will return the object itself. Any version handling intended by this class will be forfeit.

# rubocop:disable Style/OptionalBooleanParameter
# Overwriting a superclass method.
def respond_to?(method_name, include_all = false)
if method_name.to_s == 'to_model'
false
else
super
end
end
# rubocop:enable Style/OptionalBooleanParameter

def author
last_journal&.user
end

def journals
@journals ||= super.select { |j| j.version <= version.to_i }
end

def readonly?
!current_version?
end

def current_version?
latest_version == version
end

def object
__getobj__
end

def to_ary
object.send(:to_ary)
end

private

attr_writer :latest_version,
:version

def data
last_journal.present? ? last_journal.data : object
end

def last_journal
@last_journal ||= journals.last
end
end
32 changes: 16 additions & 16 deletions app/mailers/user_mailer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -119,29 +119,29 @@ def news_comment_added(user, comment)
send_mail(user, subject)
end

def wiki_content_added(user, wiki_content)
@wiki_content = wiki_content
def wiki_page_added(user, wiki_page)
@wiki_page = wiki_page

open_project_wiki_headers @wiki_content
message_id @wiki_content, user
open_project_wiki_headers @wiki_page
message_id @wiki_page, user

send_mail(user,
"[#{@wiki_content.project.name}] #{t(:mail_subject_wiki_content_added, id: @wiki_content.page.title)}")
"[#{@wiki_page.project.name}] #{t(:mail_subject_wiki_page_added, id: @wiki_page.title)}")
end

def wiki_content_updated(user, wiki_content)
@wiki_content = wiki_content
def wiki_page_updated(user, wiki_page)
@wiki_page = wiki_page
@wiki_diff_url = url_for(controller: '/wiki',
action: :diff,
project_id: wiki_content.project,
id: wiki_content.page.slug,
version: wiki_content.version)
project_id: wiki_page.project,
id: wiki_page.slug,
version: wiki_page.version)

open_project_wiki_headers @wiki_content
message_id @wiki_content, user
open_project_wiki_headers @wiki_page
message_id @wiki_page, user

send_mail(user,
"[#{@wiki_content.project.name}] #{t(:mail_subject_wiki_content_updated, id: @wiki_content.page.title)}")
"[#{@wiki_page.project.name}] #{t(:mail_subject_wiki_page_updated, id: @wiki_page.title)}")
end

def message_posted(user, message)
Expand Down Expand Up @@ -221,9 +221,9 @@ def incoming_email_error(user, mail, logs)

private

def open_project_wiki_headers(wiki_content)
open_project_headers 'Project' => wiki_content.project.identifier,
'Wiki-Page-Id' => wiki_content.page.id,
def open_project_wiki_headers(wiki_page)
open_project_headers 'Project' => wiki_page.project.identifier,
'Wiki-Page-Id' => wiki_page.id,
'Type' => 'Wiki'
end

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,12 @@
# See COPYRIGHT and LICENSE files for more details.
#++

class Activities::WikiContentActivityProvider < Activities::BaseActivityProvider
class Activities::WikiPageActivityProvider < Activities::BaseActivityProvider
activity_provider_for type: 'wiki_edits',
permission: :view_wiki_edits

def extend_event_query(query)
query.join(wiki_pages_table).on(activity_journals_table[:page_id].eq(wiki_pages_table[:id]))
query.join(wiki_pages_table).on(journals_table[:journable_id].eq(wiki_pages_table[:id]))
query.join(wikis_table).on(wiki_pages_table[:wiki_id].eq(wikis_table[:id]))
end

Expand Down
2 changes: 1 addition & 1 deletion app/models/journal.rb
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ class Journal < ApplicationRecord
# logs like the history on issue#show
scope :changing, -> { where(['version > 1']) }

scope :for_wiki_content, -> { where(journable_type: "WikiContent") }
scope :for_wiki_page, -> { where(journable_type: "WikiPage") }
scope :for_work_package, -> { where(journable_type: "WorkPackage") }

# In conjunction with the included Comparable module, allows comparison of journal records
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,11 @@
# See COPYRIGHT and LICENSE files for more details.
#++

class Journal::WikiContentJournal < Journal::BaseJournal
self.table_name = 'wiki_content_journals'
class Journal::WikiPageJournal < Journal::BaseJournal
belongs_to :author, class_name: 'User'

# The project does not change over the course of a wiki content lifetime
self.table_name = 'wiki_page_journals'

# The project does not change over the course of a wiki page lifetime
delegate :project, to: :journal
end
12 changes: 1 addition & 11 deletions app/models/permitted_params.rb
Original file line number Diff line number Diff line change
Expand Up @@ -253,15 +253,7 @@ def wiki_page_rename
def wiki_page
permitted = permitted_attributes(:wiki_page)

params.require(:content).require(:page).permit(*permitted)
end

def wiki_content
params.require(:content).permit(*self.class.permitted_attributes[:wiki_content])
end

def wiki_page_with_content
wiki_page.merge(wiki_content)
params.require(:page).permit(*permitted)
end

def pref
Expand Down Expand Up @@ -609,8 +601,6 @@ def self.permitted_attributes
title
parent_id
redirect_existing_links
),
wiki_content: %i(
text
lock_version
journal_notes
Expand Down
Loading