project_wiki.rb 4.9 KB
Newer Older
1 2
# frozen_string_literal: true

D
Dmitriy Zaporozhets 已提交
3 4
class ProjectWiki
  include Gitlab::ShellAdapter
5
  include Storage::LegacyProjectWiki
D
Dmitriy Zaporozhets 已提交
6 7

  MARKUPS = {
8
    'Markdown' => :markdown,
9 10
    'RDoc'     => :rdoc,
    'AsciiDoc' => :asciidoc
D
Douwe Maan 已提交
11
  }.freeze unless defined?(MARKUPS)
D
Dmitriy Zaporozhets 已提交
12

13
  CouldNotCreateWikiError = Class.new(StandardError)
14
  SIDEBAR = '_sidebar'
D
Dmitriy Zaporozhets 已提交
15 16 17 18

  # Returns a string describing what went wrong after
  # an operation fails.
  attr_reader :error_message
V
Valery Sizov 已提交
19
  attr_reader :project
D
Dmitriy Zaporozhets 已提交
20 21 22 23 24 25

  def initialize(project, user = nil)
    @project = project
    @user = user
  end

26
  delegate :repository_storage, :hashed_storage?, to: :project
D
Douwe Maan 已提交
27

D
Dmitriy Zaporozhets 已提交
28 29 30 31
  def path
    @project.path + '.wiki'
  end

32
  def full_path
33
    @project.full_path + '.wiki'
D
Dmitriy Zaporozhets 已提交
34 35
  end

36 37 38
  # @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

39
  def web_url
40
    Gitlab::Routing.url_helpers.project_wiki_url(@project, :home)
41 42
  end

D
Dmitriy Zaporozhets 已提交
43
  def url_to_repo
44
    gitlab_shell.url_to_repo(full_path)
D
Dmitriy Zaporozhets 已提交
45 46 47 48 49 50
  end

  def ssh_url_to_repo
    url_to_repo
  end

51
  def http_url_to_repo
52
    "#{Gitlab.config.gitlab.url}/#{full_path}.git"
D
Dmitriy Zaporozhets 已提交
53 54
  end

55
  def wiki_base_path
56
    [Gitlab.config.gitlab.relative_url_root, '/', @project.full_path, '/wikis'].join('')
57 58
  end

59
  # Returns the Gitlab::Git::Wiki object.
D
Dmitriy Zaporozhets 已提交
60 61
  def wiki
    @wiki ||= begin
62 63 64 65 66 67
      gl_repository = Gitlab::GlRepository.gl_repository(project, true)
      raw_repository = Gitlab::Git::Repository.new(project.repository_storage, disk_path + '.git', gl_repository)

      create_repo!(raw_repository) unless raw_repository.exists?

      Gitlab::Git::Wiki.new(raw_repository)
D
Dmitriy Zaporozhets 已提交
68 69 70
    end
  end

71 72 73
  def repository_exists?
    !!repository.exists?
  end
74 75 76 77

  def has_home_page?
    !!find_page('home')
  end
78

S
Stan Hu 已提交
79 80 81 82
  def empty?
    pages(limit: 1).empty?
  end

D
Dmitriy Zaporozhets 已提交
83 84
  # Returns an Array of Gitlab WikiPage instances or an
  # empty Array if this Wiki has no pages.
85
  def pages(limit: 0)
86
    wiki.pages(limit: limit).map { |page| WikiPage.new(self, page, true) }
D
Dmitriy Zaporozhets 已提交
87 88 89 90 91 92 93 94 95 96
  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)
M
Marin Jankovski 已提交
97
    page_title, page_dir = page_title_and_dir(title)
98 99

    if page = wiki.page(title: page_title, version: version, dir: page_dir)
D
Dmitriy Zaporozhets 已提交
100 101 102 103
      WikiPage.new(self, page, true)
    end
  end

104 105 106 107
  def find_sidebar(version = nil)
    find_page(SIDEBAR, version)
  end

108 109
  def find_file(name, version = nil)
    wiki.file(name, version)
110 111
  end

D
Dmitriy Zaporozhets 已提交
112 113 114
  def create_page(title, content, format = :markdown, message = nil)
    commit = commit_details(:created, message, title)

115
    wiki.write_page(title, format.to_sym, content, commit)
116 117

    update_project_activity
118
  rescue Gitlab::Git::Wiki::DuplicatePageError => e
D
Dmitriy Zaporozhets 已提交
119
    @error_message = "Duplicate page: #{e.message}"
L
Lin Jen-Shin 已提交
120
    false
D
Dmitriy Zaporozhets 已提交
121 122
  end

123
  def update_page(page, content:, title: nil, format: :markdown, message: nil)
D
Dmitriy Zaporozhets 已提交
124 125
    commit = commit_details(:updated, message, page.title)

126
    wiki.update_page(page.path, title || page.name, format.to_sym, content, commit)
127 128

    update_project_activity
D
Dmitriy Zaporozhets 已提交
129 130 131
  end

  def delete_page(page, message = nil)
132 133
    return unless page

134
    wiki.delete_page(page.path, commit_details(:deleted, message, page.title))
135 136

    update_project_activity
D
Dmitriy Zaporozhets 已提交
137 138
  end

139 140 141 142 143 144
  def page_formatted_data(page)
    page_title, page_dir = page_title_and_dir(page.title)

    wiki.page_formatted_data(title: page_title, dir: page_dir, version: page.version)
  end

M
Marin Jankovski 已提交
145
  def page_title_and_dir(title)
146 147
    return unless title

148
    title_array = title.split("/")
M
Marin Jankovski 已提交
149
    title = title_array.pop
S
Stan Hu 已提交
150
    [title, title_array.join("/")]
M
Marin Jankovski 已提交
151 152
  end

D
Dmitriy Zaporozhets 已提交
153
  def repository
154
    @repository ||= Repository.new(full_path, @project, disk_path: disk_path, is_wiki: true)
D
Dmitriy Zaporozhets 已提交
155 156 157 158 159 160
  end

  def default_branch
    wiki.class.default_ref
  end

161
  def ensure_repository
162
    raise CouldNotCreateWikiError unless wiki.repository_exists?
163 164
  end

165 166 167 168 169
  def hook_attrs
    {
      web_url: web_url,
      git_ssh_url: ssh_url_to_repo,
      git_http_url: http_url_to_repo,
170
      path_with_namespace: full_path,
G
Gabriel Mazetto 已提交
171
      default_branch: default_branch
172 173
    }
  end
D
Dmitriy Zaporozhets 已提交
174

175 176
  private

177
  def create_repo!(raw_repository)
178
    gitlab_shell.create_repository(project.repository_storage, disk_path)
179 180 181 182

    raise CouldNotCreateWikiError unless raw_repository.exists?

    repository.after_create
D
Dmitriy Zaporozhets 已提交
183 184 185 186
  end

  def commit_details(action, message = nil, title = nil)
    commit_message = message || default_message(action, title)
187
    git_user = Gitlab::Git::User.from_gitlab(@user)
D
Dmitriy Zaporozhets 已提交
188

189
    Gitlab::Git::Wiki::CommitDetails.new(@user.id,
190 191 192
                                         git_user.username,
                                         git_user.name,
                                         git_user.email,
193
                                         commit_message)
D
Dmitriy Zaporozhets 已提交
194 195 196 197 198 199
  end

  def default_message(action, title)
    "#{@user.username} #{action} page: #{title}"
  end

200
  def update_project_activity
201
    @project.touch(:last_activity_at, :last_repository_updated_at)
202
  end
D
Dmitriy Zaporozhets 已提交
203
end