diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2020-05-20 14:34:42 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2020-05-20 14:34:42 +0000 |
commit | 9f46488805e86b1bc341ea1620b866016c2ce5ed (patch) | |
tree | f9748c7e287041e37d6da49e0a29c9511dc34768 /app/models/wiki.rb | |
parent | dfc92d081ea0332d69c8aca2f0e745cb48ae5e6d (diff) | |
download | gitlab-ce-9f46488805e86b1bc341ea1620b866016c2ce5ed.tar.gz |
Add latest changes from gitlab-org/gitlab@13-0-stable-ee
Diffstat (limited to 'app/models/wiki.rb')
-rw-r--r-- | app/models/wiki.rb | 233 |
1 files changed, 233 insertions, 0 deletions
diff --git a/app/models/wiki.rb b/app/models/wiki.rb new file mode 100644 index 00000000000..54bcec32095 --- /dev/null +++ b/app/models/wiki.rb @@ -0,0 +1,233 @@ +# frozen_string_literal: true + +class Wiki + extend ::Gitlab::Utils::Override + include HasRepository + include Gitlab::Utils::StrongMemoize + + MARKUPS = { # rubocop:disable Style/MultilineIfModifier + 'Markdown' => :markdown, + 'RDoc' => :rdoc, + 'AsciiDoc' => :asciidoc, + 'Org' => :org + }.freeze unless defined?(MARKUPS) + + CouldNotCreateWikiError = Class.new(StandardError) + + HOMEPAGE = 'home' + SIDEBAR = '_sidebar' + + TITLE_ORDER = 'title' + CREATED_AT_ORDER = 'created_at' + DIRECTION_DESC = 'desc' + DIRECTION_ASC = 'asc' + + attr_reader :container, :user + + # Returns a string describing what went wrong after + # an operation fails. + attr_reader :error_message + + def self.for_container(container, user = nil) + "#{container.class.name}Wiki".constantize.new(container, user) + end + + def initialize(container, user = nil) + @container = container + @user = user + end + + def path + container.path + '.wiki' + end + + # Returns the Gitlab::Git::Wiki object. + def wiki + strong_memoize(:wiki) do + create_wiki_repository + Gitlab::Git::Wiki.new(repository.raw) + end + end + + def create_wiki_repository + repository.create_if_not_exists + + raise CouldNotCreateWikiError unless repository_exists? + rescue => err + Gitlab::ErrorTracking.track_exception(err, wiki: { + container_type: container.class.name, + container_id: container.id, + full_path: full_path, + disk_path: disk_path + }) + + raise CouldNotCreateWikiError + end + + def has_home_page? + !!find_page(HOMEPAGE) + end + + def empty? + list_pages(limit: 1).empty? + end + + def exists? + !empty? + end + + # Lists wiki pages of the repository. + # + # limit - max number of pages returned by the method. + # sort - criterion by which the pages are sorted. + # direction - order of the sorted pages. + # load_content - option, which specifies whether the content inside the page + # will be loaded. + # + # Returns an Array of GitLab WikiPage instances or an + # empty Array if this Wiki has no pages. + def list_pages(limit: 0, sort: nil, direction: DIRECTION_ASC, load_content: false) + wiki.list_pages( + limit: limit, + sort: sort, + direction_desc: direction == DIRECTION_DESC, + load_content: load_content + ).map do |page| + WikiPage.new(self, page) + end + end + + def sidebar_entries(limit: Gitlab::WikiPages::MAX_SIDEBAR_PAGES, **options) + pages = list_pages(**options.merge(limit: limit + 1)) + limited = pages.size > limit + pages = pages.first(limit) if limited + + [WikiPage.group_by_directory(pages), limited] + end + + # Finds a page within the repository based on a tile + # or slug. + # + # title - The human readable or parameterized title of + # the page. + # + # Returns an initialized WikiPage instance or nil + def find_page(title, version = nil) + page_title, page_dir = page_title_and_dir(title) + + if page = wiki.page(title: page_title, version: version, dir: page_dir) + WikiPage.new(self, page) + end + end + + def find_sidebar(version = nil) + find_page(SIDEBAR, version) + end + + def find_file(name, version = nil) + wiki.file(name, version) + end + + def create_page(title, content, format = :markdown, message = nil) + commit = commit_details(:created, message, title) + + wiki.write_page(title, format.to_sym, content, commit) + + update_container_activity + rescue Gitlab::Git::Wiki::DuplicatePageError => e + @error_message = "Duplicate page: #{e.message}" + false + end + + def update_page(page, content:, title: nil, format: :markdown, message: nil) + commit = commit_details(:updated, message, page.title) + + wiki.update_page(page.path, title || page.name, format.to_sym, content, commit) + + update_container_activity + end + + def delete_page(page, message = nil) + return unless page + + wiki.delete_page(page.path, commit_details(:deleted, message, page.title)) + + update_container_activity + end + + def page_title_and_dir(title) + return unless title + + title_array = title.split("/") + title = title_array.pop + [title, title_array.join("/")] + end + + def ensure_repository + raise CouldNotCreateWikiError unless wiki.repository_exists? + end + + def hook_attrs + { + web_url: web_url, + git_ssh_url: ssh_url_to_repo, + git_http_url: http_url_to_repo, + path_with_namespace: full_path, + default_branch: default_branch + } + end + + override :repository + def repository + @repository ||= Repository.new(full_path, container, shard: repository_storage, disk_path: disk_path, repo_type: Gitlab::GlRepository::WIKI) + end + + def repository_storage + raise NotImplementedError + end + + def hashed_storage? + raise NotImplementedError + end + + override :full_path + def full_path + container.full_path + '.wiki' + end + alias_method :id, :full_path + + # @deprecated use full_path when you need it for an URL route or disk_path when you want to point to the filesystem + alias_method :path_with_namespace, :full_path + + override :default_branch + def default_branch + wiki.class.default_ref + end + + def wiki_base_path + Gitlab.config.gitlab.relative_url_root + web_url(only_path: true).sub(%r{/#{Wiki::HOMEPAGE}\z}, '') + end + + private + + def commit_details(action, message = nil, title = nil) + commit_message = message.presence || default_message(action, title) + git_user = Gitlab::Git::User.from_gitlab(user) + + Gitlab::Git::Wiki::CommitDetails.new(user.id, + git_user.username, + git_user.name, + git_user.email, + commit_message) + end + + def default_message(action, title) + "#{user.username} #{action} page: #{title}" + end + + def update_container_activity + container.after_wiki_activity + end +end + +Wiki.prepend_if_ee('EE::Wiki') |