BigW Consortium Gitlab

wiki_page.rb 5.84 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14
class WikiPage
  include ActiveModel::Validations
  include ActiveModel::Conversion
  include StaticModel
  extend ActiveModel::Naming

  def self.primary_key
    'slug'
  end

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

15 16 17 18
  # Sorts and groups pages by directory.
  #
  # pages - an array of WikiPage objects.
  #
19 20 21
  # Returns an array of WikiPage and WikiDirectory objects. The entries are
  # sorted by alphabetical order (directories and pages inside each directory).
  # Pages at the root level come before everything.
22
  def self.group_by_directory(pages)
23 24
    return [] if pages.blank?

25
    pages.sort_by { |page| [page.directory, page.slug] }.
26
      group_by(&:directory).
27
      map do |dir, pages|
28
        if dir.present?
29
          WikiDirectory.new(dir, pages)
30 31
        else
          pages
32 33 34
        end
      end.
      flatten
35 36
  end

37 38 39 40
  def self.unhyphenize(name)
    name.gsub(/-+/, ' ')
  end

41 42 43 44 45 46 47
  def to_key
    [:slug]
  end

  validates :title, presence: true
  validates :content, presence: true

48
  # The Gitlab ProjectWiki instance.
49 50 51 52 53 54 55 56 57
  attr_reader :wiki

  # The raw Gollum::Page instance.
  attr_reader :page

  # The attributes Hash used for storing and validating
  # new Page values before writing to the Gollum repository.
  attr_accessor :attributes

58 59 60 61
  def hook_attrs
    attributes
  end

62 63 64 65 66 67 68 69 70 71 72
  def initialize(wiki, page = nil, persisted = false)
    @wiki       = wiki
    @page       = page
    @persisted  = persisted
    @attributes = {}.with_indifferent_access

    set_attributes if persisted?
  end

  # The escaped URL path of this page.
  def slug
73 74 75 76 77
    if @attributes[:slug].present?
      @attributes[:slug]
    else
      wiki.wiki.preview_page(title, '', format).url_path
    end
78 79
  end

80
  alias_method :to_param, :slug
81 82 83

  # The formatted title of this page.
  def title
84
    if @attributes[:title]
85
      self.class.unhyphenize(@attributes[:title])
86 87 88
    else
      ""
    end
89 90 91 92 93 94 95 96 97
  end

  # Sets the title of this page.
  def title=(new_title)
    @attributes[:title] = new_title
  end

  # The raw content of this page.
  def content
98
    @attributes[:content] ||= @page&.text_data
99 100
  end

101 102
  # The hierarchy of the directory this page is contained in.
  def directory
103
    wiki.page_title_and_dir(slug).last
104 105
  end

106 107
  # The processed/formatted content of this page.
  def formatted_content
108
    @attributes[:formatted_content] ||= @page&.formatted_data
109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124
  end

  # The markup format for the page.
  def format
    @attributes[:format] || :markdown
  end

  # The commit message for this page version.
  def message
    version.try(:message)
  end

  # The Gitlab Commit instance for this page.
  def version
    return nil unless persisted?

Dmitriy Zaporozhets committed
125
    @version ||= @page.version
126 127 128 129 130 131
  end

  # Returns an array of Gitlab Commit instances.
  def versions
    return [] unless persisted?

Dmitriy Zaporozhets committed
132
    @page.versions
133 134
  end

135 136 137 138
  def commit
    versions.first
  end

139 140 141 142 143 144 145 146 147
  # Returns the Date that this latest version was
  # created on.
  def created_at
    @page.version.date
  end

  # Returns boolean True or False if this instance
  # is an old version of the page.
  def historical?
148
    @page.historical? && versions.first.sha != version.sha
149 150
  end

151 152 153 154 155 156
  # Returns boolean True or False if this instance
  # is the latest commit version of the page.
  def latest?
    !historical?
  end

157
  # Returns boolean True or False if this instance
Dongqing Hu committed
158
  # has been fully created on disk or not.
159 160 161 162 163 164 165 166 167 168 169
  def persisted?
    @persisted == true
  end

  # Creates a new Wiki Page.
  #
  # attr - Hash of attributes to set on the new page.
  #       :title   - The title for the new page.
  #       :content - The raw markup content.
  #       :format  - Optional symbol representing the
  #                  content format. Can be any type
170
  #                  listed in the ProjectWiki::MARKUPS
171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186
  #                  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.
  def create(attr = {})
    @attributes.merge!(attr)

    save :create_page, title, content, format, message
  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.
187
  #               See ProjectWiki::MARKUPS Hash for available formats.
188 189 190 191 192 193 194 195 196 197 198
  # message     - Optional commit message to set on the new version.
  #
  # 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

    save :update_page, @page, content, format, message
  end

Johannes Schleifenbaum committed
199
  # Destroys the Wiki Page.
200 201 202 203 204 205 206 207 208 209
  #
  # Returns boolean True or False.
  def delete
    if wiki.delete_page(@page)
      true
    else
      false
    end
  end

210 211 212 213 214 215
  # Relative path to the partial to be used when rendering collections
  # of this object.
  def to_partial_path
    'projects/wikis/wiki_page'
  end

216 217 218 219
  def id
    page.version.to_s
  end

220 221 222
  private

  def set_attributes
223
    attributes[:slug] = @page.url_path
224 225 226 227 228
    attributes[:title] = @page.title
    attributes[:format] = @page.format
  end

  def save(method, *args)
Dongqing Hu committed
229 230
    saved = false

231 232
    project_wiki = wiki
    if valid? && project_wiki.send(method, *args)
233 234

      page_details = if method == :update_page
235 236
                       # Use url_path instead of path to omit format extension
                       @page.url_path
237 238 239 240
                     else
                       title
                     end

241 242 243
      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)
244 245 246 247

      set_attributes

      @persisted = true
Dongqing Hu committed
248
      saved = true
249
    else
250
      errors.add(:base, project_wiki.error_message) if project_wiki.error_message
251
    end
Dongqing Hu committed
252
    saved
253 254
  end
end