##// END OF EJS Templates
remove trailing white-spaces from app/models/wiki_page.rb....
Toshi MARUYAMA -
r6391:ff8af0ea2e4a
parent child
Show More
@@ -1,221 +1,221
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2011 Jean-Philippe Lang
2 # Copyright (C) 2006-2011 Jean-Philippe Lang
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'
19 require 'enumerator'
19 require 'enumerator'
20
20
21 class WikiPage < ActiveRecord::Base
21 class WikiPage < ActiveRecord::Base
22 belongs_to :wiki
22 belongs_to :wiki
23 has_one :content, :class_name => 'WikiContent', :foreign_key => 'page_id', :dependent => :destroy
23 has_one :content, :class_name => 'WikiContent', :foreign_key => 'page_id', :dependent => :destroy
24 acts_as_attachable :delete_permission => :delete_wiki_pages_attachments
24 acts_as_attachable :delete_permission => :delete_wiki_pages_attachments
25 acts_as_tree :dependent => :nullify, :order => 'title'
25 acts_as_tree :dependent => :nullify, :order => 'title'
26
26
27 acts_as_watchable
27 acts_as_watchable
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', '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 # eager load information about last updates, without loading text
45 # eager load information about last updates, without loading text
46 named_scope :with_updated_on, {
46 named_scope :with_updated_on, {
47 :select => "#{WikiPage.table_name}.*, #{WikiContent.table_name}.updated_on",
47 :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"
48 :joins => "LEFT JOIN #{WikiContent.table_name} ON #{WikiContent.table_name}.page_id = #{WikiPage.table_name}.id"
49 }
49 }
50
50
51 # Wiki pages that are protected by default
51 # Wiki pages that are protected by default
52 DEFAULT_PROTECTED_PAGES = %w(sidebar)
52 DEFAULT_PROTECTED_PAGES = %w(sidebar)
53
53
54 def after_initialize
54 def after_initialize
55 if new_record? && DEFAULT_PROTECTED_PAGES.include?(title.to_s.downcase)
55 if new_record? && DEFAULT_PROTECTED_PAGES.include?(title.to_s.downcase)
56 self.protected = true
56 self.protected = true
57 end
57 end
58 end
58 end
59
59
60 def visible?(user=User.current)
60 def visible?(user=User.current)
61 !user.nil? && user.allowed_to?(:view_wiki_pages, project)
61 !user.nil? && user.allowed_to?(:view_wiki_pages, project)
62 end
62 end
63
63
64 def title=(value)
64 def title=(value)
65 value = Wiki.titleize(value)
65 value = Wiki.titleize(value)
66 @previous_title = read_attribute(:title) if @previous_title.blank?
66 @previous_title = read_attribute(:title) if @previous_title.blank?
67 write_attribute(:title, value)
67 write_attribute(:title, value)
68 end
68 end
69
69
70 def before_save
70 def before_save
71 self.title = Wiki.titleize(title)
71 self.title = Wiki.titleize(title)
72 # Manage redirects if the title has changed
72 # Manage redirects if the title has changed
73 if !@previous_title.blank? && (@previous_title != title) && !new_record?
73 if !@previous_title.blank? && (@previous_title != title) && !new_record?
74 # Update redirects that point to the old title
74 # Update redirects that point to the old title
75 wiki.redirects.find_all_by_redirects_to(@previous_title).each do |r|
75 wiki.redirects.find_all_by_redirects_to(@previous_title).each do |r|
76 r.redirects_to = title
76 r.redirects_to = title
77 r.title == r.redirects_to ? r.destroy : r.save
77 r.title == r.redirects_to ? r.destroy : r.save
78 end
78 end
79 # Remove redirects for the new title
79 # Remove redirects for the new title
80 wiki.redirects.find_all_by_title(title).each(&:destroy)
80 wiki.redirects.find_all_by_title(title).each(&:destroy)
81 # Create a redirect to the new title
81 # Create a redirect to the new title
82 wiki.redirects << WikiRedirect.new(:title => @previous_title, :redirects_to => title) unless redirect_existing_links == "0"
82 wiki.redirects << WikiRedirect.new(:title => @previous_title, :redirects_to => title) unless redirect_existing_links == "0"
83 @previous_title = nil
83 @previous_title = nil
84 end
84 end
85 end
85 end
86
86
87 def before_destroy
87 def before_destroy
88 # Remove redirects to this page
88 # Remove redirects to this page
89 wiki.redirects.find_all_by_redirects_to(title).each(&:destroy)
89 wiki.redirects.find_all_by_redirects_to(title).each(&:destroy)
90 end
90 end
91
91
92 def pretty_title
92 def pretty_title
93 WikiPage.pretty_title(title)
93 WikiPage.pretty_title(title)
94 end
94 end
95
95
96 def content_for_version(version=nil)
96 def content_for_version(version=nil)
97 result = content.versions.find_by_version(version.to_i) if version
97 result = content.versions.find_by_version(version.to_i) if version
98 result ||= content
98 result ||= content
99 result
99 result
100 end
100 end
101
101
102 def diff(version_to=nil, version_from=nil)
102 def diff(version_to=nil, version_from=nil)
103 version_to = version_to ? version_to.to_i : self.content.version
103 version_to = version_to ? version_to.to_i : self.content.version
104 version_from = version_from ? version_from.to_i : version_to - 1
104 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
105 version_to, version_from = version_from, version_to unless version_from < version_to
106
106
107 content_to = content.versions.find_by_version(version_to)
107 content_to = content.versions.find_by_version(version_to)
108 content_from = content.versions.find_by_version(version_from)
108 content_from = content.versions.find_by_version(version_from)
109
109
110 (content_to && content_from) ? WikiDiff.new(content_to, content_from) : nil
110 (content_to && content_from) ? WikiDiff.new(content_to, content_from) : nil
111 end
111 end
112
112
113 def annotate(version=nil)
113 def annotate(version=nil)
114 version = version ? version.to_i : self.content.version
114 version = version ? version.to_i : self.content.version
115 c = content.versions.find_by_version(version)
115 c = content.versions.find_by_version(version)
116 c ? WikiAnnotate.new(c) : nil
116 c ? WikiAnnotate.new(c) : nil
117 end
117 end
118
118
119 def self.pretty_title(str)
119 def self.pretty_title(str)
120 (str && str.is_a?(String)) ? str.tr('_', ' ') : str
120 (str && str.is_a?(String)) ? str.tr('_', ' ') : str
121 end
121 end
122
122
123 def project
123 def project
124 wiki.project
124 wiki.project
125 end
125 end
126
126
127 def text
127 def text
128 content.text if content
128 content.text if content
129 end
129 end
130
130
131 def updated_on
131 def updated_on
132 unless @updated_on
132 unless @updated_on
133 if time = read_attribute(:updated_on)
133 if time = read_attribute(:updated_on)
134 # content updated_on was eager loaded with the page
134 # content updated_on was eager loaded with the page
135 @updated_on = Time.parse(time) rescue nil
135 @updated_on = Time.parse(time) rescue nil
136 else
136 else
137 @updated_on = content && content.updated_on
137 @updated_on = content && content.updated_on
138 end
138 end
139 end
139 end
140 @updated_on
140 @updated_on
141 end
141 end
142
142
143 # Returns true if usr is allowed to edit the page, otherwise false
143 # Returns true if usr is allowed to edit the page, otherwise false
144 def editable_by?(usr)
144 def editable_by?(usr)
145 !protected? || usr.allowed_to?(:protect_wiki_pages, wiki.project)
145 !protected? || usr.allowed_to?(:protect_wiki_pages, wiki.project)
146 end
146 end
147
147
148 def attachments_deletable?(usr=User.current)
148 def attachments_deletable?(usr=User.current)
149 editable_by?(usr) && super(usr)
149 editable_by?(usr) && super(usr)
150 end
150 end
151
151
152 def parent_title
152 def parent_title
153 @parent_title || (self.parent && self.parent.pretty_title)
153 @parent_title || (self.parent && self.parent.pretty_title)
154 end
154 end
155
155
156 def parent_title=(t)
156 def parent_title=(t)
157 @parent_title = t
157 @parent_title = t
158 parent_page = t.blank? ? nil : self.wiki.find_page(t)
158 parent_page = t.blank? ? nil : self.wiki.find_page(t)
159 self.parent = parent_page
159 self.parent = parent_page
160 end
160 end
161
161
162 protected
162 protected
163
163
164 def validate
164 def validate
165 errors.add(:parent_title, :invalid) if !@parent_title.blank? && parent.nil?
165 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))
166 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)
167 errors.add(:parent_title, :not_same_project) if parent && (parent.wiki_id != wiki_id)
168 end
168 end
169 end
169 end
170
170
171 class WikiDiff < Redmine::Helpers::Diff
171 class WikiDiff < Redmine::Helpers::Diff
172 attr_reader :content_to, :content_from
172 attr_reader :content_to, :content_from
173
173
174 def initialize(content_to, content_from)
174 def initialize(content_to, content_from)
175 @content_to = content_to
175 @content_to = content_to
176 @content_from = content_from
176 @content_from = content_from
177 super(content_to.text, content_from.text)
177 super(content_to.text, content_from.text)
178 end
178 end
179 end
179 end
180
180
181 class WikiAnnotate
181 class WikiAnnotate
182 attr_reader :lines, :content
182 attr_reader :lines, :content
183
183
184 def initialize(content)
184 def initialize(content)
185 @content = content
185 @content = content
186 current = content
186 current = content
187 current_lines = current.text.split(/\r?\n/)
187 current_lines = current.text.split(/\r?\n/)
188 @lines = current_lines.collect {|t| [nil, nil, t]}
188 @lines = current_lines.collect {|t| [nil, nil, t]}
189 positions = []
189 positions = []
190 current_lines.size.times {|i| positions << i}
190 current_lines.size.times {|i| positions << i}
191 while (current.previous)
191 while (current.previous)
192 d = current.previous.text.split(/\r?\n/).diff(current.text.split(/\r?\n/)).diffs.flatten
192 d = current.previous.text.split(/\r?\n/).diff(current.text.split(/\r?\n/)).diffs.flatten
193 d.each_slice(3) do |s|
193 d.each_slice(3) do |s|
194 sign, line = s[0], s[1]
194 sign, line = s[0], s[1]
195 if sign == '+' && positions[line] && positions[line] != -1
195 if sign == '+' && positions[line] && positions[line] != -1
196 if @lines[positions[line]][0].nil?
196 if @lines[positions[line]][0].nil?
197 @lines[positions[line]][0] = current.version
197 @lines[positions[line]][0] = current.version
198 @lines[positions[line]][1] = current.author
198 @lines[positions[line]][1] = current.author
199 end
199 end
200 end
200 end
201 end
201 end
202 d.each_slice(3) do |s|
202 d.each_slice(3) do |s|
203 sign, line = s[0], s[1]
203 sign, line = s[0], s[1]
204 if sign == '-'
204 if sign == '-'
205 positions.insert(line, -1)
205 positions.insert(line, -1)
206 else
206 else
207 positions[line] = nil
207 positions[line] = nil
208 end
208 end
209 end
209 end
210 positions.compact!
210 positions.compact!
211 # Stop if every line is annotated
211 # Stop if every line is annotated
212 break unless @lines.detect { |line| line[0].nil? }
212 break unless @lines.detect { |line| line[0].nil? }
213 current = current.previous
213 current = current.previous
214 end
214 end
215 @lines.each { |line|
215 @lines.each { |line|
216 line[0] ||= current.version
216 line[0] ||= current.version
217 # if the last known version is > 1 (eg. history was cleared), we don't know the author
217 # 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
218 line[1] ||= current.author if current.version == 1
219 }
219 }
220 end
220 end
221 end
221 end
General Comments 0
You need to be logged in to leave comments. Login now