##// END OF EJS Templates
Rails4: replace deprecated find_all_by_* at WikiPage model...
Toshi MARUYAMA -
r12258:95d86daef3aa
parent child
Show More
@@ -1,252 +1,252
1 1 # Redmine - project management software
2 2 # Copyright (C) 2006-2013 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 include Redmine::SafeAttributes
23 23
24 24 belongs_to :wiki
25 25 has_one :content, :class_name => 'WikiContent', :foreign_key => 'page_id', :dependent => :destroy
26 26 acts_as_attachable :delete_permission => :delete_wiki_pages_attachments
27 27 acts_as_tree :dependent => :nullify, :order => 'title'
28 28
29 29 acts_as_watchable
30 30 acts_as_event :title => Proc.new {|o| "#{l(:label_wiki)}: #{o.title}"},
31 31 :description => :text,
32 32 :datetime => :created_on,
33 33 :url => Proc.new {|o| {:controller => 'wiki', :action => 'show', :project_id => o.wiki.project, :id => o.title}}
34 34
35 35 acts_as_searchable :columns => ['title', "#{WikiContent.table_name}.text"],
36 36 :include => [{:wiki => :project}, :content],
37 37 :permission => :view_wiki_pages,
38 38 :project_key => "#{Wiki.table_name}.project_id"
39 39
40 40 attr_accessor :redirect_existing_links
41 41
42 42 validates_presence_of :title
43 43 validates_format_of :title, :with => /\A[^,\.\/\?\;\|\s]*\z/
44 44 validates_uniqueness_of :title, :scope => :wiki_id, :case_sensitive => false
45 45 validates_associated :content
46 46
47 47 validate :validate_parent_title
48 48 before_destroy :remove_redirects
49 49 before_save :handle_redirects
50 50
51 51 # eager load information about last updates, without loading text
52 52 scope :with_updated_on, lambda {
53 53 select("#{WikiPage.table_name}.*, #{WikiContent.table_name}.updated_on, #{WikiContent.table_name}.version").
54 54 joins("LEFT JOIN #{WikiContent.table_name} ON #{WikiContent.table_name}.page_id = #{WikiPage.table_name}.id")
55 55 }
56 56
57 57 # Wiki pages that are protected by default
58 58 DEFAULT_PROTECTED_PAGES = %w(sidebar)
59 59
60 60 safe_attributes 'parent_id', 'parent_title',
61 61 :if => lambda {|page, user| page.new_record? || user.allowed_to?(:rename_wiki_pages, page.project)}
62 62
63 63 def initialize(attributes=nil, *args)
64 64 super
65 65 if new_record? && DEFAULT_PROTECTED_PAGES.include?(title.to_s.downcase)
66 66 self.protected = true
67 67 end
68 68 end
69 69
70 70 def visible?(user=User.current)
71 71 !user.nil? && user.allowed_to?(:view_wiki_pages, project)
72 72 end
73 73
74 74 def title=(value)
75 75 value = Wiki.titleize(value)
76 76 @previous_title = read_attribute(:title) if @previous_title.blank?
77 77 write_attribute(:title, value)
78 78 end
79 79
80 80 def handle_redirects
81 81 self.title = Wiki.titleize(title)
82 82 # Manage redirects if the title has changed
83 83 if !@previous_title.blank? && (@previous_title != title) && !new_record?
84 84 # Update redirects that point to the old title
85 wiki.redirects.find_all_by_redirects_to(@previous_title).each do |r|
85 wiki.redirects.where(:redirects_to => @previous_title).each do |r|
86 86 r.redirects_to = title
87 87 r.title == r.redirects_to ? r.destroy : r.save
88 88 end
89 89 # Remove redirects for the new title
90 90 wiki.redirects.where(:title => title).all.each(&:destroy)
91 91 # Create a redirect to the new title
92 92 wiki.redirects << WikiRedirect.new(:title => @previous_title, :redirects_to => title) unless redirect_existing_links == "0"
93 93 @previous_title = nil
94 94 end
95 95 end
96 96
97 97 def remove_redirects
98 98 # Remove redirects to this page
99 wiki.redirects.find_all_by_redirects_to(title).each(&:destroy)
99 wiki.redirects.where(:redirects_to => title).each(&:destroy)
100 100 end
101 101
102 102 def pretty_title
103 103 WikiPage.pretty_title(title)
104 104 end
105 105
106 106 def content_for_version(version=nil)
107 107 result = content.versions.find_by_version(version.to_i) if version
108 108 result ||= content
109 109 result
110 110 end
111 111
112 112 def diff(version_to=nil, version_from=nil)
113 113 version_to = version_to ? version_to.to_i : self.content.version
114 114 content_to = content.versions.find_by_version(version_to)
115 115 content_from = version_from ? content.versions.find_by_version(version_from.to_i) : content_to.try(:previous)
116 116 return nil unless content_to && content_from
117 117
118 118 if content_from.version > content_to.version
119 119 content_to, content_from = content_from, content_to
120 120 end
121 121
122 122 (content_to && content_from) ? WikiDiff.new(content_to, content_from) : nil
123 123 end
124 124
125 125 def annotate(version=nil)
126 126 version = version ? version.to_i : self.content.version
127 127 c = content.versions.find_by_version(version)
128 128 c ? WikiAnnotate.new(c) : nil
129 129 end
130 130
131 131 def self.pretty_title(str)
132 132 (str && str.is_a?(String)) ? str.tr('_', ' ') : str
133 133 end
134 134
135 135 def project
136 136 wiki.project
137 137 end
138 138
139 139 def text
140 140 content.text if content
141 141 end
142 142
143 143 def updated_on
144 144 unless @updated_on
145 145 if time = read_attribute(:updated_on)
146 146 # content updated_on was eager loaded with the page
147 147 begin
148 148 @updated_on = (self.class.default_timezone == :utc ? Time.parse(time.to_s).utc : Time.parse(time.to_s).localtime)
149 149 rescue
150 150 end
151 151 else
152 152 @updated_on = content && content.updated_on
153 153 end
154 154 end
155 155 @updated_on
156 156 end
157 157
158 158 # Returns true if usr is allowed to edit the page, otherwise false
159 159 def editable_by?(usr)
160 160 !protected? || usr.allowed_to?(:protect_wiki_pages, wiki.project)
161 161 end
162 162
163 163 def attachments_deletable?(usr=User.current)
164 164 editable_by?(usr) && super(usr)
165 165 end
166 166
167 167 def parent_title
168 168 @parent_title || (self.parent && self.parent.pretty_title)
169 169 end
170 170
171 171 def parent_title=(t)
172 172 @parent_title = t
173 173 parent_page = t.blank? ? nil : self.wiki.find_page(t)
174 174 self.parent = parent_page
175 175 end
176 176
177 177 # Saves the page and its content if text was changed
178 178 def save_with_content(content)
179 179 ret = nil
180 180 transaction do
181 181 self.content = content
182 182 if new_record?
183 183 # Rails automatically saves associated content
184 184 ret = save
185 185 else
186 186 ret = save && (content.text_changed? ? content.save : true)
187 187 end
188 188 raise ActiveRecord::Rollback unless ret
189 189 end
190 190 ret
191 191 end
192 192
193 193 protected
194 194
195 195 def validate_parent_title
196 196 errors.add(:parent_title, :invalid) if !@parent_title.blank? && parent.nil?
197 197 errors.add(:parent_title, :circular_dependency) if parent && (parent == self || parent.ancestors.include?(self))
198 198 errors.add(:parent_title, :not_same_project) if parent && (parent.wiki_id != wiki_id)
199 199 end
200 200 end
201 201
202 202 class WikiDiff < Redmine::Helpers::Diff
203 203 attr_reader :content_to, :content_from
204 204
205 205 def initialize(content_to, content_from)
206 206 @content_to = content_to
207 207 @content_from = content_from
208 208 super(content_to.text, content_from.text)
209 209 end
210 210 end
211 211
212 212 class WikiAnnotate
213 213 attr_reader :lines, :content
214 214
215 215 def initialize(content)
216 216 @content = content
217 217 current = content
218 218 current_lines = current.text.split(/\r?\n/)
219 219 @lines = current_lines.collect {|t| [nil, nil, t]}
220 220 positions = []
221 221 current_lines.size.times {|i| positions << i}
222 222 while (current.previous)
223 223 d = current.previous.text.split(/\r?\n/).diff(current.text.split(/\r?\n/)).diffs.flatten
224 224 d.each_slice(3) do |s|
225 225 sign, line = s[0], s[1]
226 226 if sign == '+' && positions[line] && positions[line] != -1
227 227 if @lines[positions[line]][0].nil?
228 228 @lines[positions[line]][0] = current.version
229 229 @lines[positions[line]][1] = current.author
230 230 end
231 231 end
232 232 end
233 233 d.each_slice(3) do |s|
234 234 sign, line = s[0], s[1]
235 235 if sign == '-'
236 236 positions.insert(line, -1)
237 237 else
238 238 positions[line] = nil
239 239 end
240 240 end
241 241 positions.compact!
242 242 # Stop if every line is annotated
243 243 break unless @lines.detect { |line| line[0].nil? }
244 244 current = current.previous
245 245 end
246 246 @lines.each { |line|
247 247 line[0] ||= current.version
248 248 # if the last known version is > 1 (eg. history was cleared), we don't know the author
249 249 line[1] ||= current.author if current.version == 1
250 250 }
251 251 end
252 252 end
General Comments 0
You need to be logged in to leave comments. Login now