Class: WikiPage

Inherits:
Object
  • Object
show all
Extended by:
ActiveModel::Naming
Includes:
ActiveModel::Conversion, ActiveModel::Validations, Gitlab::Utils::StrongMemoize, StaticModel
Defined in:
app/models/wiki_page.rb,
app/models/wiki_page/meta.rb,
app/models/wiki_page/slug.rb

Overview

rubocop:disable Rails/ActiveRecordAliases

Defined Under Namespace

Classes: Meta, MetaPolicy, Slug

Constant Summary collapse

PageChangedError =
Class.new(StandardError)
PageRenameError =
Class.new(StandardError)
FrontMatterTooLong =
Class.new(StandardError)

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from StaticModel

#[], #destroyed?, #new_record?

Constructor Details

#initialize(wiki, page = nil) ⇒ WikiPage

Construct a new WikiPage

Parameters:



66
67
68
69
70
71
72
# File 'app/models/wiki_page.rb', line 66

def initialize(wiki, page = nil)
  @wiki       = wiki
  @page       = page
  @attributes = {}.with_indifferent_access

  set_attributes if persisted?
end

Instance Attribute Details

#attributesObject

The attributes Hash used for storing and validating new Page values before writing to the raw repository.



56
57
58
# File 'app/models/wiki_page.rb', line 56

def attributes
  @attributes
end

#pageObject (readonly)

The raw Gitlab::Git::WikiPage instance.



52
53
54
# File 'app/models/wiki_page.rb', line 52

def page
  @page
end

#wikiObject (readonly)

The GitLab Wiki instance.



47
48
49
# File 'app/models/wiki_page.rb', line 47

def wiki
  @wiki
end

Class Method Details

.model_nameObject



22
23
24
# File 'app/models/wiki_page.rb', line 22

def self.model_name
  ActiveModel::Name.new(self, nil, 'wiki')
end

.primary_keyObject



18
19
20
# File 'app/models/wiki_page.rb', line 18

def self.primary_key
  'slug'
end

.unhyphenize(name) ⇒ Object



34
35
36
# File 'app/models/wiki_page.rb', line 34

def self.unhyphenize(name)
  name.gsub(/-+/, ' ')
end

Instance Method Details

#content_changed?Boolean

Returns:

  • (Boolean)


285
286
287
288
289
290
291
292
293
# File 'app/models/wiki_page.rb', line 285

def content_changed?
  if persisted?
    # To avoid end-of-line differences depending if Git is enforcing CRLF or not,
    # we compare just the Wiki Content.
    raw_content.lines(chomp: true) != page&.text_data&.lines(chomp: true)
  else
    raw_content.present?
  end
end

#count_versionsObject



156
157
158
159
160
# File 'app/models/wiki_page.rb', line 156

def count_versions
  return [] unless persisted?

  wiki.repository.count_commits(ref: wiki.default_branch, path: page.path)
end

#create(attrs = {}) ⇒ Object

Creates a new Wiki Page.

attr - Hash of attributes to set on 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
           listed in the Wiki::VALID_USER_MARKUPS
           Hash.
:message - Optional commit message to set on
           the new page.

Returns the String SHA1 of the newly created page or False if the save was unsuccessful.



204
205
206
207
208
209
210
# File 'app/models/wiki_page.rb', line 204

def create(attrs = {})
  update_attributes(attrs)

  save do
    wiki.create_page(title, content, format, attrs[:message])
  end
end

#deleteObject

Destroys the Wiki Page.

Returns boolean True or False.



253
254
255
256
257
258
259
# File 'app/models/wiki_page.rb', line 253

def delete
  if wiki.delete_page(page)
    true
  else
    false
  end
end

#diffs(diff_options = {}) ⇒ Object



314
315
316
# File 'app/models/wiki_page.rb', line 314

def diffs(diff_options = {})
  Gitlab::Diff::FileCollection::WikiPage.new(self, diff_options: diff_options)
end

#directoryObject

The hierarchy of the directory this page is contained in.



110
111
112
# File 'app/models/wiki_page.rb', line 110

def directory
  wiki.page_title_and_dir(slug)&.last.to_s
end

#eql?(other) ⇒ Boolean Also known as: ==

Returns:

  • (Boolean)


26
27
28
29
30
# File 'app/models/wiki_page.rb', line 26

def eql?(other)
  return false unless other.present? && other.is_a?(self.class)

  slug == other.slug && wiki.container == other.wiki.container
end

#formatObject

The markup format for the page.



115
116
117
# File 'app/models/wiki_page.rb', line 115

def format
  attributes[:format] || :markdown
end

#historical?Boolean

Returns boolean True or False if this instance is an old version of the page.

Returns:

  • (Boolean)


172
173
174
175
176
# File 'app/models/wiki_page.rb', line 172

def historical?
  return false unless last_commit_sha && version

  page.historical? && last_commit_sha != version.sha
end

#hook_attrsObject



58
59
60
# File 'app/models/wiki_page.rb', line 58

def hook_attrs
  Gitlab::HookData::WikiPageBuilder.new(self).build
end

#human_titleObject



82
83
84
85
86
# File 'app/models/wiki_page.rb', line 82

def human_title
  return 'Home' if title == Wiki::HOMEPAGE

  title
end

#last_commit_shaObject



166
167
168
# File 'app/models/wiki_page.rb', line 166

def last_commit_sha
  last_version&.sha
end

#last_versionObject



162
163
164
# File 'app/models/wiki_page.rb', line 162

def last_version
  @last_version ||= wiki.repository.last_commit_for_path(wiki.default_branch, page.path) if page
end

#latest?Boolean

Returns boolean True or False if this instance is the latest commit version of the page.

Returns:

  • (Boolean)


180
181
182
# File 'app/models/wiki_page.rb', line 180

def latest?
  !historical?
end

#messageObject

The commit message for this page version.



120
121
122
# File 'app/models/wiki_page.rb', line 120

def message
  version.try(:message)
end

#pathObject



131
132
133
134
135
# File 'app/models/wiki_page.rb', line 131

def path
  return unless persisted?

  @path ||= @page.path
end

#persisted?Boolean

Returns boolean True or False if this instance has been fully created on disk or not.

Returns:

  • (Boolean)


186
187
188
# File 'app/models/wiki_page.rb', line 186

def persisted?
  page.present?
end

#raw_contentObject



98
99
100
# File 'app/models/wiki_page.rb', line 98

def raw_content
  attributes[:content] ||= page&.text_data
end

#raw_content=(content) ⇒ Object



102
103
104
105
106
107
# File 'app/models/wiki_page.rb', line 102

def raw_content=(content)
  return if page.nil?

  page.raw_data = content
  attributes[:content] = page.text_data
end

#shaObject



267
268
269
# File 'app/models/wiki_page.rb', line 267

def sha
  page.version&.sha
end

#slugObject Also known as: id, to_param

The escaped URL path of this page.



75
76
77
# File 'app/models/wiki_page.rb', line 75

def slug
  attributes[:slug].presence || ::Wiki.preview_slug(title, format)
end

#titleObject

The formatted title of this page.



89
90
91
# File 'app/models/wiki_page.rb', line 89

def title
  attributes[:title] || ''
end

#title=(new_title) ⇒ Object

Sets the title of this page.



94
95
96
# File 'app/models/wiki_page.rb', line 94

def title=(new_title)
  attributes[:title] = new_title
end

#title_changed?Boolean

Returns:

  • (Boolean)


271
272
273
274
275
276
277
278
279
280
281
282
283
# File 'app/models/wiki_page.rb', line 271

def title_changed?
  if persisted?
    # A page's `title` will be returned from Gollum/Gitaly with any +<>
    # characters changed to -, whereas the `path` preserves these characters.
    path_without_extension = Pathname(page.path).sub_ext('').to_s
    old_title, old_dir = wiki.page_title_and_dir(self.class.unhyphenize(path_without_extension))
    new_title, new_dir = wiki.page_title_and_dir(self.class.unhyphenize(title))

    new_title != old_title || (title.include?('/') && new_dir != old_dir)
  else
    title.present?
  end
end

#to_ability_nameObject



306
307
308
# File 'app/models/wiki_page.rb', line 306

def to_ability_name
  'wiki_page'
end

#to_keyObject



38
39
40
# File 'app/models/wiki_page.rb', line 38

def to_key
  [:slug]
end

#to_partial_pathObject

Relative path to the partial to be used when rendering collections of this object.



263
264
265
# File 'app/models/wiki_page.rb', line 263

def to_partial_path
  'shared/wikis/wiki_page'
end

#update(attrs = {}) ⇒ Object

Updates an existing Wiki Page, creating a 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 Wiki::VALID_USER_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.



224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
# File 'app/models/wiki_page.rb', line 224

def update(attrs = {})
  last_commit_sha = attrs.delete(:last_commit_sha)

  if last_commit_sha && last_commit_sha != self.last_commit_sha
    raise PageChangedError, s_(
      'WikiPageConflictMessage|Someone edited the page the same time you did. Please check out %{wikiLinkStart}the page%{wikiLinkEnd} and make sure your changes will not unintentionally remove theirs.')
  end

  update_attributes(attrs)

  if title.present? && title_changed? && wiki.find_page(title, load_content: false).present?
    attributes[:title] = page.title
    raise PageRenameError, s_('WikiEdit|There is already a page with the same title in that path.')
  end

  save do
    wiki.update_page(
      page,
      content: raw_content,
      format: format,
      message: attrs[:message],
      title: title
    )
  end
end

#update_attributes(attrs) ⇒ Object

Updates the current @attributes hash by merging a hash of params



296
297
298
299
300
301
302
303
304
# File 'app/models/wiki_page.rb', line 296

def update_attributes(attrs)
  attrs[:title] = process_title(attrs[:title]) if attrs[:title].present?
  update_front_matter(attrs)

  attrs.slice!(:content, :format, :message, :title)
  clear_memoization(:parsed_content) if attrs.has_key?(:content)

  attributes.merge!(attrs)
end

#versionObject

The GitLab Commit instance for this page.



125
126
127
128
129
# File 'app/models/wiki_page.rb', line 125

def version
  return unless persisted?

  @version ||= @page.version || last_version
end

#version_commit_timestampObject



310
311
312
# File 'app/models/wiki_page.rb', line 310

def version_commit_timestamp
  version&.commit&.committed_date
end

#versions(options = {}) ⇒ Object

Returns a CommitCollection

Queries the commits for current page’s path, equivalent to ‘git log path/to/page`. Filters and options supported: gitlab.com/gitlab-org/gitaly/-/blob/master/proto/commit.proto#L322-344



142
143
144
145
146
147
148
149
150
151
152
153
154
# File 'app/models/wiki_page.rb', line 142

def versions(options = {})
  return [] unless persisted?

  default_per_page = Kaminari.config.default_per_page
  offset = [options[:page].to_i - 1, 0].max * options.fetch(:per_page, default_per_page)

  wiki.repository.commits(
    wiki.default_branch,
    path: page.path,
    limit: options.fetch(:limit, default_per_page),
    offset: offset
  )
end