##// END OF EJS Templates
Makes the wiki sidebar editable (#5208)....
Jean-Philippe Lang -
r3518:58792737394c
parent child
Show More
@@ -1,248 +1,248
1 1 # redMine - project management software
2 2 # Copyright (C) 2006-2007 Jean-Philippe Lang
3 3 #
4 4 # This program is free software; you can redistribute it and/or
5 5 # modify it under the terms of the GNU General Public License
6 6 # as published by the Free Software Foundation; either version 2
7 7 # of the License, or (at your option) any later version.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU General Public License
15 15 # along with this program; if not, write to the Free Software
16 16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 17
18 18 require 'diff'
19 19
20 20 class WikiController < ApplicationController
21 21 default_search_scope :wiki_pages
22 22 before_filter :find_wiki, :authorize
23 23 before_filter :find_existing_page, :only => [:rename, :protect, :history, :diff, :annotate, :add_attachment, :destroy]
24 24
25 25 verify :method => :post, :only => [:destroy, :protect], :redirect_to => { :action => :index }
26 26
27 27 helper :attachments
28 28 include AttachmentsHelper
29 29 helper :watchers
30 30
31 31 # display a page (in editing mode if it doesn't exist)
32 32 def index
33 33 page_title = params[:page]
34 34 @page = @wiki.find_or_new_page(page_title)
35 35 if @page.new_record?
36 if User.current.allowed_to?(:edit_wiki_pages, @project)
36 if User.current.allowed_to?(:edit_wiki_pages, @project) && editable?
37 37 edit
38 38 render :action => 'edit'
39 39 else
40 40 render_404
41 41 end
42 42 return
43 43 end
44 44 if params[:version] && !User.current.allowed_to?(:view_wiki_edits, @project)
45 45 # Redirects user to the current version if he's not allowed to view previous versions
46 46 redirect_to :version => nil
47 47 return
48 48 end
49 49 @content = @page.content_for_version(params[:version])
50 50 if User.current.allowed_to?(:export_wiki_pages, @project)
51 51 if params[:format] == 'html'
52 52 export = render_to_string :action => 'export', :layout => false
53 53 send_data(export, :type => 'text/html', :filename => "#{@page.title}.html")
54 54 return
55 55 elsif params[:format] == 'txt'
56 56 send_data(@content.text, :type => 'text/plain', :filename => "#{@page.title}.txt")
57 57 return
58 58 end
59 59 end
60 60 @editable = editable?
61 61 render :action => 'show'
62 62 end
63 63
64 64 # edit an existing page or a new one
65 65 def edit
66 66 @page = @wiki.find_or_new_page(params[:page])
67 67 return render_403 unless editable?
68 68 @page.content = WikiContent.new(:page => @page) if @page.new_record?
69 69
70 70 @content = @page.content_for_version(params[:version])
71 71 @content.text = initial_page_content(@page) if @content.text.blank?
72 72 # don't keep previous comment
73 73 @content.comments = nil
74 74 if request.get?
75 75 # To prevent StaleObjectError exception when reverting to a previous version
76 76 @content.version = @page.content.version
77 77 else
78 78 if !@page.new_record? && @content.text == params[:content][:text]
79 79 attachments = Attachment.attach_files(@page, params[:attachments])
80 80 render_attachment_warning_if_needed(@page)
81 81 # don't save if text wasn't changed
82 82 redirect_to :action => 'index', :id => @project, :page => @page.title
83 83 return
84 84 end
85 85 #@content.text = params[:content][:text]
86 86 #@content.comments = params[:content][:comments]
87 87 @content.attributes = params[:content]
88 88 @content.author = User.current
89 89 # if page is new @page.save will also save content, but not if page isn't a new record
90 90 if (@page.new_record? ? @page.save : @content.save)
91 91 attachments = Attachment.attach_files(@page, params[:attachments])
92 92 render_attachment_warning_if_needed(@page)
93 93 call_hook(:controller_wiki_edit_after_save, { :params => params, :page => @page})
94 94 redirect_to :action => 'index', :id => @project, :page => @page.title
95 95 end
96 96 end
97 97 rescue ActiveRecord::StaleObjectError
98 98 # Optimistic locking exception
99 99 flash[:error] = l(:notice_locking_conflict)
100 100 end
101 101
102 102 # rename a page
103 103 def rename
104 104 return render_403 unless editable?
105 105 @page.redirect_existing_links = true
106 106 # used to display the *original* title if some AR validation errors occur
107 107 @original_title = @page.pretty_title
108 108 if request.post? && @page.update_attributes(params[:wiki_page])
109 109 flash[:notice] = l(:notice_successful_update)
110 110 redirect_to :action => 'index', :id => @project, :page => @page.title
111 111 end
112 112 end
113 113
114 114 def protect
115 115 @page.update_attribute :protected, params[:protected]
116 116 redirect_to :action => 'index', :id => @project, :page => @page.title
117 117 end
118 118
119 119 # show page history
120 120 def history
121 121 @version_count = @page.content.versions.count
122 122 @version_pages = Paginator.new self, @version_count, per_page_option, params['p']
123 123 # don't load text
124 124 @versions = @page.content.versions.find :all,
125 125 :select => "id, author_id, comments, updated_on, version",
126 126 :order => 'version DESC',
127 127 :limit => @version_pages.items_per_page + 1,
128 128 :offset => @version_pages.current.offset
129 129
130 130 render :layout => false if request.xhr?
131 131 end
132 132
133 133 def diff
134 134 @diff = @page.diff(params[:version], params[:version_from])
135 135 render_404 unless @diff
136 136 end
137 137
138 138 def annotate
139 139 @annotate = @page.annotate(params[:version])
140 140 render_404 unless @annotate
141 141 end
142 142
143 143 # Removes a wiki page and its history
144 144 # Children can be either set as root pages, removed or reassigned to another parent page
145 145 def destroy
146 146 return render_403 unless editable?
147 147
148 148 @descendants_count = @page.descendants.size
149 149 if @descendants_count > 0
150 150 case params[:todo]
151 151 when 'nullify'
152 152 # Nothing to do
153 153 when 'destroy'
154 154 # Removes all its descendants
155 155 @page.descendants.each(&:destroy)
156 156 when 'reassign'
157 157 # Reassign children to another parent page
158 158 reassign_to = @wiki.pages.find_by_id(params[:reassign_to_id].to_i)
159 159 return unless reassign_to
160 160 @page.children.each do |child|
161 161 child.update_attribute(:parent, reassign_to)
162 162 end
163 163 else
164 164 @reassignable_to = @wiki.pages - @page.self_and_descendants
165 165 return
166 166 end
167 167 end
168 168 @page.destroy
169 169 redirect_to :action => 'special', :id => @project, :page => 'Page_index'
170 170 end
171 171
172 172 # display special pages
173 173 def special
174 174 page_title = params[:page].downcase
175 175 case page_title
176 176 # show pages index, sorted by title
177 177 when 'page_index', 'date_index'
178 178 # eager load information about last updates, without loading text
179 179 @pages = @wiki.pages.find :all, :select => "#{WikiPage.table_name}.*, #{WikiContent.table_name}.updated_on",
180 180 :joins => "LEFT JOIN #{WikiContent.table_name} ON #{WikiContent.table_name}.page_id = #{WikiPage.table_name}.id",
181 181 :order => 'title'
182 182 @pages_by_date = @pages.group_by {|p| p.updated_on.to_date}
183 183 @pages_by_parent_id = @pages.group_by(&:parent_id)
184 184 # export wiki to a single html file
185 185 when 'export'
186 186 if User.current.allowed_to?(:export_wiki_pages, @project)
187 187 @pages = @wiki.pages.find :all, :order => 'title'
188 188 export = render_to_string :action => 'export_multiple', :layout => false
189 189 send_data(export, :type => 'text/html', :filename => "wiki.html")
190 190 else
191 191 redirect_to :action => 'index', :id => @project, :page => nil
192 192 end
193 193 return
194 194 else
195 195 # requested special page doesn't exist, redirect to default page
196 196 redirect_to :action => 'index', :id => @project, :page => nil
197 197 return
198 198 end
199 199 render :action => "special_#{page_title}"
200 200 end
201 201
202 202 def preview
203 203 page = @wiki.find_page(params[:page])
204 204 # page is nil when previewing a new page
205 205 return render_403 unless page.nil? || editable?(page)
206 206 if page
207 207 @attachements = page.attachments
208 208 @previewed = page.content
209 209 end
210 210 @text = params[:content][:text]
211 211 render :partial => 'common/preview'
212 212 end
213 213
214 214 def add_attachment
215 215 return render_403 unless editable?
216 216 attachments = Attachment.attach_files(@page, params[:attachments])
217 217 render_attachment_warning_if_needed(@page)
218 218 redirect_to :action => 'index', :page => @page.title
219 219 end
220 220
221 221 private
222 222
223 223 def find_wiki
224 224 @project = Project.find(params[:id])
225 225 @wiki = @project.wiki
226 226 render_404 unless @wiki
227 227 rescue ActiveRecord::RecordNotFound
228 228 render_404
229 229 end
230 230
231 231 # Finds the requested page and returns a 404 error if it doesn't exist
232 232 def find_existing_page
233 233 @page = @wiki.find_page(params[:page])
234 234 render_404 if @page.nil?
235 235 end
236 236
237 237 # Returns true if the current user is allowed to edit the page, otherwise false
238 238 def editable?(page = @page)
239 239 page.editable_by?(User.current)
240 240 end
241 241
242 242 # Returns the default content of a new wiki page
243 243 def initial_page_content(page)
244 244 helper = Redmine::WikiFormatting.helper_for(Setting.text_formatting)
245 245 extend helper unless self.instance_of?(helper)
246 246 helper.instance_method(:initial_page_content).bind(self).call(page)
247 247 end
248 248 end
@@ -1,79 +1,85
1 1 # Redmine - project management software
2 2 # Copyright (C) 2006-2009 Jean-Philippe Lang
3 3 #
4 4 # This program is free software; you can redistribute it and/or
5 5 # modify it under the terms of the GNU General Public License
6 6 # as published by the Free Software Foundation; either version 2
7 7 # of the License, or (at your option) any later version.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU General Public License
15 15 # along with this program; if not, write to the Free Software
16 16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 17
18 18 class Wiki < ActiveRecord::Base
19 19 belongs_to :project
20 20 has_many :pages, :class_name => 'WikiPage', :dependent => :destroy, :order => 'title'
21 21 has_many :redirects, :class_name => 'WikiRedirect', :dependent => :delete_all
22 22
23 23 acts_as_watchable
24 24
25 25 validates_presence_of :start_page
26 26 validates_format_of :start_page, :with => /^[^,\.\/\?\;\|\:]*$/
27 27
28 28 def visible?(user=User.current)
29 29 !user.nil? && user.allowed_to?(:view_wiki_pages, project)
30 30 end
31 31
32 # Returns the wiki page that acts as the sidebar content
33 # or nil if no such page exists
34 def sidebar
35 @sidebar ||= find_page('Sidebar', :with_redirect => false)
36 end
37
32 38 # find the page with the given title
33 39 # if page doesn't exist, return a new page
34 40 def find_or_new_page(title)
35 41 title = start_page if title.blank?
36 42 find_page(title) || WikiPage.new(:wiki => self, :title => Wiki.titleize(title))
37 43 end
38 44
39 45 # find the page with the given title
40 46 def find_page(title, options = {})
41 47 title = start_page if title.blank?
42 48 title = Wiki.titleize(title)
43 49 page = pages.find_by_title(title)
44 50 if !page && !(options[:with_redirect] == false)
45 51 # search for a redirect
46 52 redirect = redirects.find_by_title(title)
47 53 page = find_page(redirect.redirects_to, :with_redirect => false) if redirect
48 54 end
49 55 page
50 56 end
51 57
52 58 # Finds a page by title
53 59 # The given string can be of one of the forms: "title" or "project:title"
54 60 # Examples:
55 61 # Wiki.find_page("bar", project => foo)
56 62 # Wiki.find_page("foo:bar")
57 63 def self.find_page(title, options = {})
58 64 project = options[:project]
59 65 if title.to_s =~ %r{^([^\:]+)\:(.*)$}
60 66 project_identifier, title = $1, $2
61 67 project = Project.find_by_identifier(project_identifier) || Project.find_by_name(project_identifier)
62 68 end
63 69 if project && project.wiki
64 70 page = project.wiki.find_page(title)
65 71 if page && page.content
66 72 page
67 73 end
68 74 end
69 75 end
70 76
71 77 # turn a string into a valid page title
72 78 def self.titleize(title)
73 79 # replace spaces with _ and remove unwanted caracters
74 80 title = title.gsub(/\s+/, '_').delete(',./?;|:') if title
75 81 # upcase the first letter
76 82 title = (title.slice(0..0).upcase + (title.slice(1..-1) || '')) if title
77 83 title
78 84 end
79 85 end
@@ -1,106 +1,110
1 1 # redMine - project management software
2 2 # Copyright (C) 2006-2007 Jean-Philippe Lang
3 3 #
4 4 # This program is free software; you can redistribute it and/or
5 5 # modify it under the terms of the GNU General Public License
6 6 # as published by the Free Software Foundation; either version 2
7 7 # of the License, or (at your option) any later version.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU General Public License
15 15 # along with this program; if not, write to the Free Software
16 16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 17
18 18 require 'zlib'
19 19
20 20 class WikiContent < ActiveRecord::Base
21 21 set_locking_column :version
22 22 belongs_to :page, :class_name => 'WikiPage', :foreign_key => 'page_id'
23 23 belongs_to :author, :class_name => 'User', :foreign_key => 'author_id'
24 24 validates_presence_of :text
25 25 validates_length_of :comments, :maximum => 255, :allow_nil => true
26 26
27 27 acts_as_versioned
28 28
29 29 def visible?(user=User.current)
30 30 page.visible?(user)
31 31 end
32 32
33 33 def project
34 34 page.project
35 35 end
36 36
37 def attachments
38 page.nil? ? [] : page.attachments
39 end
40
37 41 # Returns the mail adresses of users that should be notified
38 42 def recipients
39 43 notified = project.notified_users
40 44 notified.reject! {|user| !visible?(user)}
41 45 notified.collect(&:mail)
42 46 end
43 47
44 48 class Version
45 49 belongs_to :page, :class_name => '::WikiPage', :foreign_key => 'page_id'
46 50 belongs_to :author, :class_name => '::User', :foreign_key => 'author_id'
47 51 attr_protected :data
48 52
49 53 acts_as_event :title => Proc.new {|o| "#{l(:label_wiki_edit)}: #{o.page.title} (##{o.version})"},
50 54 :description => :comments,
51 55 :datetime => :updated_on,
52 56 :type => 'wiki-page',
53 57 :url => Proc.new {|o| {:controller => 'wiki', :id => o.page.wiki.project_id, :page => o.page.title, :version => o.version}}
54 58
55 59 acts_as_activity_provider :type => 'wiki_edits',
56 60 :timestamp => "#{WikiContent.versioned_table_name}.updated_on",
57 61 :author_key => "#{WikiContent.versioned_table_name}.author_id",
58 62 :permission => :view_wiki_edits,
59 63 :find_options => {:select => "#{WikiContent.versioned_table_name}.updated_on, #{WikiContent.versioned_table_name}.comments, " +
60 64 "#{WikiContent.versioned_table_name}.#{WikiContent.version_column}, #{WikiPage.table_name}.title, " +
61 65 "#{WikiContent.versioned_table_name}.page_id, #{WikiContent.versioned_table_name}.author_id, " +
62 66 "#{WikiContent.versioned_table_name}.id",
63 67 :joins => "LEFT JOIN #{WikiPage.table_name} ON #{WikiPage.table_name}.id = #{WikiContent.versioned_table_name}.page_id " +
64 68 "LEFT JOIN #{Wiki.table_name} ON #{Wiki.table_name}.id = #{WikiPage.table_name}.wiki_id " +
65 69 "LEFT JOIN #{Project.table_name} ON #{Project.table_name}.id = #{Wiki.table_name}.project_id"}
66 70
67 71 def text=(plain)
68 72 case Setting.wiki_compression
69 73 when 'gzip'
70 74 begin
71 75 self.data = Zlib::Deflate.deflate(plain, Zlib::BEST_COMPRESSION)
72 76 self.compression = 'gzip'
73 77 rescue
74 78 self.data = plain
75 79 self.compression = ''
76 80 end
77 81 else
78 82 self.data = plain
79 83 self.compression = ''
80 84 end
81 85 plain
82 86 end
83 87
84 88 def text
85 89 @text ||= case compression
86 90 when 'gzip'
87 91 Zlib::Inflate.inflate(data)
88 92 else
89 93 # uncompressed data
90 94 data
91 95 end
92 96 end
93 97
94 98 def project
95 99 page.project
96 100 end
97 101
98 102 # Returns the previous version or nil
99 103 def previous
100 104 @previous ||= WikiContent::Version.find(:first,
101 105 :order => 'version DESC',
102 106 :include => :author,
103 107 :conditions => ["wiki_content_id = ? AND version < ?", wiki_content_id, version])
104 108 end
105 109 end
106 110 end
@@ -1,193 +1,202
1 1 # Redmine - project management software
2 2 # Copyright (C) 2006-2009 Jean-Philippe Lang
3 3 #
4 4 # This program is free software; you can redistribute it and/or
5 5 # modify it under the terms of the GNU General Public License
6 6 # as published by the Free Software Foundation; either version 2
7 7 # of the License, or (at your option) any later version.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU General Public License
15 15 # along with this program; if not, write to the Free Software
16 16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 17
18 18 require 'diff'
19 19 require 'enumerator'
20 20
21 21 class WikiPage < ActiveRecord::Base
22 22 belongs_to :wiki
23 23 has_one :content, :class_name => 'WikiContent', :foreign_key => 'page_id', :dependent => :destroy
24 24 acts_as_attachable :delete_permission => :delete_wiki_pages_attachments
25 25 acts_as_tree :dependent => :nullify, :order => 'title'
26 26
27 27 acts_as_watchable
28 28 acts_as_event :title => Proc.new {|o| "#{l(:label_wiki)}: #{o.title}"},
29 29 :description => :text,
30 30 :datetime => :created_on,
31 31 :url => Proc.new {|o| {:controller => 'wiki', :id => o.wiki.project, :page => o.title}}
32 32
33 33 acts_as_searchable :columns => ['title', 'text'],
34 34 :include => [{:wiki => :project}, :content],
35 35 :project_key => "#{Wiki.table_name}.project_id"
36 36
37 37 attr_accessor :redirect_existing_links
38 38
39 39 validates_presence_of :title
40 40 validates_format_of :title, :with => /^[^,\.\/\?\;\|\s]*$/
41 41 validates_uniqueness_of :title, :scope => :wiki_id, :case_sensitive => false
42 42 validates_associated :content
43 43
44 # Wiki pages that are protected by default
45 DEFAULT_PROTECTED_PAGES = %w(sidebar)
46
47 def after_initialize
48 if new_record? && DEFAULT_PROTECTED_PAGES.include?(title.to_s.downcase)
49 self.protected = true
50 end
51 end
52
44 53 def visible?(user=User.current)
45 54 !user.nil? && user.allowed_to?(:view_wiki_pages, project)
46 55 end
47 56
48 57 def title=(value)
49 58 value = Wiki.titleize(value)
50 59 @previous_title = read_attribute(:title) if @previous_title.blank?
51 60 write_attribute(:title, value)
52 61 end
53 62
54 63 def before_save
55 64 self.title = Wiki.titleize(title)
56 65 # Manage redirects if the title has changed
57 66 if !@previous_title.blank? && (@previous_title != title) && !new_record?
58 67 # Update redirects that point to the old title
59 68 wiki.redirects.find_all_by_redirects_to(@previous_title).each do |r|
60 69 r.redirects_to = title
61 70 r.title == r.redirects_to ? r.destroy : r.save
62 71 end
63 72 # Remove redirects for the new title
64 73 wiki.redirects.find_all_by_title(title).each(&:destroy)
65 74 # Create a redirect to the new title
66 75 wiki.redirects << WikiRedirect.new(:title => @previous_title, :redirects_to => title) unless redirect_existing_links == "0"
67 76 @previous_title = nil
68 77 end
69 78 end
70 79
71 80 def before_destroy
72 81 # Remove redirects to this page
73 82 wiki.redirects.find_all_by_redirects_to(title).each(&:destroy)
74 83 end
75 84
76 85 def pretty_title
77 86 WikiPage.pretty_title(title)
78 87 end
79 88
80 89 def content_for_version(version=nil)
81 90 result = content.versions.find_by_version(version.to_i) if version
82 91 result ||= content
83 92 result
84 93 end
85 94
86 95 def diff(version_to=nil, version_from=nil)
87 96 version_to = version_to ? version_to.to_i : self.content.version
88 97 version_from = version_from ? version_from.to_i : version_to - 1
89 98 version_to, version_from = version_from, version_to unless version_from < version_to
90 99
91 100 content_to = content.versions.find_by_version(version_to)
92 101 content_from = content.versions.find_by_version(version_from)
93 102
94 103 (content_to && content_from) ? WikiDiff.new(content_to, content_from) : nil
95 104 end
96 105
97 106 def annotate(version=nil)
98 107 version = version ? version.to_i : self.content.version
99 108 c = content.versions.find_by_version(version)
100 109 c ? WikiAnnotate.new(c) : nil
101 110 end
102 111
103 112 def self.pretty_title(str)
104 113 (str && str.is_a?(String)) ? str.tr('_', ' ') : str
105 114 end
106 115
107 116 def project
108 117 wiki.project
109 118 end
110 119
111 120 def text
112 121 content.text if content
113 122 end
114 123
115 124 # Returns true if usr is allowed to edit the page, otherwise false
116 125 def editable_by?(usr)
117 126 !protected? || usr.allowed_to?(:protect_wiki_pages, wiki.project)
118 127 end
119 128
120 129 def attachments_deletable?(usr=User.current)
121 130 editable_by?(usr) && super(usr)
122 131 end
123 132
124 133 def parent_title
125 134 @parent_title || (self.parent && self.parent.pretty_title)
126 135 end
127 136
128 137 def parent_title=(t)
129 138 @parent_title = t
130 139 parent_page = t.blank? ? nil : self.wiki.find_page(t)
131 140 self.parent = parent_page
132 141 end
133 142
134 143 protected
135 144
136 145 def validate
137 146 errors.add(:parent_title, :invalid) if !@parent_title.blank? && parent.nil?
138 147 errors.add(:parent_title, :circular_dependency) if parent && (parent == self || parent.ancestors.include?(self))
139 148 errors.add(:parent_title, :not_same_project) if parent && (parent.wiki_id != wiki_id)
140 149 end
141 150 end
142 151
143 152 class WikiDiff
144 153 attr_reader :diff, :words, :content_to, :content_from
145 154
146 155 def initialize(content_to, content_from)
147 156 @content_to = content_to
148 157 @content_from = content_from
149 158 @words = content_to.text.split(/(\s+)/)
150 159 @words = @words.select {|word| word != ' '}
151 160 words_from = content_from.text.split(/(\s+)/)
152 161 words_from = words_from.select {|word| word != ' '}
153 162 @diff = words_from.diff @words
154 163 end
155 164 end
156 165
157 166 class WikiAnnotate
158 167 attr_reader :lines, :content
159 168
160 169 def initialize(content)
161 170 @content = content
162 171 current = content
163 172 current_lines = current.text.split(/\r?\n/)
164 173 @lines = current_lines.collect {|t| [nil, nil, t]}
165 174 positions = []
166 175 current_lines.size.times {|i| positions << i}
167 176 while (current.previous)
168 177 d = current.previous.text.split(/\r?\n/).diff(current.text.split(/\r?\n/)).diffs.flatten
169 178 d.each_slice(3) do |s|
170 179 sign, line = s[0], s[1]
171 180 if sign == '+' && positions[line] && positions[line] != -1
172 181 if @lines[positions[line]][0].nil?
173 182 @lines[positions[line]][0] = current.version
174 183 @lines[positions[line]][1] = current.author
175 184 end
176 185 end
177 186 end
178 187 d.each_slice(3) do |s|
179 188 sign, line = s[0], s[1]
180 189 if sign == '-'
181 190 positions.insert(line, -1)
182 191 else
183 192 positions[line] = nil
184 193 end
185 194 end
186 195 positions.compact!
187 196 # Stop if every line is annotated
188 197 break unless @lines.detect { |line| line[0].nil? }
189 198 current = current.previous
190 199 end
191 200 @lines.each { |line| line[0] ||= current.version }
192 201 end
193 202 end
@@ -1,5 +1,9
1 <% if @wiki && @wiki.sidebar -%>
2 <%= textilizable @wiki.sidebar.content, :text %>
3 <% end -%>
4
1 5 <h3><%= l(:label_wiki) %></h3>
2 6
3 7 <%= link_to l(:field_start_page), {:action => 'index', :page => nil} %><br />
4 8 <%= link_to l(:label_index_by_title), {:action => 'special', :page => 'Page_index'} %><br />
5 9 <%= link_to l(:label_index_by_date), {:action => 'special', :page => 'Date_index'} %><br />
@@ -1,414 +1,425
1 1 # redMine - project management software
2 2 # Copyright (C) 2006-2007 Jean-Philippe Lang
3 3 #
4 4 # This program is free software; you can redistribute it and/or
5 5 # modify it under the terms of the GNU General Public License
6 6 # as published by the Free Software Foundation; either version 2
7 7 # of the License, or (at your option) any later version.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU General Public License
15 15 # along with this program; if not, write to the Free Software
16 16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 17
18 18 require File.dirname(__FILE__) + '/../test_helper'
19 19 require 'wiki_controller'
20 20
21 21 # Re-raise errors caught by the controller.
22 22 class WikiController; def rescue_action(e) raise e end; end
23 23
24 24 class WikiControllerTest < ActionController::TestCase
25 25 fixtures :projects, :users, :roles, :members, :member_roles, :enabled_modules, :wikis, :wiki_pages, :wiki_contents, :wiki_content_versions, :attachments
26 26
27 27 def setup
28 28 @controller = WikiController.new
29 29 @request = ActionController::TestRequest.new
30 30 @response = ActionController::TestResponse.new
31 31 User.current = nil
32 32 end
33 33
34 34 def test_index_routing
35 35 assert_routing(
36 36 {:method => :get, :path => '/projects/567/wiki'},
37 37 :controller => 'wiki', :action => 'index', :id => '567'
38 38 )
39 39 assert_routing(
40 40 {:method => :get, :path => '/projects/567/wiki/lalala'},
41 41 :controller => 'wiki', :action => 'index', :id => '567', :page => 'lalala'
42 42 )
43 43 assert_generates(
44 44 '/projects/567/wiki',
45 45 :controller => 'wiki', :action => 'index', :id => '567', :page => nil
46 46 )
47 47 end
48 48
49 49 def test_show_start_page
50 50 get :index, :id => 'ecookbook'
51 51 assert_response :success
52 52 assert_template 'show'
53 53 assert_tag :tag => 'h1', :content => /CookBook documentation/
54 54
55 55 # child_pages macro
56 56 assert_tag :ul, :attributes => { :class => 'pages-hierarchy' },
57 57 :child => { :tag => 'li',
58 58 :child => { :tag => 'a', :attributes => { :href => '/projects/ecookbook/wiki/Page_with_an_inline_image' },
59 59 :content => 'Page with an inline image' } }
60 60 end
61 61
62 62 def test_show_page_with_name
63 63 get :index, :id => 1, :page => 'Another_page'
64 64 assert_response :success
65 65 assert_template 'show'
66 66 assert_tag :tag => 'h1', :content => /Another page/
67 67 # Included page with an inline image
68 68 assert_tag :tag => 'p', :content => /This is an inline image/
69 69 assert_tag :tag => 'img', :attributes => { :src => '/attachments/download/3',
70 70 :alt => 'This is a logo' }
71 71 end
72 72
73 def test_show_with_sidebar
74 page = Project.find(1).wiki.pages.new(:title => 'Sidebar')
75 page.content = WikiContent.new(:text => 'Side bar content for test_show_with_sidebar')
76 page.save!
77
78 get :index, :id => 1, :page => 'Another_page'
79 assert_response :success
80 assert_tag :tag => 'div', :attributes => {:id => 'sidebar'},
81 :content => /Side bar content for test_show_with_sidebar/
82 end
83
73 84 def test_show_unexistent_page_without_edit_right
74 85 get :index, :id => 1, :page => 'Unexistent page'
75 86 assert_response 404
76 87 end
77 88
78 89 def test_show_unexistent_page_with_edit_right
79 90 @request.session[:user_id] = 2
80 91 get :index, :id => 1, :page => 'Unexistent page'
81 92 assert_response :success
82 93 assert_template 'edit'
83 94 end
84 95
85 96 def test_edit_routing
86 97 assert_routing(
87 98 {:method => :get, :path => '/projects/567/wiki/my_page/edit'},
88 99 :controller => 'wiki', :action => 'edit', :id => '567', :page => 'my_page'
89 100 )
90 101 assert_recognizes(#TODO: use PUT to page path, adjust forms accordingly
91 102 {:controller => 'wiki', :action => 'edit', :id => '567', :page => 'my_page'},
92 103 {:method => :post, :path => '/projects/567/wiki/my_page/edit'}
93 104 )
94 105 end
95 106
96 107 def test_create_page
97 108 @request.session[:user_id] = 2
98 109 post :edit, :id => 1,
99 110 :page => 'New page',
100 111 :content => {:comments => 'Created the page',
101 112 :text => "h1. New page\n\nThis is a new page",
102 113 :version => 0}
103 114 assert_redirected_to :action => 'index', :id => 'ecookbook', :page => 'New_page'
104 115 page = Project.find(1).wiki.find_page('New page')
105 116 assert !page.new_record?
106 117 assert_not_nil page.content
107 118 assert_equal 'Created the page', page.content.comments
108 119 end
109 120
110 121 def test_create_page_with_attachments
111 122 @request.session[:user_id] = 2
112 123 assert_difference 'WikiPage.count' do
113 124 assert_difference 'Attachment.count' do
114 125 post :edit, :id => 1,
115 126 :page => 'New page',
116 127 :content => {:comments => 'Created the page',
117 128 :text => "h1. New page\n\nThis is a new page",
118 129 :version => 0},
119 130 :attachments => {'1' => {'file' => uploaded_test_file('testfile.txt', 'text/plain')}}
120 131 end
121 132 end
122 133 page = Project.find(1).wiki.find_page('New page')
123 134 assert_equal 1, page.attachments.count
124 135 assert_equal 'testfile.txt', page.attachments.first.filename
125 136 end
126 137
127 138 def test_preview_routing
128 139 assert_routing(
129 140 {:method => :post, :path => '/projects/567/wiki/CookBook_documentation/preview'},
130 141 :controller => 'wiki', :action => 'preview', :id => '567', :page => 'CookBook_documentation'
131 142 )
132 143 end
133 144
134 145 def test_preview
135 146 @request.session[:user_id] = 2
136 147 xhr :post, :preview, :id => 1, :page => 'CookBook_documentation',
137 148 :content => { :comments => '',
138 149 :text => 'this is a *previewed text*',
139 150 :version => 3 }
140 151 assert_response :success
141 152 assert_template 'common/_preview'
142 153 assert_tag :tag => 'strong', :content => /previewed text/
143 154 end
144 155
145 156 def test_preview_new_page
146 157 @request.session[:user_id] = 2
147 158 xhr :post, :preview, :id => 1, :page => 'New page',
148 159 :content => { :text => 'h1. New page',
149 160 :comments => '',
150 161 :version => 0 }
151 162 assert_response :success
152 163 assert_template 'common/_preview'
153 164 assert_tag :tag => 'h1', :content => /New page/
154 165 end
155 166
156 167 def test_history_routing
157 168 assert_routing(
158 169 {:method => :get, :path => '/projects/1/wiki/CookBook_documentation/history'},
159 170 :controller => 'wiki', :action => 'history', :id => '1', :page => 'CookBook_documentation'
160 171 )
161 172 end
162 173
163 174 def test_history
164 175 get :history, :id => 1, :page => 'CookBook_documentation'
165 176 assert_response :success
166 177 assert_template 'history'
167 178 assert_not_nil assigns(:versions)
168 179 assert_equal 3, assigns(:versions).size
169 180 assert_select "input[type=submit][name=commit]"
170 181 end
171 182
172 183 def test_history_with_one_version
173 184 get :history, :id => 1, :page => 'Another_page'
174 185 assert_response :success
175 186 assert_template 'history'
176 187 assert_not_nil assigns(:versions)
177 188 assert_equal 1, assigns(:versions).size
178 189 assert_select "input[type=submit][name=commit]", false
179 190 end
180 191
181 192 def test_diff_routing
182 193 assert_routing(
183 194 {:method => :get, :path => '/projects/1/wiki/CookBook_documentation/diff/2/vs/1'},
184 195 :controller => 'wiki', :action => 'diff', :id => '1', :page => 'CookBook_documentation', :version => '2', :version_from => '1'
185 196 )
186 197 end
187 198
188 199 def test_diff
189 200 get :diff, :id => 1, :page => 'CookBook_documentation', :version => 2, :version_from => 1
190 201 assert_response :success
191 202 assert_template 'diff'
192 203 assert_tag :tag => 'span', :attributes => { :class => 'diff_in'},
193 204 :content => /updated/
194 205 end
195 206
196 207 def test_annotate_routing
197 208 assert_routing(
198 209 {:method => :get, :path => '/projects/1/wiki/CookBook_documentation/annotate/2'},
199 210 :controller => 'wiki', :action => 'annotate', :id => '1', :page => 'CookBook_documentation', :version => '2'
200 211 )
201 212 end
202 213
203 214 def test_annotate
204 215 get :annotate, :id => 1, :page => 'CookBook_documentation', :version => 2
205 216 assert_response :success
206 217 assert_template 'annotate'
207 218 # Line 1
208 219 assert_tag :tag => 'tr', :child => { :tag => 'th', :attributes => {:class => 'line-num'}, :content => '1' },
209 220 :child => { :tag => 'td', :attributes => {:class => 'author'}, :content => /John Smith/ },
210 221 :child => { :tag => 'td', :content => /h1\. CookBook documentation/ }
211 222 # Line 2
212 223 assert_tag :tag => 'tr', :child => { :tag => 'th', :attributes => {:class => 'line-num'}, :content => '2' },
213 224 :child => { :tag => 'td', :attributes => {:class => 'author'}, :content => /redMine Admin/ },
214 225 :child => { :tag => 'td', :content => /Some updated \[\[documentation\]\] here/ }
215 226 end
216 227
217 228 def test_rename_routing
218 229 assert_routing(
219 230 {:method => :get, :path => '/projects/22/wiki/ladida/rename'},
220 231 :controller => 'wiki', :action => 'rename', :id => '22', :page => 'ladida'
221 232 )
222 233 assert_recognizes(
223 234 #TODO: should be moved into a update action and use a PUT to the page URI
224 235 {:controller => 'wiki', :action => 'rename', :id => '22', :page => 'ladida'},
225 236 {:method => :post, :path => '/projects/22/wiki/ladida/rename'}
226 237 )
227 238 end
228 239
229 240 def test_rename_with_redirect
230 241 @request.session[:user_id] = 2
231 242 post :rename, :id => 1, :page => 'Another_page',
232 243 :wiki_page => { :title => 'Another renamed page',
233 244 :redirect_existing_links => 1 }
234 245 assert_redirected_to :action => 'index', :id => 'ecookbook', :page => 'Another_renamed_page'
235 246 wiki = Project.find(1).wiki
236 247 # Check redirects
237 248 assert_not_nil wiki.find_page('Another page')
238 249 assert_nil wiki.find_page('Another page', :with_redirect => false)
239 250 end
240 251
241 252 def test_rename_without_redirect
242 253 @request.session[:user_id] = 2
243 254 post :rename, :id => 1, :page => 'Another_page',
244 255 :wiki_page => { :title => 'Another renamed page',
245 256 :redirect_existing_links => "0" }
246 257 assert_redirected_to :action => 'index', :id => 'ecookbook', :page => 'Another_renamed_page'
247 258 wiki = Project.find(1).wiki
248 259 # Check that there's no redirects
249 260 assert_nil wiki.find_page('Another page')
250 261 end
251 262
252 263 def test_destroy_routing
253 264 assert_recognizes(
254 265 #TODO: should use DELETE on page URI
255 266 {:controller => 'wiki', :action => 'destroy', :id => '22', :page => 'ladida'},
256 267 {:method => :post, :path => 'projects/22/wiki/ladida/destroy'}
257 268 )
258 269 end
259 270
260 271 def test_destroy_child
261 272 @request.session[:user_id] = 2
262 273 post :destroy, :id => 1, :page => 'Child_1'
263 274 assert_redirected_to :action => 'special', :id => 'ecookbook', :page => 'Page_index'
264 275 end
265 276
266 277 def test_destroy_parent
267 278 @request.session[:user_id] = 2
268 279 assert_no_difference('WikiPage.count') do
269 280 post :destroy, :id => 1, :page => 'Another_page'
270 281 end
271 282 assert_response :success
272 283 assert_template 'destroy'
273 284 end
274 285
275 286 def test_destroy_parent_with_nullify
276 287 @request.session[:user_id] = 2
277 288 assert_difference('WikiPage.count', -1) do
278 289 post :destroy, :id => 1, :page => 'Another_page', :todo => 'nullify'
279 290 end
280 291 assert_redirected_to :action => 'special', :id => 'ecookbook', :page => 'Page_index'
281 292 assert_nil WikiPage.find_by_id(2)
282 293 end
283 294
284 295 def test_destroy_parent_with_cascade
285 296 @request.session[:user_id] = 2
286 297 assert_difference('WikiPage.count', -3) do
287 298 post :destroy, :id => 1, :page => 'Another_page', :todo => 'destroy'
288 299 end
289 300 assert_redirected_to :action => 'special', :id => 'ecookbook', :page => 'Page_index'
290 301 assert_nil WikiPage.find_by_id(2)
291 302 assert_nil WikiPage.find_by_id(5)
292 303 end
293 304
294 305 def test_destroy_parent_with_reassign
295 306 @request.session[:user_id] = 2
296 307 assert_difference('WikiPage.count', -1) do
297 308 post :destroy, :id => 1, :page => 'Another_page', :todo => 'reassign', :reassign_to_id => 1
298 309 end
299 310 assert_redirected_to :action => 'special', :id => 'ecookbook', :page => 'Page_index'
300 311 assert_nil WikiPage.find_by_id(2)
301 312 assert_equal WikiPage.find(1), WikiPage.find_by_id(5).parent
302 313 end
303 314
304 315 def test_special_routing
305 316 assert_routing(
306 317 {:method => :get, :path => '/projects/567/wiki/page_index'},
307 318 :controller => 'wiki', :action => 'special', :id => '567', :page => 'page_index'
308 319 )
309 320 assert_routing(
310 321 {:method => :get, :path => '/projects/567/wiki/Page_Index'},
311 322 :controller => 'wiki', :action => 'special', :id => '567', :page => 'Page_Index'
312 323 )
313 324 assert_routing(
314 325 {:method => :get, :path => '/projects/567/wiki/date_index'},
315 326 :controller => 'wiki', :action => 'special', :id => '567', :page => 'date_index'
316 327 )
317 328 assert_routing(
318 329 {:method => :get, :path => '/projects/567/wiki/export'},
319 330 :controller => 'wiki', :action => 'special', :id => '567', :page => 'export'
320 331 )
321 332 end
322 333
323 334 def test_page_index
324 335 get :special, :id => 'ecookbook', :page => 'Page_index'
325 336 assert_response :success
326 337 assert_template 'special_page_index'
327 338 pages = assigns(:pages)
328 339 assert_not_nil pages
329 340 assert_equal Project.find(1).wiki.pages.size, pages.size
330 341
331 342 assert_tag :ul, :attributes => { :class => 'pages-hierarchy' },
332 343 :child => { :tag => 'li', :child => { :tag => 'a', :attributes => { :href => '/projects/ecookbook/wiki/CookBook_documentation' },
333 344 :content => 'CookBook documentation' },
334 345 :child => { :tag => 'ul',
335 346 :child => { :tag => 'li',
336 347 :child => { :tag => 'a', :attributes => { :href => '/projects/ecookbook/wiki/Page_with_an_inline_image' },
337 348 :content => 'Page with an inline image' } } } },
338 349 :child => { :tag => 'li', :child => { :tag => 'a', :attributes => { :href => '/projects/ecookbook/wiki/Another_page' },
339 350 :content => 'Another page' } }
340 351 end
341 352
342 353 def test_not_found
343 354 get :index, :id => 999
344 355 assert_response 404
345 356 end
346 357
347 358 def test_protect_routing
348 359 assert_routing(
349 360 {:method => :post, :path => 'projects/22/wiki/ladida/protect'},
350 361 {:controller => 'wiki', :action => 'protect', :id => '22', :page => 'ladida'}
351 362 )
352 363 end
353 364
354 365 def test_protect_page
355 366 page = WikiPage.find_by_wiki_id_and_title(1, 'Another_page')
356 367 assert !page.protected?
357 368 @request.session[:user_id] = 2
358 369 post :protect, :id => 1, :page => page.title, :protected => '1'
359 370 assert_redirected_to :action => 'index', :id => 'ecookbook', :page => 'Another_page'
360 371 assert page.reload.protected?
361 372 end
362 373
363 374 def test_unprotect_page
364 375 page = WikiPage.find_by_wiki_id_and_title(1, 'CookBook_documentation')
365 376 assert page.protected?
366 377 @request.session[:user_id] = 2
367 378 post :protect, :id => 1, :page => page.title, :protected => '0'
368 379 assert_redirected_to :action => 'index', :id => 'ecookbook', :page => 'CookBook_documentation'
369 380 assert !page.reload.protected?
370 381 end
371 382
372 383 def test_show_page_with_edit_link
373 384 @request.session[:user_id] = 2
374 385 get :index, :id => 1
375 386 assert_response :success
376 387 assert_template 'show'
377 388 assert_tag :tag => 'a', :attributes => { :href => '/projects/1/wiki/CookBook_documentation/edit' }
378 389 end
379 390
380 391 def test_show_page_without_edit_link
381 392 @request.session[:user_id] = 4
382 393 get :index, :id => 1
383 394 assert_response :success
384 395 assert_template 'show'
385 396 assert_no_tag :tag => 'a', :attributes => { :href => '/projects/1/wiki/CookBook_documentation/edit' }
386 397 end
387 398
388 399 def test_edit_unprotected_page
389 400 # Non members can edit unprotected wiki pages
390 401 @request.session[:user_id] = 4
391 402 get :edit, :id => 1, :page => 'Another_page'
392 403 assert_response :success
393 404 assert_template 'edit'
394 405 end
395 406
396 407 def test_edit_protected_page_by_nonmember
397 408 # Non members can't edit protected wiki pages
398 409 @request.session[:user_id] = 4
399 410 get :edit, :id => 1, :page => 'CookBook_documentation'
400 411 assert_response 403
401 412 end
402 413
403 414 def test_edit_protected_page_by_member
404 415 @request.session[:user_id] = 2
405 416 get :edit, :id => 1, :page => 'CookBook_documentation'
406 417 assert_response :success
407 418 assert_template 'edit'
408 419 end
409 420
410 421 def test_history_of_non_existing_page_should_return_404
411 422 get :history, :id => 1, :page => 'Unknown_page'
412 423 assert_response 404
413 424 end
414 425 end
@@ -1,117 +1,124
1 1 # redMine - project management software
2 2 # Copyright (C) 2006-2007 Jean-Philippe Lang
3 3 #
4 4 # This program is free software; you can redistribute it and/or
5 5 # modify it under the terms of the GNU General Public License
6 6 # as published by the Free Software Foundation; either version 2
7 7 # of the License, or (at your option) any later version.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU General Public License
15 15 # along with this program; if not, write to the Free Software
16 16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 17
18 18 require File.dirname(__FILE__) + '/../test_helper'
19 19
20 20 class WikiPageTest < ActiveSupport::TestCase
21 21 fixtures :projects, :wikis, :wiki_pages, :wiki_contents, :wiki_content_versions
22 22
23 23 def setup
24 24 @wiki = Wiki.find(1)
25 25 @page = @wiki.pages.first
26 26 end
27 27
28 28 def test_create
29 29 page = WikiPage.new(:wiki => @wiki)
30 30 assert !page.save
31 31 assert_equal 1, page.errors.count
32 32
33 33 page.title = "Page"
34 34 assert page.save
35 35 page.reload
36 assert !page.protected?
36 37
37 38 @wiki.reload
38 39 assert @wiki.pages.include?(page)
39 40 end
40 41
42 def test_sidebar_should_be_protected_by_default
43 page = @wiki.find_or_new_page('sidebar')
44 assert page.new_record?
45 assert page.protected?
46 end
47
41 48 def test_find_or_new_page
42 49 page = @wiki.find_or_new_page("CookBook documentation")
43 50 assert_kind_of WikiPage, page
44 51 assert !page.new_record?
45 52
46 53 page = @wiki.find_or_new_page("Non existing page")
47 54 assert_kind_of WikiPage, page
48 55 assert page.new_record?
49 56 end
50 57
51 58 def test_parent_title
52 59 page = WikiPage.find_by_title('Another_page')
53 60 assert_nil page.parent_title
54 61
55 62 page = WikiPage.find_by_title('Page_with_an_inline_image')
56 63 assert_equal 'CookBook documentation', page.parent_title
57 64 end
58 65
59 66 def test_assign_parent
60 67 page = WikiPage.find_by_title('Another_page')
61 68 page.parent_title = 'CookBook documentation'
62 69 assert page.save
63 70 page.reload
64 71 assert_equal WikiPage.find_by_title('CookBook_documentation'), page.parent
65 72 end
66 73
67 74 def test_unassign_parent
68 75 page = WikiPage.find_by_title('Page_with_an_inline_image')
69 76 page.parent_title = ''
70 77 assert page.save
71 78 page.reload
72 79 assert_nil page.parent
73 80 end
74 81
75 82 def test_parent_validation
76 83 page = WikiPage.find_by_title('CookBook_documentation')
77 84
78 85 # A page that doesn't exist
79 86 page.parent_title = 'Unknown title'
80 87 assert !page.save
81 88 assert_equal I18n.translate('activerecord.errors.messages.invalid'), page.errors.on(:parent_title)
82 89 # A child page
83 90 page.parent_title = 'Page_with_an_inline_image'
84 91 assert !page.save
85 92 assert_equal I18n.translate('activerecord.errors.messages.circular_dependency'), page.errors.on(:parent_title)
86 93 # The page itself
87 94 page.parent_title = 'CookBook_documentation'
88 95 assert !page.save
89 96 assert_equal I18n.translate('activerecord.errors.messages.circular_dependency'), page.errors.on(:parent_title)
90 97
91 98 page.parent_title = 'Another_page'
92 99 assert page.save
93 100 end
94 101
95 102 def test_destroy
96 103 page = WikiPage.find(1)
97 104 page.destroy
98 105 assert_nil WikiPage.find_by_id(1)
99 106 # make sure that page content and its history are deleted
100 107 assert WikiContent.find_all_by_page_id(1).empty?
101 108 assert WikiContent.versioned_class.find_all_by_page_id(1).empty?
102 109 end
103 110
104 111 def test_destroy_should_not_nullify_children
105 112 page = WikiPage.find(2)
106 113 child_ids = page.child_ids
107 114 assert child_ids.any?
108 115 page.destroy
109 116 assert_nil WikiPage.find_by_id(2)
110 117
111 118 children = WikiPage.find_all_by_id(child_ids)
112 119 assert_equal child_ids.size, children.size
113 120 children.each do |child|
114 121 assert_nil child.parent_id
115 122 end
116 123 end
117 124 end
@@ -1,46 +1,65
1 1 # encoding: utf-8
2 2 #
3 3 # redMine - project management software
4 4 # Copyright (C) 2006-2007 Jean-Philippe Lang
5 5 #
6 6 # This program is free software; you can redistribute it and/or
7 7 # modify it under the terms of the GNU General Public License
8 8 # as published by the Free Software Foundation; either version 2
9 9 # of the License, or (at your option) any later version.
10 10 #
11 11 # This program is distributed in the hope that it will be useful,
12 12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 14 # GNU General Public License for more details.
15 15 #
16 16 # You should have received a copy of the GNU General Public License
17 17 # along with this program; if not, write to the Free Software
18 18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 19
20 20 require File.dirname(__FILE__) + '/../test_helper'
21 21
22 22 class WikiTest < ActiveSupport::TestCase
23 23 fixtures :wikis, :wiki_pages, :wiki_contents, :wiki_content_versions
24 24
25 25 def test_create
26 26 wiki = Wiki.new(:project => Project.find(2))
27 27 assert !wiki.save
28 28 assert_equal 1, wiki.errors.count
29 29
30 30 wiki.start_page = "Start page"
31 31 assert wiki.save
32 32 end
33 33
34 34 def test_update
35 35 @wiki = Wiki.find(1)
36 36 @wiki.start_page = "Another start page"
37 37 assert @wiki.save
38 38 @wiki.reload
39 39 assert_equal "Another start page", @wiki.start_page
40 40 end
41 41
42 42 def test_titleize
43 43 assert_equal 'Page_title_with_CAPITALES', Wiki.titleize('page title with CAPITALES')
44 44 assert_equal 'テスト', Wiki.titleize('テスト')
45 45 end
46
47 context "#sidebar" do
48 setup do
49 @wiki = Wiki.find(1)
50 end
51
52 should "return nil if undefined" do
53 assert_nil @wiki.sidebar
54 end
55
56 should "return a WikiPage if defined" do
57 page = @wiki.pages.new(:title => 'Sidebar')
58 page.content = WikiContent.new(:text => 'Side bar content for test_show_with_sidebar')
59 page.save!
60
61 assert_kind_of WikiPage, @wiki.sidebar
62 assert_equal 'Sidebar', @wiki.sidebar.title
63 end
64 end
46 65 end
General Comments 0
You need to be logged in to leave comments. Login now