Class: WikiController

Inherits:
ApplicationController show all
Includes:
AttachmentsHelper, Redmine::Export::PDF
Defined in:
app/controllers/wiki_controller.rb

Overview

The WikiController follows the Rails REST controller pattern but with a few differences

  • index - shows a list of WikiPages grouped by page or date

  • new - not used

  • create - not used

  • show - will also show the form for creating a new wiki page

  • edit - used to edit an existing or new page

  • update - used to save a wiki page update to the database, including new pages

  • destroy - normal

Other member and collection methods are also used

TODO: still being worked on

Constant Summary

Constants included from ApplicationHelper

ApplicationHelper::HEADING_RE, ApplicationHelper::MACROS_RE, ApplicationHelper::MACRO_SUB_RE, ApplicationHelper::TOC_RE

Instance Method Summary collapse

Methods included from Redmine::Export::PDF

#calc_col_width, #fetch_row_values, #get_issues_to_pdf_write_cells, #is_cjk?, #issue_to_pdf, #issues_to_pdf, #issues_to_pdf_draw_borders, #issues_to_pdf_write_cells, #render_table_header, #wiki_page_to_pdf, #wiki_pages_to_pdf, #write_page_hierarchy, #write_wiki_page

Methods included from IssuesHelper

#bulk_edit_error_messages, #details_to_strings, #email_issue_attributes, #find_name_by_reflection, #issue_fields_rows, #issue_heading, #issue_list, #issues_destroy_confirmation_message, #link_to_new_subtask, #query_links, #render_api_issue_children, #render_custom_fields_rows, #render_descendants_tree, #render_email_issue_attributes, #render_issue_subject_with_tree, #render_issue_tooltip, #render_sidebar_queries, #show_detail, #sidebar_queries

Methods included from ApplicationHelper

#accesskey, #anchor, #api_meta, #authoring, #authorize_for, #avatar, #back_url, #back_url_hidden_field_tag, #body_css_classes, #breadcrumb, #calendar_for, #catch_macros, #check_all_links, #checked_image, #context_menu, #current_theme, #delete_link, #due_date_distance_in_words, #email_delivery_enabled?, #error_messages_for, #favicon, #favicon_path, #favicon_url, #format_activity_day, #format_activity_description, #format_activity_title, #format_object, #format_version_name, #heads_for_theme, #html_hours, #html_title, #image_tag, #include_calendar_headers_tags, #include_in_api_response?, #inject_macros, #javascript_heads, #javascript_include_tag, #labelled_fields_for, #labelled_form_for, #lang_options_for_select, #link_to_attachment, #link_to_function, #link_to_if_authorized, #link_to_issue, #link_to_message, #link_to_project, #link_to_project_settings, #link_to_revision, #link_to_user, #link_to_version, #option_tag, #other_formats_links, #page_header_title, #parse_headings, #parse_inline_attachments, #parse_non_pre_blocks, #parse_redmine_links, #parse_sections, #parse_wiki_links, #preview_link, #principals_check_box_tags, #principals_options_for_select, #progress_bar, #project_tree, #project_tree_options_for_select, #raw_json, #render_flash_messages, #render_page_hierarchy, #render_project_jump_box, #render_project_nested_lists, #render_tabs, #reorder_links, #replace_toc, #robot_exclusion_tag, #sanitize_anchor_name, #sidebar_content?, #simple_format_without_paragraph, #stylesheet_link_tag, #syntax_highlight, #syntax_highlight_lines, #textilizable, #thumbnail_tag, #time_tag, #title, #to_path_param, #toggle_checkboxes_link, #toggle_link, #truncate_lines, #truncate_single_line_raw, #view_layouts_base_sidebar_hook_response, #wiki_page_path

Methods included from Redmine::Pagination::Helper

#pagination_links_each, #pagination_links_full, #per_page_links, #per_page_options

Methods included from Redmine::I18n

#current_language, #day_letter, #day_name, #find_language, #format_date, #format_time, included, #l, #l_hours, #l_or_humanize, #languages_options, #ll, #month_name, #set_language_if_valid, #valid_languages

Methods included from GravatarHelper::PublicMethods

#gravatar, #gravatar_api_url, #gravatar_for, #gravatar_url

Methods included from Redmine::WikiFormatting::Macros::Definitions

#exec_macro, #extract_macro_options, #macro_exists?

Methods included from AttachmentsHelper

#container_attachments_edit_path, #container_attachments_path, #link_to_attachments, #render_api_attachment

Methods inherited from ApplicationController

#_include_layout?, accept_api_auth, #accept_api_auth?, accept_rss_auth, #accept_rss_auth?, #api_key_from_request, #api_offset_and_limit, #api_request?, #api_switch_user_from_request, #authorize, #authorize_global, #autologin_cookie_name, #back_url, #check_if_login_required, #check_password_change, #check_project_privacy, #deny_access, #filename_for_content_disposition, #find_attachments, #find_current_user, #find_issue, #find_issues, #find_model_object, #find_optional_project, #find_project, #find_project_by_project_id, #find_project_from_association, #force_logout_if_password_changed, #handle_unverified_request, #logged_user=, #logout_user, #missing_template, model_object, #parse_qvalues, #per_page_option, #query_statement_invalid, #redirect_back_or_default, #redirect_to_referer_or, #render_403, #render_404, #render_api_head, #render_api_ok, #render_attachment_warning_if_needed, #render_error, #render_feed, #render_validation_errors, #require_admin, #require_admin_or_api_request, #require_login, #session_expiration, #session_expired?, #set_localization, #start_user_session, #try_to_autologin, #use_layout, #user_setup, #verify_authenticity_token

Methods included from Redmine::MenuManager::MenuController

#current_menu_item, included, #menu_items, #redirect_to_project_menu_item

Methods included from Redmine::Search::Controller

#default_search_scope, #default_search_scopes, included

Methods included from RoutesHelper

#_new_time_entry_path, #_project_calendar_path, #_project_gantt_path, #_project_issues_path, #_report_time_entries_path, #_time_entries_path

Methods included from Redmine::Pagination

#deprecated_paginate, #paginate, #paginator

Instance Method Details

#add_attachmentObject


305
306
307
308
309
310
# File 'app/controllers/wiki_controller.rb', line 305

def add_attachment
  return render_403 unless editable?
  attachments = Attachment.attach_files(@page, params[:attachments])
  render_attachment_warning_if_needed(@page)
  redirect_to :action => 'show', :id => @page.title, :project_id => @project
end

#annotateObject


228
229
230
231
# File 'app/controllers/wiki_controller.rb', line 228

def annotate
  @annotate = @page.annotate(params[:version])
  render_404 unless @annotate
end

#date_indexObject

List of page, by last update


58
59
60
61
# File 'app/controllers/wiki_controller.rb', line 58

def date_index
  load_pages_for_index
  @pages_by_date = @pages.group_by {|p| p.updated_on.to_date}
end

#destroyObject

Removes a wiki page and its history Children can be either set as root pages, removed or reassigned to another parent page


235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
# File 'app/controllers/wiki_controller.rb', line 235

def destroy
  return render_403 unless editable?

  @descendants_count = @page.descendants.size
  if @descendants_count > 0
    case params[:todo]
    when 'nullify'
      # Nothing to do
    when 'destroy'
      # Removes all its descendants
      @page.descendants.each(&:destroy)
    when 'reassign'
      # Reassign children to another parent page
      reassign_to = @wiki.pages.find_by_id(params[:reassign_to_id].to_i)
      return unless reassign_to
      @page.children.each do |child|
        child.update_attribute(:parent, reassign_to)
      end
    else
      @reassignable_to = @wiki.pages - @page.self_and_descendants
      # display the destroy form if it's a user request
      return unless api_request?
    end
  end
  @page.destroy
  respond_to do |format|
    format.html { redirect_to project_wiki_index_path(@project) }
    format.api { render_api_ok }
  end
end

#destroy_versionObject


266
267
268
269
270
271
272
# File 'app/controllers/wiki_controller.rb', line 266

def destroy_version
  return render_403 unless editable?

  @content = @page.content_for_version(params[:version])
  @content.destroy
  redirect_to_referer_or history_project_wiki_page_path(@project, @page.title)
end

#diffObject


223
224
225
226
# File 'app/controllers/wiki_controller.rb', line 223

def diff
  @diff = @page.diff(params[:version], params[:version_from])
  render_404 unless @diff
end

#editObject

edit an existing page or a new one


104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
# File 'app/controllers/wiki_controller.rb', line 104

def edit
  return render_403 unless editable?
  if @page.new_record?
    if params[:parent].present?
      @page.parent = @page.wiki.find_page(params[:parent].to_s)
    end
  end

  @content = @page.content_for_version(params[:version])
  @content ||= WikiContent.new(:page => @page)
  @content.text = initial_page_content(@page) if @content.text.blank?
  # don't keep previous comment
  @content.comments = nil

  # To prevent StaleObjectError exception when reverting to a previous version
  @content.version = @page.content.version if @page.content

  @text = @content.text
  if params[:section].present? && Redmine::WikiFormatting.supports_section_edit?
    @section = params[:section].to_i
    @text, @section_hash = Redmine::WikiFormatting.formatter.new(@text).get_section(@section)
    render_404 if @text.blank?
  end
end

#exportObject

Export wiki to a single pdf or html file


275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
# File 'app/controllers/wiki_controller.rb', line 275

def export
  @pages = @wiki.pages.
                    order('title').
                    includes([:content, {:attachments => :author}]).
                    to_a
  respond_to do |format|
    format.html {
      export = render_to_string :action => 'export_multiple', :layout => false
      send_data(export, :type => 'text/html', :filename => "wiki.html")
    }
    format.pdf {
      send_data(wiki_pages_to_pdf(@pages, @project),
                :type => 'application/pdf',
                :filename => "#{@project.identifier}.pdf")
    }
  end
end

#historyObject

show page history


209
210
211
212
213
214
215
216
217
218
219
220
221
# File 'app/controllers/wiki_controller.rb', line 209

def history
  @version_count = @page.content.versions.count
  @version_pages = Paginator.new @version_count, per_page_option, params['page']
  # don't load text
  @versions = @page.content.versions.
    select("id, author_id, comments, updated_on, version").
    reorder('version DESC').
    limit(@version_pages.per_page + 1).
    offset(@version_pages.offset).
    to_a

  render :layout => false if request.xhr?
end

#indexObject

List of pages, sorted alphabetically and by parent (hierarchy)


46
47
48
49
50
51
52
53
54
55
# File 'app/controllers/wiki_controller.rb', line 46

def index
  load_pages_for_index

  respond_to do |format|
    format.html {
      @pages_by_parent_id = @pages.group_by(&:parent_id)
    }
    format.api
  end
end

#previewObject


293
294
295
296
297
298
299
300
301
302
303
# File 'app/controllers/wiki_controller.rb', line 293

def preview
  page = @wiki.find_page(params[:id])
  # page is nil when previewing a new page
  return render_403 unless page.nil? || editable?(page)
  if page
    @attachments += page.attachments
    @previewed = page.content
  end
  @text = params[:content][:text]
  render :partial => 'common/preview'
end

#protectObject


203
204
205
206
# File 'app/controllers/wiki_controller.rb', line 203

def protect
  @page.update_attribute :protected, params[:protected]
  redirect_to project_wiki_page_path(@project, @page.title)
end

#renameObject

rename a page


191
192
193
194
195
196
197
198
199
200
201
# File 'app/controllers/wiki_controller.rb', line 191

def rename
  return render_403 unless editable?
  @page.redirect_existing_links = true
  # used to display the *original* title if some AR validation errors occur
  @original_title = @page.pretty_title
  @page.safe_attributes = params[:wiki_page]
  if request.post? && @page.save
    flash[:notice] = l(:notice_successful_update)
    redirect_to project_wiki_page_path(@page.project, @page.title)
  end
end

#showObject

display a page (in editing mode if it doesn't exist)


64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
# File 'app/controllers/wiki_controller.rb', line 64

def show
  if params[:version] && !User.current.allowed_to?(:view_wiki_edits, @project)
    deny_access
    return
  end
  @content = @page.content_for_version(params[:version])
  if @content.nil?
    if User.current.allowed_to?(:edit_wiki_pages, @project) && editable? && !api_request?
      edit
      render :action => 'edit'
    else
      render_404
    end
    return
  end
  if User.current.allowed_to?(:export_wiki_pages, @project)
    if params[:format] == 'pdf'
      send_data(wiki_page_to_pdf(@page, @project), :type => 'application/pdf', :filename => "#{@page.title}.pdf")
      return
    elsif params[:format] == 'html'
      export = render_to_string :action => 'export', :layout => false
      send_data(export, :type => 'text/html', :filename => "#{@page.title}.html")
      return
    elsif params[:format] == 'txt'
      send_data(@content.text, :type => 'text/plain', :filename => "#{@page.title}.txt")
      return
    end
  end
  @editable = editable?
  @sections_editable = @editable && User.current.allowed_to?(:edit_wiki_pages, @page.project) &&
    @content.current_version? &&
    Redmine::WikiFormatting.supports_section_edit?

  respond_to do |format|
    format.html
    format.api
  end
end

#updateObject

Creates a new page or updates an existing one


130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
# File 'app/controllers/wiki_controller.rb', line 130

def update
  return render_403 unless editable?
  was_new_page = @page.new_record?
  @page.safe_attributes = params[:wiki_page]

  @content = @page.content || WikiContent.new(:page => @page)
  content_params = params[:content]
  if content_params.nil? && params[:wiki_page].is_a?(Hash)
    content_params = params[:wiki_page].slice(:text, :comments, :version)
  end
  content_params ||= {}

  @content.comments = content_params[:comments]
  @text = content_params[:text]
  if params[:section].present? && Redmine::WikiFormatting.supports_section_edit?
    @section = params[:section].to_i
    @section_hash = params[:section_hash]
    @content.text = Redmine::WikiFormatting.formatter.new(@content.text).update_section(@section, @text, @section_hash)
  else
    @content.version = content_params[:version] if content_params[:version]
    @content.text = @text
  end
  @content.author = User.current

  if @page.save_with_content(@content)
    attachments = Attachment.attach_files(@page, params[:attachments])
    render_attachment_warning_if_needed(@page)
    call_hook(:controller_wiki_edit_after_save, { :params => params, :page => @page})

    respond_to do |format|
      format.html {
        anchor = @section ? "section-#{@section}" : nil
        redirect_to project_wiki_page_path(@project, @page.title, :anchor => anchor)
      }
      format.api {
        if was_new_page
          render :action => 'show', :status => :created, :location => project_wiki_page_path(@project, @page.title)
        else
          render_api_ok
        end
      }
    end
  else
    respond_to do |format|
      format.html { render :action => 'edit' }
      format.api { render_validation_errors(@content) }
    end
  end

rescue ActiveRecord::StaleObjectError, Redmine::WikiFormatting::StaleSectionError
  # Optimistic locking exception
  respond_to do |format|
    format.html {
      flash.now[:error] = l(:notice_locking_conflict)
      render :action => 'edit'
    }
    format.api { render_api_head :conflict }
  end
end