To check out this repository please hg clone the following URL, or open the URL using EasyMercurial or your preferred Mercurial client.

Statistics Download as Zip
| Branch: | Tag: | Revision:

root / app / controllers / wiki_controller.rb @ 437:102056ec2de9

History | View | Annotate | Download (9.91 KB)

1
# redMine - project management software
2
# Copyright (C) 2006-2007  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_page, :only => [:rename, :protect, :history, :diff, :annotate, :add_attachment, :destroy]
38
  
39
  verify :method => :post, :only => [:protect], :redirect_to => { :action => :show }
40

    
41
  helper :attachments
42
  include AttachmentsHelper   
43
  helper :watchers
44

    
45
  # List of pages, sorted alphabetically and by parent (hierarchy)
46
  def index
47
    load_pages_grouped_by_date_without_content
48
  end
49

    
50
  # display a page (in editing mode if it doesn't exist)
51
  def show
52
    page_title = params[:id]
53
    @page = @wiki.find_or_new_page(page_title)
54
    if @page.new_record?
55
      if User.current.allowed_to?(:edit_wiki_pages, @project) && editable?
56
        edit
57
        render :action => 'edit'
58
      else
59
        render_404
60
      end
61
      return
62
    end
63
    if params[:version] && !User.current.allowed_to?(:view_wiki_edits, @project)
64
      # Redirects user to the current version if he's not allowed to view previous versions
65
      redirect_to :version => nil
66
      return
67
    end
68
    @content = @page.content_for_version(params[:version])
69
    if User.current.allowed_to?(:export_wiki_pages, @project)
70
      if params[:format] == 'html'
71
        export = render_to_string :action => 'export', :layout => false
72
        send_data(export, :type => 'text/html', :filename => "#{@page.title}.html")
73
        return
74
      elsif params[:format] == 'txt'
75
        send_data(@content.text, :type => 'text/plain', :filename => "#{@page.title}.txt")
76
        return
77
      end
78
    end
79
    @editable = editable?
80
    render :action => 'show'
81
  end
82
  
83
  # edit an existing page or a new one
84
  def edit
85
    @page = @wiki.find_or_new_page(params[:id])    
86
    return render_403 unless editable?
87
    @page.content = WikiContent.new(:page => @page) if @page.new_record?
88
    
89
    @content = @page.content_for_version(params[:version])
90
    @content.text = initial_page_content(@page) if @content.text.blank?
91
    # don't keep previous comment
92
    @content.comments = nil
93

    
94
    # To prevent StaleObjectError exception when reverting to a previous version
95
    @content.version = @page.content.version
96
  rescue ActiveRecord::StaleObjectError
97
    # Optimistic locking exception
98
    flash[:error] = l(:notice_locking_conflict)
99
  end
100

    
101
  verify :method => :put, :only => :update, :render => {:nothing => true, :status => :method_not_allowed }
102
  # Creates a new page or updates an existing one
103
  def update
104
    @page = @wiki.find_or_new_page(params[:id])    
105
    return render_403 unless editable?
106
    @page.content = WikiContent.new(:page => @page) if @page.new_record?
107
    
108
    @content = @page.content_for_version(params[:version])
109
    @content.text = initial_page_content(@page) if @content.text.blank?
110
    # don't keep previous comment
111
    @content.comments = nil
112

    
113
    if !@page.new_record? && params[:content].present? && @content.text == params[:content][:text]
114
      attachments = Attachment.attach_files(@page, params[:attachments])
115
      render_attachment_warning_if_needed(@page)
116
      # don't save if text wasn't changed
117
      redirect_to :action => 'show', :project_id => @project, :id => @page.title
118
      return
119
    end
120
    @content.attributes = params[:content]
121
    @content.author = User.current
122
    # if page is new @page.save will also save content, but not if page isn't a new record
123
    if (@page.new_record? ? @page.save : @content.save)
124
      attachments = Attachment.attach_files(@page, params[:attachments])
125
      render_attachment_warning_if_needed(@page)
126
      call_hook(:controller_wiki_edit_after_save, { :params => params, :page => @page})
127
      redirect_to :action => 'show', :project_id => @project, :id => @page.title
128
    end
129

    
130
  rescue ActiveRecord::StaleObjectError
131
    # Optimistic locking exception
132
    flash[:error] = l(:notice_locking_conflict)
133
  end
134

    
135
  # rename a page
136
  def rename
137
    return render_403 unless editable?
138
    @page.redirect_existing_links = true
139
    # used to display the *original* title if some AR validation errors occur
140
    @original_title = @page.pretty_title
141
    if request.post? && @page.update_attributes(params[:wiki_page])
142
      flash[:notice] = l(:notice_successful_update)
143
      redirect_to :action => 'show', :project_id => @project, :id => @page.title
144
    end
145
  end
146
  
147
  def protect
148
    @page.update_attribute :protected, params[:protected]
149
    redirect_to :action => 'show', :project_id => @project, :id => @page.title
150
  end
151

    
152
  # show page history
153
  def history
154
    @version_count = @page.content.versions.count
155
    @version_pages = Paginator.new self, @version_count, per_page_option, params['p']
156
    # don't load text    
157
    @versions = @page.content.versions.find :all, 
158
                                            :select => "id, author_id, comments, updated_on, version",
159
                                            :order => 'version DESC',
160
                                            :limit  =>  @version_pages.items_per_page + 1,
161
                                            :offset =>  @version_pages.current.offset
162

    
163
    render :layout => false if request.xhr?
164
  end
165
  
166
  def diff
167
    @diff = @page.diff(params[:version], params[:version_from])
168
    render_404 unless @diff
169
  end
170
  
171
  def annotate
172
    @annotate = @page.annotate(params[:version])
173
    render_404 unless @annotate
174
  end
175

    
176
  verify :method => :delete, :only => [:destroy], :redirect_to => { :action => :show }
177
  # Removes a wiki page and its history
178
  # Children can be either set as root pages, removed or reassigned to another parent page
179
  def destroy
180
    return render_403 unless editable?
181
    
182
    @descendants_count = @page.descendants.size
183
    if @descendants_count > 0
184
      case params[:todo]
185
      when 'nullify'
186
        # Nothing to do
187
      when 'destroy'
188
        # Removes all its descendants
189
        @page.descendants.each(&:destroy)
190
      when 'reassign'
191
        # Reassign children to another parent page
192
        reassign_to = @wiki.pages.find_by_id(params[:reassign_to_id].to_i)
193
        return unless reassign_to
194
        @page.children.each do |child|
195
          child.update_attribute(:parent, reassign_to)
196
        end
197
      else
198
        @reassignable_to = @wiki.pages - @page.self_and_descendants
199
        return
200
      end
201
    end
202
    @page.destroy
203
    redirect_to :action => 'index', :project_id => @project
204
  end
205

    
206
  # Export wiki to a single html file
207
  def export
208
    if User.current.allowed_to?(:export_wiki_pages, @project)
209
      @pages = @wiki.pages.find :all, :order => 'title'
210
      export = render_to_string :action => 'export_multiple', :layout => false
211
      send_data(export, :type => 'text/html', :filename => "wiki.html")
212
    else
213
      redirect_to :action => 'show', :project_id => @project, :id => nil
214
    end
215
  end
216

    
217
  def date_index
218
    load_pages_grouped_by_date_without_content
219
  end
220
  
221
  def preview
222
    page = @wiki.find_page(params[:id])
223
    # page is nil when previewing a new page
224
    return render_403 unless page.nil? || editable?(page)
225
    if page
226
      @attachements = page.attachments
227
      @previewed = page.content
228
    end
229
    @text = params[:content][:text]
230
    render :partial => 'common/preview'
231
  end
232

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

    
240
private
241
  
242
  def find_wiki
243
    @project = Project.find(params[:project_id])
244
    @wiki = @project.wiki
245
    render_404 unless @wiki
246
  rescue ActiveRecord::RecordNotFound
247
    render_404
248
  end
249
  
250
  # Finds the requested page and returns a 404 error if it doesn't exist
251
  def find_existing_page
252
    @page = @wiki.find_page(params[:id])
253
    render_404 if @page.nil?
254
  end
255
  
256
  # Returns true if the current user is allowed to edit the page, otherwise false
257
  def editable?(page = @page)
258
    page.editable_by?(User.current)
259
  end
260

    
261
  # Returns the default content of a new wiki page
262
  def initial_page_content(page)
263
    helper = Redmine::WikiFormatting.helper_for(Setting.text_formatting)
264
    extend helper unless self.instance_of?(helper)
265
    helper.instance_method(:initial_page_content).bind(self).call(page)
266
  end
267

    
268
  # eager load information about last updates, without loading text
269
  def load_pages_grouped_by_date_without_content
270
    @pages = @wiki.pages.find :all, :select => "#{WikiPage.table_name}.*, #{WikiContent.table_name}.updated_on",
271
                                    :joins => "LEFT JOIN #{WikiContent.table_name} ON #{WikiContent.table_name}.page_id = #{WikiPage.table_name}.id",
272
                                    :order => 'title'
273
    @pages_by_date = @pages.group_by {|p| p.updated_on.to_date}
274
    @pages_by_parent_id = @pages.group_by(&:parent_id)
275
  end
276
  
277
end