Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'app/models/wiki_page.rb')
-rw-r--r--app/models/wiki_page.rb159
1 files changed, 114 insertions, 45 deletions
diff --git a/app/models/wiki_page.rb b/app/models/wiki_page.rb
index 224eb3cd4d0..0f5536415f7 100644
--- a/app/models/wiki_page.rb
+++ b/app/models/wiki_page.rb
@@ -1,4 +1,7 @@
class WikiPage
+ PageChangedError = Class.new(StandardError)
+ PageRenameError = Class.new(StandardError)
+
include ActiveModel::Validations
include ActiveModel::Conversion
include StaticModel
@@ -48,7 +51,7 @@ class WikiPage
# The Gitlab ProjectWiki instance.
attr_reader :wiki
- # The raw Gollum::Page instance.
+ # The raw Gitlab::Git::WikiPage instance.
attr_reader :page
# The attributes Hash used for storing and validating
@@ -73,7 +76,7 @@ class WikiPage
if @attributes[:slug].present?
@attributes[:slug]
else
- wiki.wiki.preview_page(title, '', format).url_path
+ wiki.wiki.preview_slug(title, format)
end
end
@@ -82,7 +85,7 @@ class WikiPage
# The formatted title of this page.
def title
if @attributes[:title]
- self.class.unhyphenize(@attributes[:title])
+ CGI.unescape_html(self.class.unhyphenize(@attributes[:title]))
else
""
end
@@ -100,12 +103,15 @@ class WikiPage
# The hierarchy of the directory this page is contained in.
def directory
- wiki.page_title_and_dir(slug).last
+ wiki.page_title_and_dir(slug)&.last.to_s
end
# The processed/formatted content of this page.
def formatted_content
- @attributes[:formatted_content] ||= @page&.formatted_data
+ # Assuming @page exists, nil formatted_data means we didn't load it
+ # before hand (i.e. page was fetched by Gitaly), so we fetch it separately.
+ # If the page was fetched by Gollum, formatted_data would've been a String.
+ @attributes[:formatted_content] ||= @page&.formatted_data || @wiki.page_formatted_data(@page)
end
# The markup format for the page.
@@ -125,15 +131,24 @@ class WikiPage
@version ||= @page.version
end
- # Returns an array of Gitlab Commit instances.
- def versions
+ def versions(options = {})
+ return [] unless persisted?
+
+ wiki.wiki.page_versions(@page.path, options)
+ end
+
+ def count_versions
return [] unless persisted?
- @page.versions
+ wiki.wiki.count_page_versions(@page.path)
end
- def commit
- versions.first
+ def last_version
+ @last_version ||= versions(limit: 1).first
+ end
+
+ def last_commit_sha
+ last_version&.sha
end
# Returns the Date that this latest version was
@@ -145,7 +160,7 @@ class WikiPage
# Returns boolean True or False if this instance
# is an old version of the page.
def historical?
- @page.historical? && versions.first.sha != version.sha
+ @page.historical? && last_version.sha != version.sha
end
# Returns boolean True or False if this instance
@@ -163,7 +178,7 @@ class WikiPage
# Creates a new Wiki Page.
#
# attr - Hash of attributes to set on the new page.
- # :title - The title for the new page.
+ # :title - The title (optionally including dir) for the new page.
# :content - The raw markup content.
# :format - Optional symbol representing the
# content format. Can be any type
@@ -174,26 +189,55 @@ class WikiPage
#
# Returns the String SHA1 of the newly created page
# or False if the save was unsuccessful.
- def create(attr = {})
- @attributes.merge!(attr)
+ def create(attrs = {})
+ update_attributes(attrs)
- save :create_page, title, content, format, message
+ save(page_details: title) do
+ wiki.create_page(title, content, format, message)
+ end
end
# Updates an existing Wiki Page, creating a new version.
#
- # new_content - The raw markup content to replace the existing.
- # format - Optional symbol representing the content format.
- # See ProjectWiki::MARKUPS Hash for available formats.
- # message - Optional commit message to set on the new version.
+ # attrs - Hash of attributes to be updated on the page.
+ # :content - The raw markup content to replace the existing.
+ # :format - Optional symbol representing the content format.
+ # See ProjectWiki::MARKUPS Hash for available formats.
+ # :message - Optional commit message to set on the new version.
+ # :last_commit_sha - Optional last commit sha to validate the page unchanged.
+ # :title - The Title (optionally including dir) to replace existing title
#
# Returns the String SHA1 of the newly created page
# or False if the save was unsuccessful.
- def update(new_content = "", format = :markdown, message = nil)
- @attributes[:content] = new_content
- @attributes[:format] = format
+ def update(attrs = {})
+ last_commit_sha = attrs.delete(:last_commit_sha)
+
+ if last_commit_sha && last_commit_sha != self.last_commit_sha
+ raise PageChangedError
+ end
- save :update_page, @page, content, format, message
+ update_attributes(attrs)
+
+ if title_changed?
+ page_details = title
+
+ if wiki.find_page(page_details).present?
+ @attributes[:title] = @page.url_path
+ raise PageRenameError
+ end
+ else
+ page_details = @page.url_path
+ end
+
+ save(page_details: page_details) do
+ wiki.update_page(
+ @page,
+ content: content,
+ format: format,
+ message: attrs[:message],
+ title: title
+ )
+ end
end
# Destroys the Wiki Page.
@@ -217,38 +261,63 @@ class WikiPage
page.version.to_s
end
+ def title_changed?
+ title.present? && self.class.unhyphenize(@page.url_path) != title
+ end
+
private
+ # Process and format the title based on the user input.
+ def process_title(title)
+ return if title.blank?
+
+ title = deep_title_squish(title)
+ current_dirname = File.dirname(title)
+
+ if @page.present?
+ return title[1..-1] if current_dirname == '/'
+ return File.join([directory.presence, title].compact) if current_dirname == '.'
+ end
+
+ title
+ end
+
+ # This method squishes all the filename
+ # i.e: ' foo / bar / page_name' => 'foo/bar/page_name'
+ def deep_title_squish(title)
+ components = title.split(File::SEPARATOR).map(&:squish)
+
+ File.join(components)
+ end
+
+ # Updates the current @attributes hash by merging a hash of params
+ def update_attributes(attrs)
+ attrs[:title] = process_title(attrs[:title]) if attrs[:title].present?
+
+ attrs.slice!(:content, :format, :message, :title)
+
+ @attributes.merge!(attrs)
+ end
+
def set_attributes
attributes[:slug] = @page.url_path
attributes[:title] = @page.title
attributes[:format] = @page.format
end
- def save(method, *args)
- saved = false
-
- project_wiki = wiki
- if valid? && project_wiki.send(method, *args)
+ def save(page_details:)
+ return unless valid?
- page_details = if method == :update_page
- # Use url_path instead of path to omit format extension
- @page.url_path
- else
- title
- end
-
- page_title, page_dir = project_wiki.page_title_and_dir(page_details)
- gollum_wiki = project_wiki.wiki
- @page = gollum_wiki.paged(page_title, page_dir)
+ unless yield
+ errors.add(:base, wiki.error_message)
+ return false
+ end
- set_attributes
+ page_title, page_dir = wiki.page_title_and_dir(page_details)
+ gitlab_git_wiki = wiki.wiki
+ @page = gitlab_git_wiki.page(title: page_title, dir: page_dir)
- @persisted = true
- saved = true
- else
- errors.add(:base, project_wiki.error_message) if project_wiki.error_message
- end
- saved
+ set_attributes
+ @persisted = errors.blank?
end
end