To check out this repository please hg clone the following URL, or open the URL using EasyMercurial or your preferred Mercurial client.
root / .svn / pristine / 20 / 2069c7a6894bd57d0791bf6d175776952425d0ca.svn-base @ 1297:0a574315af3e
History | View | Annotate | Download (11.8 KB)
| 1 | 1296:038ba2d95de8 | Chris | # Redmine - project management software |
|---|---|---|---|
| 2 | # Copyright (C) 2006-2012 Jean-Philippe Lang |
||
| 3 | # |
||
| 4 | # This program is free software; you can redistribute it and/or |
||
| 5 | # modify it under the terms of the GNU General Public License |
||
| 6 | # as published by the Free Software Foundation; either version 2 |
||
| 7 | # of the License, or (at your option) any later version. |
||
| 8 | # |
||
| 9 | # This program is distributed in the hope that it will be useful, |
||
| 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
| 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||
| 12 | # GNU General Public License for more details. |
||
| 13 | # |
||
| 14 | # You should have received a copy of the GNU General Public License |
||
| 15 | # along with this program; if not, write to the Free Software |
||
| 16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
||
| 17 | |||
| 18 | require 'diff' |
||
| 19 | |||
| 20 | # The WikiController follows the Rails REST controller pattern but with |
||
| 21 | # a few differences |
||
| 22 | # |
||
| 23 | # * index - shows a list of WikiPages grouped by page or date |
||
| 24 | # * new - not used |
||
| 25 | # * create - not used |
||
| 26 | # * show - will also show the form for creating a new wiki page |
||
| 27 | # * edit - used to edit an existing or new page |
||
| 28 | # * update - used to save a wiki page update to the database, including new pages |
||
| 29 | # * destroy - normal |
||
| 30 | # |
||
| 31 | # Other member and collection methods are also used |
||
| 32 | # |
||
| 33 | # TODO: still being worked on |
||
| 34 | class WikiController < ApplicationController |
||
| 35 | default_search_scope :wiki_pages |
||
| 36 | before_filter :find_wiki, :authorize |
||
| 37 | before_filter :find_existing_or_new_page, :only => [:show, :edit, :update] |
||
| 38 | before_filter :find_existing_page, :only => [:rename, :protect, :history, :diff, :annotate, :add_attachment, :destroy, :destroy_version] |
||
| 39 | accept_api_auth :index, :show, :update, :destroy |
||
| 40 | |||
| 41 | helper :attachments |
||
| 42 | include AttachmentsHelper |
||
| 43 | helper :watchers |
||
| 44 | include Redmine::Export::PDF |
||
| 45 | |||
| 46 | # List of pages, sorted alphabetically and by parent (hierarchy) |
||
| 47 | def index |
||
| 48 | load_pages_for_index |
||
| 49 | |||
| 50 | respond_to do |format| |
||
| 51 | format.html {
|
||
| 52 | @pages_by_parent_id = @pages.group_by(&:parent_id) |
||
| 53 | } |
||
| 54 | format.api |
||
| 55 | end |
||
| 56 | end |
||
| 57 | |||
| 58 | # List of page, by last update |
||
| 59 | def date_index |
||
| 60 | load_pages_for_index |
||
| 61 | @pages_by_date = @pages.group_by {|p| p.updated_on.to_date}
|
||
| 62 | end |
||
| 63 | |||
| 64 | # display a page (in editing mode if it doesn't exist) |
||
| 65 | def show |
||
| 66 | if @page.new_record? |
||
| 67 | if User.current.allowed_to?(:edit_wiki_pages, @project) && editable? && !api_request? |
||
| 68 | edit |
||
| 69 | render :action => 'edit' |
||
| 70 | else |
||
| 71 | render_404 |
||
| 72 | end |
||
| 73 | return |
||
| 74 | end |
||
| 75 | if params[:version] && !User.current.allowed_to?(:view_wiki_edits, @project) |
||
| 76 | deny_access |
||
| 77 | return |
||
| 78 | end |
||
| 79 | @content = @page.content_for_version(params[:version]) |
||
| 80 | if User.current.allowed_to?(:export_wiki_pages, @project) |
||
| 81 | if params[:format] == 'pdf' |
||
| 82 | send_data(wiki_page_to_pdf(@page, @project), :type => 'application/pdf', :filename => "#{@page.title}.pdf")
|
||
| 83 | return |
||
| 84 | elsif params[:format] == 'html' |
||
| 85 | export = render_to_string :action => 'export', :layout => false |
||
| 86 | send_data(export, :type => 'text/html', :filename => "#{@page.title}.html")
|
||
| 87 | return |
||
| 88 | elsif params[:format] == 'txt' |
||
| 89 | send_data(@content.text, :type => 'text/plain', :filename => "#{@page.title}.txt")
|
||
| 90 | return |
||
| 91 | end |
||
| 92 | end |
||
| 93 | @editable = editable? |
||
| 94 | @sections_editable = @editable && User.current.allowed_to?(:edit_wiki_pages, @page.project) && |
||
| 95 | @content.current_version? && |
||
| 96 | Redmine::WikiFormatting.supports_section_edit? |
||
| 97 | |||
| 98 | respond_to do |format| |
||
| 99 | format.html |
||
| 100 | format.api |
||
| 101 | end |
||
| 102 | end |
||
| 103 | |||
| 104 | # edit an existing page or a new one |
||
| 105 | def edit |
||
| 106 | return render_403 unless editable? |
||
| 107 | if @page.new_record? |
||
| 108 | @page.content = WikiContent.new(:page => @page) |
||
| 109 | if params[:parent].present? |
||
| 110 | @page.parent = @page.wiki.find_page(params[:parent].to_s) |
||
| 111 | end |
||
| 112 | end |
||
| 113 | |||
| 114 | @content = @page.content_for_version(params[:version]) |
||
| 115 | @content.text = initial_page_content(@page) if @content.text.blank? |
||
| 116 | # don't keep previous comment |
||
| 117 | @content.comments = nil |
||
| 118 | |||
| 119 | # To prevent StaleObjectError exception when reverting to a previous version |
||
| 120 | @content.version = @page.content.version |
||
| 121 | |||
| 122 | @text = @content.text |
||
| 123 | if params[:section].present? && Redmine::WikiFormatting.supports_section_edit? |
||
| 124 | @section = params[:section].to_i |
||
| 125 | @text, @section_hash = Redmine::WikiFormatting.formatter.new(@text).get_section(@section) |
||
| 126 | render_404 if @text.blank? |
||
| 127 | end |
||
| 128 | end |
||
| 129 | |||
| 130 | # Creates a new page or updates an existing one |
||
| 131 | def update |
||
| 132 | return render_403 unless editable? |
||
| 133 | was_new_page = @page.new_record? |
||
| 134 | @page.content = WikiContent.new(:page => @page) if @page.new_record? |
||
| 135 | @page.safe_attributes = params[:wiki_page] |
||
| 136 | |||
| 137 | @content = @page.content |
||
| 138 | content_params = params[:content] |
||
| 139 | if content_params.nil? && params[:wiki_page].is_a?(Hash) |
||
| 140 | content_params = params[:wiki_page].slice(:text, :comments, :version) |
||
| 141 | end |
||
| 142 | content_params ||= {}
|
||
| 143 | |||
| 144 | @content.comments = content_params[:comments] |
||
| 145 | @text = content_params[:text] |
||
| 146 | if params[:section].present? && Redmine::WikiFormatting.supports_section_edit? |
||
| 147 | @section = params[:section].to_i |
||
| 148 | @section_hash = params[:section_hash] |
||
| 149 | @content.text = Redmine::WikiFormatting.formatter.new(@content.text).update_section(params[:section].to_i, @text, @section_hash) |
||
| 150 | else |
||
| 151 | @content.version = content_params[:version] if content_params[:version] |
||
| 152 | @content.text = @text |
||
| 153 | end |
||
| 154 | @content.author = User.current |
||
| 155 | |||
| 156 | if @page.save_with_content |
||
| 157 | attachments = Attachment.attach_files(@page, params[:attachments]) |
||
| 158 | render_attachment_warning_if_needed(@page) |
||
| 159 | call_hook(:controller_wiki_edit_after_save, { :params => params, :page => @page})
|
||
| 160 | |||
| 161 | respond_to do |format| |
||
| 162 | format.html { redirect_to :action => 'show', :project_id => @project, :id => @page.title }
|
||
| 163 | format.api {
|
||
| 164 | if was_new_page |
||
| 165 | render :action => 'show', :status => :created, :location => url_for(:controller => 'wiki', :action => 'show', :project_id => @project, :id => @page.title) |
||
| 166 | else |
||
| 167 | render_api_ok |
||
| 168 | end |
||
| 169 | } |
||
| 170 | end |
||
| 171 | else |
||
| 172 | respond_to do |format| |
||
| 173 | format.html { render :action => 'edit' }
|
||
| 174 | format.api { render_validation_errors(@content) }
|
||
| 175 | end |
||
| 176 | end |
||
| 177 | |||
| 178 | rescue ActiveRecord::StaleObjectError, Redmine::WikiFormatting::StaleSectionError |
||
| 179 | # Optimistic locking exception |
||
| 180 | respond_to do |format| |
||
| 181 | format.html {
|
||
| 182 | flash.now[:error] = l(:notice_locking_conflict) |
||
| 183 | render :action => 'edit' |
||
| 184 | } |
||
| 185 | format.api { render_api_head :conflict }
|
||
| 186 | end |
||
| 187 | rescue ActiveRecord::RecordNotSaved |
||
| 188 | respond_to do |format| |
||
| 189 | format.html { render :action => 'edit' }
|
||
| 190 | format.api { render_validation_errors(@content) }
|
||
| 191 | end |
||
| 192 | end |
||
| 193 | |||
| 194 | # rename a page |
||
| 195 | def rename |
||
| 196 | return render_403 unless editable? |
||
| 197 | @page.redirect_existing_links = true |
||
| 198 | # used to display the *original* title if some AR validation errors occur |
||
| 199 | @original_title = @page.pretty_title |
||
| 200 | if request.post? && @page.update_attributes(params[:wiki_page]) |
||
| 201 | flash[:notice] = l(:notice_successful_update) |
||
| 202 | redirect_to :action => 'show', :project_id => @project, :id => @page.title |
||
| 203 | end |
||
| 204 | end |
||
| 205 | |||
| 206 | def protect |
||
| 207 | @page.update_attribute :protected, params[:protected] |
||
| 208 | redirect_to :action => 'show', :project_id => @project, :id => @page.title |
||
| 209 | end |
||
| 210 | |||
| 211 | # show page history |
||
| 212 | def history |
||
| 213 | @version_count = @page.content.versions.count |
||
| 214 | @version_pages = Paginator.new self, @version_count, per_page_option, params['page'] |
||
| 215 | # don't load text |
||
| 216 | @versions = @page.content.versions.find :all, |
||
| 217 | :select => "id, author_id, comments, updated_on, version", |
||
| 218 | :order => 'version DESC', |
||
| 219 | :limit => @version_pages.items_per_page + 1, |
||
| 220 | :offset => @version_pages.current.offset |
||
| 221 | |||
| 222 | render :layout => false if request.xhr? |
||
| 223 | end |
||
| 224 | |||
| 225 | def diff |
||
| 226 | @diff = @page.diff(params[:version], params[:version_from]) |
||
| 227 | render_404 unless @diff |
||
| 228 | end |
||
| 229 | |||
| 230 | def annotate |
||
| 231 | @annotate = @page.annotate(params[:version]) |
||
| 232 | render_404 unless @annotate |
||
| 233 | end |
||
| 234 | |||
| 235 | # Removes a wiki page and its history |
||
| 236 | # Children can be either set as root pages, removed or reassigned to another parent page |
||
| 237 | def destroy |
||
| 238 | return render_403 unless editable? |
||
| 239 | |||
| 240 | @descendants_count = @page.descendants.size |
||
| 241 | if @descendants_count > 0 |
||
| 242 | case params[:todo] |
||
| 243 | when 'nullify' |
||
| 244 | # Nothing to do |
||
| 245 | when 'destroy' |
||
| 246 | # Removes all its descendants |
||
| 247 | @page.descendants.each(&:destroy) |
||
| 248 | when 'reassign' |
||
| 249 | # Reassign children to another parent page |
||
| 250 | reassign_to = @wiki.pages.find_by_id(params[:reassign_to_id].to_i) |
||
| 251 | return unless reassign_to |
||
| 252 | @page.children.each do |child| |
||
| 253 | child.update_attribute(:parent, reassign_to) |
||
| 254 | end |
||
| 255 | else |
||
| 256 | @reassignable_to = @wiki.pages - @page.self_and_descendants |
||
| 257 | # display the destroy form if it's a user request |
||
| 258 | return unless api_request? |
||
| 259 | end |
||
| 260 | end |
||
| 261 | @page.destroy |
||
| 262 | respond_to do |format| |
||
| 263 | format.html { redirect_to :action => 'index', :project_id => @project }
|
||
| 264 | format.api { render_api_ok }
|
||
| 265 | end |
||
| 266 | end |
||
| 267 | |||
| 268 | def destroy_version |
||
| 269 | return render_403 unless editable? |
||
| 270 | |||
| 271 | @content = @page.content_for_version(params[:version]) |
||
| 272 | @content.destroy |
||
| 273 | redirect_to_referer_or :action => 'history', :id => @page.title, :project_id => @project |
||
| 274 | end |
||
| 275 | |||
| 276 | # Export wiki to a single pdf or html file |
||
| 277 | def export |
||
| 278 | @pages = @wiki.pages.all(:order => 'title', :include => [:content, {:attachments => :author}])
|
||
| 279 | respond_to do |format| |
||
| 280 | format.html {
|
||
| 281 | export = render_to_string :action => 'export_multiple', :layout => false |
||
| 282 | send_data(export, :type => 'text/html', :filename => "wiki.html") |
||
| 283 | } |
||
| 284 | format.pdf {
|
||
| 285 | send_data(wiki_pages_to_pdf(@pages, @project), :type => 'application/pdf', :filename => "#{@project.identifier}.pdf")
|
||
| 286 | } |
||
| 287 | end |
||
| 288 | end |
||
| 289 | |||
| 290 | def preview |
||
| 291 | page = @wiki.find_page(params[:id]) |
||
| 292 | # page is nil when previewing a new page |
||
| 293 | return render_403 unless page.nil? || editable?(page) |
||
| 294 | if page |
||
| 295 | @attachements = page.attachments |
||
| 296 | @previewed = page.content |
||
| 297 | end |
||
| 298 | @text = params[:content][:text] |
||
| 299 | render :partial => 'common/preview' |
||
| 300 | end |
||
| 301 | |||
| 302 | def add_attachment |
||
| 303 | return render_403 unless editable? |
||
| 304 | attachments = Attachment.attach_files(@page, params[:attachments]) |
||
| 305 | render_attachment_warning_if_needed(@page) |
||
| 306 | redirect_to :action => 'show', :id => @page.title, :project_id => @project |
||
| 307 | end |
||
| 308 | |||
| 309 | private |
||
| 310 | |||
| 311 | def find_wiki |
||
| 312 | @project = Project.find(params[:project_id]) |
||
| 313 | @wiki = @project.wiki |
||
| 314 | render_404 unless @wiki |
||
| 315 | rescue ActiveRecord::RecordNotFound |
||
| 316 | render_404 |
||
| 317 | end |
||
| 318 | |||
| 319 | # Finds the requested page or a new page if it doesn't exist |
||
| 320 | def find_existing_or_new_page |
||
| 321 | @page = @wiki.find_or_new_page(params[:id]) |
||
| 322 | if @wiki.page_found_with_redirect? |
||
| 323 | redirect_to params.update(:id => @page.title) |
||
| 324 | end |
||
| 325 | end |
||
| 326 | |||
| 327 | # Finds the requested page and returns a 404 error if it doesn't exist |
||
| 328 | def find_existing_page |
||
| 329 | @page = @wiki.find_page(params[:id]) |
||
| 330 | if @page.nil? |
||
| 331 | render_404 |
||
| 332 | return |
||
| 333 | end |
||
| 334 | if @wiki.page_found_with_redirect? |
||
| 335 | redirect_to params.update(:id => @page.title) |
||
| 336 | end |
||
| 337 | end |
||
| 338 | |||
| 339 | # Returns true if the current user is allowed to edit the page, otherwise false |
||
| 340 | def editable?(page = @page) |
||
| 341 | page.editable_by?(User.current) |
||
| 342 | end |
||
| 343 | |||
| 344 | # Returns the default content of a new wiki page |
||
| 345 | def initial_page_content(page) |
||
| 346 | helper = Redmine::WikiFormatting.helper_for(Setting.text_formatting) |
||
| 347 | extend helper unless self.instance_of?(helper) |
||
| 348 | helper.instance_method(:initial_page_content).bind(self).call(page) |
||
| 349 | end |
||
| 350 | |||
| 351 | def load_pages_for_index |
||
| 352 | @pages = @wiki.pages.with_updated_on.order("#{WikiPage.table_name}.title").includes(:wiki => :project).includes(:parent).all
|
||
| 353 | end |
||
| 354 | end |