comparison app/models/wiki_page.rb @ 909:cbb26bc654de redmine-1.3

Update to Redmine 1.3-stable branch (Redmine SVN rev 8964)
author Chris Cannam
date Fri, 24 Feb 2012 19:09:32 +0000
parents 0c939c159af4
children 433d4f72a19b
comparison
equal deleted inserted replaced
908:c6c2cbd0afee 909:cbb26bc654de
3 # 3 #
4 # This program is free software; you can redistribute it and/or 4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License 5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2 6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version. 7 # of the License, or (at your option) any later version.
8 # 8 #
9 # This program is distributed in the hope that it will be useful, 9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details. 12 # GNU General Public License for more details.
13 # 13 #
14 # You should have received a copy of the GNU General Public License 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 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. 16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 17
18 require 'diff' 18 require 'diff'
28 acts_as_event :title => Proc.new {|o| "#{l(:label_wiki)}: #{o.title}"}, 28 acts_as_event :title => Proc.new {|o| "#{l(:label_wiki)}: #{o.title}"},
29 :description => :text, 29 :description => :text,
30 :datetime => :created_on, 30 :datetime => :created_on,
31 :url => Proc.new {|o| {:controller => 'wiki', :action => 'show', :project_id => o.wiki.project, :id => o.title}} 31 :url => Proc.new {|o| {:controller => 'wiki', :action => 'show', :project_id => o.wiki.project, :id => o.title}}
32 32
33 acts_as_searchable :columns => ['title', 'text'], 33 acts_as_searchable :columns => ['title', "#{WikiContent.table_name}.text"],
34 :include => [{:wiki => :project}, :content], 34 :include => [{:wiki => :project}, :content],
35 :permission => :view_wiki_pages, 35 :permission => :view_wiki_pages,
36 :project_key => "#{Wiki.table_name}.project_id" 36 :project_key => "#{Wiki.table_name}.project_id"
37 37
38 attr_accessor :redirect_existing_links 38 attr_accessor :redirect_existing_links
39 39
40 validates_presence_of :title 40 validates_presence_of :title
41 validates_format_of :title, :with => /^[^,\.\/\?\;\|\s]*$/ 41 validates_format_of :title, :with => /^[^,\.\/\?\;\|\s]*$/
42 validates_uniqueness_of :title, :scope => :wiki_id, :case_sensitive => false 42 validates_uniqueness_of :title, :scope => :wiki_id, :case_sensitive => false
43 validates_associated :content 43 validates_associated :content
44 44
45 validate :validate_parent_title
46 before_destroy :remove_redirects
47 before_save :handle_redirects
48
45 # eager load information about last updates, without loading text 49 # eager load information about last updates, without loading text
46 named_scope :with_updated_on, { 50 named_scope :with_updated_on, {
47 :select => "#{WikiPage.table_name}.*, #{WikiContent.table_name}.updated_on", 51 :select => "#{WikiPage.table_name}.*, #{WikiContent.table_name}.updated_on",
48 :joins => "LEFT JOIN #{WikiContent.table_name} ON #{WikiContent.table_name}.page_id = #{WikiPage.table_name}.id" 52 :joins => "LEFT JOIN #{WikiContent.table_name} ON #{WikiContent.table_name}.page_id = #{WikiPage.table_name}.id"
49 } 53 }
50 54
51 # Wiki pages that are protected by default 55 # Wiki pages that are protected by default
52 DEFAULT_PROTECTED_PAGES = %w(sidebar) 56 DEFAULT_PROTECTED_PAGES = %w(sidebar)
53 57
54 def after_initialize 58 def after_initialize
55 if new_record? && DEFAULT_PROTECTED_PAGES.include?(title.to_s.downcase) 59 if new_record? && DEFAULT_PROTECTED_PAGES.include?(title.to_s.downcase)
56 self.protected = true 60 self.protected = true
57 end 61 end
58 end 62 end
59 63
60 def visible?(user=User.current) 64 def visible?(user=User.current)
61 !user.nil? && user.allowed_to?(:view_wiki_pages, project) 65 !user.nil? && user.allowed_to?(:view_wiki_pages, project)
62 end 66 end
63 67
64 def title=(value) 68 def title=(value)
65 value = Wiki.titleize(value) 69 value = Wiki.titleize(value)
66 @previous_title = read_attribute(:title) if @previous_title.blank? 70 @previous_title = read_attribute(:title) if @previous_title.blank?
67 write_attribute(:title, value) 71 write_attribute(:title, value)
68 end 72 end
69 73
70 def before_save 74 def handle_redirects
71 self.title = Wiki.titleize(title) 75 self.title = Wiki.titleize(title)
72 # Manage redirects if the title has changed 76 # Manage redirects if the title has changed
73 if !@previous_title.blank? && (@previous_title != title) && !new_record? 77 if !@previous_title.blank? && (@previous_title != title) && !new_record?
74 # Update redirects that point to the old title 78 # Update redirects that point to the old title
75 wiki.redirects.find_all_by_redirects_to(@previous_title).each do |r| 79 wiki.redirects.find_all_by_redirects_to(@previous_title).each do |r|
76 r.redirects_to = title 80 r.redirects_to = title
81 # Create a redirect to the new title 85 # Create a redirect to the new title
82 wiki.redirects << WikiRedirect.new(:title => @previous_title, :redirects_to => title) unless redirect_existing_links == "0" 86 wiki.redirects << WikiRedirect.new(:title => @previous_title, :redirects_to => title) unless redirect_existing_links == "0"
83 @previous_title = nil 87 @previous_title = nil
84 end 88 end
85 end 89 end
86 90
87 def before_destroy 91 def remove_redirects
88 # Remove redirects to this page 92 # Remove redirects to this page
89 wiki.redirects.find_all_by_redirects_to(title).each(&:destroy) 93 wiki.redirects.find_all_by_redirects_to(title).each(&:destroy)
90 end 94 end
91 95
92 def pretty_title 96 def pretty_title
93 WikiPage.pretty_title(title) 97 WikiPage.pretty_title(title)
94 end 98 end
95 99
96 def content_for_version(version=nil) 100 def content_for_version(version=nil)
97 result = content.versions.find_by_version(version.to_i) if version 101 result = content.versions.find_by_version(version.to_i) if version
98 result ||= content 102 result ||= content
99 result 103 result
100 end 104 end
101 105
102 def diff(version_to=nil, version_from=nil) 106 def diff(version_to=nil, version_from=nil)
103 version_to = version_to ? version_to.to_i : self.content.version 107 version_to = version_to ? version_to.to_i : self.content.version
104 version_from = version_from ? version_from.to_i : version_to - 1 108 version_from = version_from ? version_from.to_i : version_to - 1
105 version_to, version_from = version_from, version_to unless version_from < version_to 109 version_to, version_from = version_from, version_to unless version_from < version_to
106 110
107 content_to = content.versions.find_by_version(version_to) 111 content_to = content.versions.find_by_version(version_to)
108 content_from = content.versions.find_by_version(version_from) 112 content_from = content.versions.find_by_version(version_from)
109 113
110 (content_to && content_from) ? WikiDiff.new(content_to, content_from) : nil 114 (content_to && content_from) ? WikiDiff.new(content_to, content_from) : nil
111 end 115 end
112 116
113 def annotate(version=nil) 117 def annotate(version=nil)
114 version = version ? version.to_i : self.content.version 118 version = version ? version.to_i : self.content.version
115 c = content.versions.find_by_version(version) 119 c = content.versions.find_by_version(version)
116 c ? WikiAnnotate.new(c) : nil 120 c ? WikiAnnotate.new(c) : nil
117 end 121 end
118 122
119 def self.pretty_title(str) 123 def self.pretty_title(str)
120 (str && str.is_a?(String)) ? str.tr('_', ' ') : str 124 (str && str.is_a?(String)) ? str.tr('_', ' ') : str
121 end 125 end
122 126
123 def project 127 def project
124 wiki.project 128 wiki.project
125 end 129 end
126 130
127 def text 131 def text
128 content.text if content 132 content.text if content
129 end 133 end
130 134
131 def updated_on 135 def updated_on
132 unless @updated_on 136 unless @updated_on
133 if time = read_attribute(:updated_on) 137 if time = read_attribute(:updated_on)
134 # content updated_on was eager loaded with the page 138 # content updated_on was eager loaded with the page
135 @updated_on = Time.parse(time) rescue nil 139 @updated_on = Time.parse(time) rescue nil
137 @updated_on = content && content.updated_on 141 @updated_on = content && content.updated_on
138 end 142 end
139 end 143 end
140 @updated_on 144 @updated_on
141 end 145 end
142 146
143 # Returns true if usr is allowed to edit the page, otherwise false 147 # Returns true if usr is allowed to edit the page, otherwise false
144 def editable_by?(usr) 148 def editable_by?(usr)
145 !protected? || usr.allowed_to?(:protect_wiki_pages, wiki.project) 149 !protected? || usr.allowed_to?(:protect_wiki_pages, wiki.project)
146 end 150 end
147 151
148 def attachments_deletable?(usr=User.current) 152 def attachments_deletable?(usr=User.current)
149 editable_by?(usr) && super(usr) 153 editable_by?(usr) && super(usr)
150 end 154 end
151 155
152 def parent_title 156 def parent_title
153 @parent_title || (self.parent && self.parent.pretty_title) 157 @parent_title || (self.parent && self.parent.pretty_title)
154 end 158 end
155 159
156 def parent_title=(t) 160 def parent_title=(t)
157 @parent_title = t 161 @parent_title = t
158 parent_page = t.blank? ? nil : self.wiki.find_page(t) 162 parent_page = t.blank? ? nil : self.wiki.find_page(t)
159 self.parent = parent_page 163 self.parent = parent_page
160 end 164 end
161 165
162 protected 166 protected
163 167
164 def validate 168 def validate_parent_title
165 errors.add(:parent_title, :invalid) if !@parent_title.blank? && parent.nil? 169 errors.add(:parent_title, :invalid) if !@parent_title.blank? && parent.nil?
166 errors.add(:parent_title, :circular_dependency) if parent && (parent == self || parent.ancestors.include?(self)) 170 errors.add(:parent_title, :circular_dependency) if parent && (parent == self || parent.ancestors.include?(self))
167 errors.add(:parent_title, :not_same_project) if parent && (parent.wiki_id != wiki_id) 171 errors.add(:parent_title, :not_same_project) if parent && (parent.wiki_id != wiki_id)
168 end 172 end
169 end 173 end
170 174
171 class WikiDiff < Redmine::Helpers::Diff 175 class WikiDiff < Redmine::Helpers::Diff
172 attr_reader :content_to, :content_from 176 attr_reader :content_to, :content_from
173 177
174 def initialize(content_to, content_from) 178 def initialize(content_to, content_from)
175 @content_to = content_to 179 @content_to = content_to
176 @content_from = content_from 180 @content_from = content_from
177 super(content_to.text, content_from.text) 181 super(content_to.text, content_from.text)
178 end 182 end
179 end 183 end
180 184
181 class WikiAnnotate 185 class WikiAnnotate
182 attr_reader :lines, :content 186 attr_reader :lines, :content
183 187
184 def initialize(content) 188 def initialize(content)
185 @content = content 189 @content = content
186 current = content 190 current = content
187 current_lines = current.text.split(/\r?\n/) 191 current_lines = current.text.split(/\r?\n/)
188 @lines = current_lines.collect {|t| [nil, nil, t]} 192 @lines = current_lines.collect {|t| [nil, nil, t]}
210 positions.compact! 214 positions.compact!
211 # Stop if every line is annotated 215 # Stop if every line is annotated
212 break unless @lines.detect { |line| line[0].nil? } 216 break unless @lines.detect { |line| line[0].nil? }
213 current = current.previous 217 current = current.previous
214 end 218 end
215 @lines.each { |line| 219 @lines.each { |line|
216 line[0] ||= current.version 220 line[0] ||= current.version
217 # if the last known version is > 1 (eg. history was cleared), we don't know the author 221 # if the last known version is > 1 (eg. history was cleared), we don't know the author
218 line[1] ||= current.author if current.version == 1 222 line[1] ||= current.author if current.version == 1
219 } 223 }
220 end 224 end