project_wiki.rb 4.85 KB
Newer Older
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
1 2
class ProjectWiki
  include Gitlab::ShellAdapter
3
  include Storage::LegacyProjectWiki
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
4 5

  MARKUPS = {
6
    'Markdown' => :markdown,
7 8
    'RDoc'     => :rdoc,
    'AsciiDoc' => :asciidoc
Douwe Maan's avatar
Douwe Maan committed
9
  }.freeze unless defined?(MARKUPS)
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
10

11
  CouldNotCreateWikiError = Class.new(StandardError)
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
12 13 14 15

  # Returns a string describing what went wrong after
  # an operation fails.
  attr_reader :error_message
16
  attr_reader :project
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
17 18 19 20 21 22

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

Douwe Maan's avatar
Douwe Maan committed
23
  delegate :empty?, to: :pages
24
  delegate :repository_storage_path, :hashed_storage?, to: :project
Douwe Maan's avatar
Douwe Maan committed
25

Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
26 27 28 29
  def path
    @project.path + '.wiki'
  end

30
  def full_path
31
    @project.full_path + '.wiki'
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
32 33
  end

34 35 36
  # @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

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

Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
41
  def url_to_repo
42
    gitlab_shell.url_to_repo(full_path)
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
43 44 45 46 47 48
  end

  def ssh_url_to_repo
    url_to_repo
  end

49
  def http_url_to_repo
50
    "#{Gitlab.config.gitlab.url}/#{full_path}.git"
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
51 52
  end

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

57
  # Returns the Gitlab::Git::Wiki object.
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
58 59
  def wiki
    @wiki ||= begin
60 61 62 63 64 65
      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)
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
66 67 68
    end
  end

69 70 71
  def repository_exists?
    !!repository.exists?
  end
72 73 74 75

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

Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
77 78
  # Returns an Array of Gitlab WikiPage instances or an
  # empty Array if this Wiki has no pages.
79 80
  def pages(limit: nil)
    wiki.pages(limit: limit).map { |page| WikiPage.new(self, page, true) }
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
81 82 83 84 85 86 87 88 89 90
  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)
91
    page_title, page_dir = page_title_and_dir(title)
92 93

    if page = wiki.page(title: page_title, version: version, dir: page_dir)
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
94 95 96 97
      WikiPage.new(self, page, true)
    end
  end

98 99
  def find_file(name, version = nil)
    wiki.file(name, version)
100 101
  end

Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
102 103 104
  def create_page(title, content, format = :markdown, message = nil)
    commit = commit_details(:created, message, title)

105
    wiki.write_page(title, format.to_sym, content, commit)
106 107

    update_project_activity
108
  rescue Gitlab::Git::Wiki::DuplicatePageError => e
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
109 110 111 112
    @error_message = "Duplicate page: #{e.message}"
    return false
  end

113
  def update_page(page, content:, title: nil, format: :markdown, message: nil)
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
114 115
    commit = commit_details(:updated, message, page.title)

116
    wiki.update_page(page.path, title || page.name, format.to_sym, content, commit)
117 118

    update_project_activity
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
119 120 121
  end

  def delete_page(page, message = nil)
122 123
    return unless page

124
    wiki.delete_page(page.path, commit_details(:deleted, message, page.title))
125 126

    update_project_activity
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
127 128
  end

129 130 131 132 133 134
  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

135
  def page_title_and_dir(title)
136 137
    return unless title

138
    title_array = title.split("/")
139
    title = title_array.pop
140
    [title, title_array.join("/")]
141 142
  end

Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
143
  def search_files(query)
144
    repository.search_files_by_content(query, default_branch)
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
145 146 147
  end

  def repository
148
    @repository ||= Repository.new(full_path, @project, disk_path: disk_path, is_wiki: true)
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
149 150 151 152 153 154
  end

  def default_branch
    wiki.class.default_ref
  end

155
  def ensure_repository
156
    raise CouldNotCreateWikiError unless wiki.repository_exists?
157 158
  end

159 160 161 162 163
  def hook_attrs
    {
      web_url: web_url,
      git_ssh_url: ssh_url_to_repo,
      git_http_url: http_url_to_repo,
164
      path_with_namespace: full_path,
Gabriel Mazetto's avatar
Gabriel Mazetto committed
165
      default_branch: default_branch
166 167
    }
  end
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
168

169 170
  private

171
  def create_repo!(raw_repository)
172
    gitlab_shell.create_repository(project.repository_storage, disk_path)
173 174 175 176

    raise CouldNotCreateWikiError unless raw_repository.exists?

    repository.after_create
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
177 178 179 180 181
  end

  def commit_details(action, message = nil, title = nil)
    commit_message = message || default_message(action, title)

182 183 184 185 186
    Gitlab::Git::Wiki::CommitDetails.new(@user.id,
                                         @user.username,
                                         @user.name,
                                         @user.email,
                                         commit_message)
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
187 188 189 190 191 192
  end

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

193
  def update_project_activity
194
    @project.touch(:last_activity_at, :last_repository_updated_at)
195
  end
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
196
end