Changesets can be listed by changeset number.
The Git repository is here.
- Revision:
- 344
- Log:
Massive changeset which brings the old, ROOL customised Instiki
version up to date, but without any ROOL customisations in this
latest checked-in version (which is 0.19.1). This is deliberate,
so that it's easy to see the changes made for the ROOL version
in a subsequent changeset. The 'app/views/shared' directory is not
part of Instiki but is kept to maintain the change history with
updated ROOL customisations, some of which involve the same files
in that same directory.
- Author:
- rool
- Date:
- Sat Mar 19 19:52:13 +0000 2011
- Size:
- 19781 Bytes
1 | require 'fileutils' |
2 | require 'maruku' |
3 | require 'maruku/ext/math' |
4 | require 'zip/zip' |
5 | require 'instiki_stringsupport' |
6 | require 'resolv' |
7 | |
8 | class WikiController < ApplicationController |
9 | |
10 | before_filter :load_page |
11 | before_filter :dnsbl_check, :only => [:edit, :new, :save, :export_html, :export_markup] |
12 | caches_action :show, :published, :authors, :tex, :s5, :print, :recently_revised, :list, :file_list, :source, |
13 | :history, :revision, :atom_with_content, :atom_with_headlines, :if => Proc.new { |c| c.send(:do_caching?) } |
14 | cache_sweeper :revision_sweeper |
15 | |
16 | layout 'default', :except => [:atom_with_content, :atom_with_headlines, :atom, :source, :tex, :s5, :export_html] |
17 | |
18 | def index |
19 | if @web_name |
20 | redirect_home |
21 | elsif not @wiki.setup? |
22 | redirect_to :controller => 'admin', :action => 'create_system' |
23 | elsif @wiki.webs.size == 1 |
24 | redirect_home @wiki.webs.values.first.address |
25 | else |
26 | redirect_to :action => 'web_list' |
27 | end |
28 | end |
29 | |
30 | # Outside a single web -------------------------------------------------------- |
31 | |
32 | def authenticate |
33 | if password_check(params['password']) |
34 | redirect_home |
35 | else |
36 | flash[:info] = password_error(params['password']) |
37 | redirect_to :action => 'login', :web => @web_name |
38 | end |
39 | end |
40 | |
41 | def login |
42 | # to template |
43 | end |
44 | |
45 | def web_list |
46 | @webs = wiki.webs.values.sort_by { |web| web.name } |
47 | end |
48 | |
49 | |
50 | # Within a single web --------------------------------------------------------- |
51 | |
52 | def authors |
53 | @page_names_by_author = @web.page_names_by_author |
54 | @authors = @page_names_by_author.keys.sort |
55 | end |
56 | |
57 | def file_list |
58 | sort_order = params['sort_order'] || 'file_name' |
59 | case sort_order |
60 | when 'file_name' |
61 | @alt_sort_order = 'created_at' |
62 | @alt_sort_name = 'date' |
63 | else |
64 | @alt_sort_order = 'file_name' |
65 | @alt_sort_name = 'filename' |
66 | end |
67 | @file_list = @web.file_list(sort_order) |
68 | end |
69 | |
70 | def export_html |
71 | export_pages_as_zip(html_ext) do |page| |
72 | renderer = PageRenderer.new(page.revisions.last) |
73 | rendered_page = <<-EOL |
74 | <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1 plus MathML 2.0 plus SVG 1.1//EN" "http://www.w3.org/2002/04/xhtml-math-svg/xhtml-math-svg-flat.dtd" > |
75 | <html xmlns="http://www.w3.org/1999/xhtml"> |
76 | <head> |
77 | <title>#{page.plain_name} in #{@web.name}</title> |
78 | <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> |
79 | |
80 | <script src="public/javascripts/page_helper.js" type="text/javascript"></script> |
81 | <link href="public/stylesheets/instiki.css" media="all" rel="stylesheet" type="text/css" /> |
82 | <link href="public/stylesheets/syntax.css" media="all" rel="stylesheet" type="text/css" /> |
83 | <style type="text/css"> |
84 | h1#pageName, div.info, .newWikiWord a, a.existingWikiWord, .newWikiWord a:hover, [actiontype="toggle"]:hover, #TextileHelp h3 { |
85 | color: ##{@web ? @web.color : "393"}; |
86 | } |
87 | a:visited.existingWikiWord { |
88 | color: ##{darken(@web ? @web.color : "393")}; |
89 | } |
90 | </style> |
91 | |
92 | <style type="text/css"><!--/*--><![CDATA[/*><!--*/ |
93 | #{@web ? @web.additional_style : ''} |
94 | /*]]>*/--></style> |
95 | <script src="public/javascripts/prototype.js" type="text/javascript"></script> |
96 | <script src="public/javascripts/effects.js" type="text/javascript"></script> |
97 | <script src="public/javascripts/dragdrop.js" type="text/javascript"></script> |
98 | <script src="public/javascripts/controls.js" type="text/javascript"></script> |
99 | <script src="public/javascripts/application.js" type="text/javascript"></script> |
100 | |
101 | </head> |
102 | <body> |
103 | <div id="Container"> |
104 | <div id="Content"> |
105 | <h1 id="pageName"> |
106 | #{xhtml_enabled? ? %{<span id="svg_logo"><svg version="1.1" width="100%" height="100%" viewBox='0 -1 180 198' xmlns='http://www.w3.org/2000/svg'> |
107 | <path id="svg_logo_path" fill="##{@web ? @web.color : "393"}" stroke-width='0.5' stroke='#000' d=' |
108 | M170,60c4,11-1,20-12,25c-9,4-25,3-20,15c5,5,15,0,24,1c11,1,21,11,14,21c-10,15-35,6-48-1c-5-3-27-23-32-10c-1,13,15,10,22,16 |
109 | c11,4,24,14,34,20c12,10,7,25-9,23c-11-1-22-9-30-16c-5-5-13-18-21-9c-2,6,2,11,5,14c9,9,22,14,22,31c-2,8-12,8-18,4c-4-3-9-8-11-13 |
110 | c-3-6-5-18-12-18c-14-1-5,28-18,30c-9,2-13-9-12-16c1-14,12-24,21-31c5-4,17-13,10-20c-9-10-19,12-23,16c-7,7-17,16-31,15 |
111 | c-9-1-18-9-11-17c5-7,14-4,23-6c6-1,15-8,8-15c-5-6-57,2-42-24c7-12,51,4,61,6c6,1,17,4,18-4c2-11-12-7-21-8c-21-2-49-14-49-34 |
112 | c0-5,3-11,8-11C31,42,34,65,42,67c6,1,9-3,8-9C49,49,38,40,40,25c1-5,4-15,13-14c10,2,11,18,13,29c1,8,0,24,7,28c15,0,5-22,4-30 |
113 | C74,23,78,7,87,1c8-4,14,1,16,9c2,11-8,21-2,30c8,2,11-6,14-12c9-14,36-18,30,5c-3,9-12,19-21,24c-6,4-22,10-23,19c-2,14,15,2,18-2 |
114 | c9-9,20-18,33-22C159,52,166,54,170,60' /> |
115 | </svg></span>} : ''} |
116 | <span class="webName">#{@web.name}</span><br /> |
117 | #{page.plain_name} |
118 | </h1> |
119 | #{renderer.display_content_for_export} |
120 | <div class="byline"> |
121 | #{page.revisions? ? "Revised" : "Created" } on #{ page.revised_at.strftime('%B %d, %Y %H:%M:%S') } |
122 | by |
123 | #{ UrlGenerator.new(self).make_link(@web, page.author.name, @web, nil, { :mode => :export }) } |
124 | </div> |
125 | </div> |
126 | </div> |
127 | </body> |
128 | </html> |
129 | EOL |
130 | rendered_page |
131 | end |
132 | end |
133 | |
134 | def export_markup |
135 | export_pages_as_zip(@web.markup) { |page| page.content } |
136 | end |
137 | |
138 | # def export_pdf |
139 | # file_name = "#{@web.address}-tex-#{@web.revised_at.strftime('%Y-%m-%d-%H-%M-%S')}" |
140 | # file_path = File.join(@wiki.storage_path, file_name) |
141 | # |
142 | # export_web_to_tex "#{file_path}.tex" unless FileTest.exists? "#{file_path}.tex" |
143 | # convert_tex_to_pdf "#{file_path}.tex" |
144 | # send_file "#{file_path}.pdf" |
145 | # end |
146 | |
147 | # def export_tex |
148 | # file_name = "#{@web.address}-tex-#{@web.revised_at.strftime('%Y-%m-%d-%H-%M-%S')}.tex" |
149 | # file_path = File.join(@wiki.storage_path, file_name) |
150 | # export_web_to_tex(file_path) unless FileTest.exists?(file_path) |
151 | # send_file file_path |
152 | # end |
153 | |
154 | def feeds |
155 | @rss_with_content_allowed = rss_with_content_allowed? |
156 | # show the template |
157 | end |
158 | |
159 | def list |
160 | parse_category |
161 | @page_names_that_are_wanted = @pages_in_category.wanted_pages |
162 | @pages_that_are_orphaned = @pages_in_category.orphaned_pages |
163 | end |
164 | |
165 | def recently_revised |
166 | parse_category |
167 | @pages_by_revision = @pages_in_category.by_revision |
168 | @pages_by_day = Hash.new { |h, day| h[day] = [] } |
169 | @pages_by_revision.each do |page| |
170 | day = Date.new(page.revised_at.year, page.revised_at.month, page.revised_at.day) |
171 | @pages_by_day[day] << page |
172 | end |
173 | end |
174 | |
175 | def atom_with_content |
176 | if rss_with_content_allowed? |
177 | render_atom(hide_description = false) |
178 | else |
179 | render :text => 'Atom feed with content for this web is blocked for security reasons. ' + |
180 | 'The web is password-protected and not published', :status => 403, :layout => 'error' |
181 | end |
182 | end |
183 | |
184 | def atom_with_headlines |
185 | render_atom(hide_description = true) |
186 | end |
187 | |
188 | def tex_list |
189 | return unless is_post |
190 | if [:markdownMML, :markdownPNG, :markdown].include?(@web.markup) |
191 | @tex_content = '' |
192 | # Ruby 1.9.x has ordered hashes; 1.8.x doesn't. So let's just parse the query ourselves. |
193 | ordered_params = ActiveSupport::OrderedHash[*request.raw_post.split('&').collect {|k_v| k_v.split('=').collect {|x| CGI::unescape(x)}}.flatten] |
194 | ordered_params.each do |name, p| |
195 | if p == 'tex' && @web.has_page?(name) |
196 | @tex_content << "\\section*\{#{Maruku.new(name).to_latex.strip}\}\n\n" |
197 | @tex_content << Maruku.new(@web.page(name).content).to_latex |
198 | end |
199 | end |
200 | else |
201 | @tex_content = 'TeX export only supported with the Markdown text filters.' |
202 | end |
203 | if @tex_content == '' |
204 | flash[:error] = "You didn't select any pages to export." |
205 | redirect_to :back |
206 | return |
207 | end |
208 | expire_action :controller => 'wiki', :web => @web.address, :action => 'list', :category => params['category'] |
209 | render(:layout => 'tex') |
210 | end |
211 | |
212 | |
213 | def search |
214 | @query = params['query'].purify |
215 | @title_results = @web.select { |page| page.name =~ /#{@query}/i }.sort |
216 | @results = @web.select { |page| page.content =~ /#{@query}/i }.sort |
217 | all_pages_found = (@results + @title_results).uniq |
218 | if all_pages_found.size == 1 |
219 | redirect_to_page(all_pages_found.first.name) |
220 | end |
221 | end |
222 | |
223 | # Within a single page -------------------------------------------------------- |
224 | |
225 | def cancel_edit |
226 | @page.unlock |
227 | redirect_to_page(@page_name) |
228 | end |
229 | |
230 | def edit |
231 | if @page.nil? |
232 | redirect_home |
233 | elsif @page.locked?(Time.now) and not params['break_lock'] |
234 | redirect_to :web => @web_name, :action => 'locked', :id => @page_name |
235 | else |
236 | @page.lock(Time.now, @author) |
237 | end |
238 | end |
239 | |
240 | def locked |
241 | # to template |
242 | end |
243 | |
244 | def new |
245 | # to template |
246 | end |
247 | |
248 | # def pdf |
249 | # page = wiki.read_page(@web_name, @page_name) |
250 | # safe_page_name = @page.name.gsub(/\W/, '') |
251 | # file_name = "#{safe_page_name}-#{@web.address}-#{@page.revised_at.strftime('%Y-%m-%d-%H-%M-%S')}" |
252 | # file_path = File.join(@wiki.storage_path, file_name) |
253 | # |
254 | # export_page_to_tex("#{file_path}.tex") unless FileTest.exists?("#{file_path}.tex") |
255 | # # NB: this is _very_ slow |
256 | # convert_tex_to_pdf("#{file_path}.tex") |
257 | # send_file "#{file_path}.pdf" |
258 | # end |
259 | |
260 | def print |
261 | if @page.nil? |
262 | redirect_home |
263 | end |
264 | @link_mode ||= :show |
265 | @renderer = PageRenderer.new(@page.revisions.last) |
266 | # to template |
267 | end |
268 | |
269 | def published |
270 | if not @web.published? |
271 | render(:text => "Published version of web '#{@web_name}' is not available", :status => 404, :layout => 'error') |
272 | return |
273 | end |
274 | |
275 | @page_name ||= 'HomePage' |
276 | @page ||= wiki.read_page(@web_name, @page_name) |
277 | @link_mode ||= :publish |
278 | if @page |
279 | @renderer = PageRenderer.new(@page.revisions.last) |
280 | else |
281 | real_page = WikiReference.page_that_redirects_for(@web, @page_name) |
282 | if real_page |
283 | flash[:info] = "Redirected from \"#{@page_name}\"." |
284 | redirect_to :web => @web_name, :action => 'published', :id => real_page, :status => 301 |
285 | else |
286 | render(:text => "Page '#{@page_name}' not found", :status => 404, :layout => 'error') |
287 | end |
288 | end |
289 | end |
290 | |
291 | def revision |
292 | get_page_and_revision |
293 | @show_diff = (params[:mode] == 'diff') |
294 | @renderer = PageRenderer.new(@revision) |
295 | end |
296 | |
297 | def rollback |
298 | get_page_and_revision |
299 | if @page.locked?(Time.now) and not params['break_lock'] |
300 | redirect_to :web => @web_name, :action => 'locked', :id => @page_name |
301 | else |
302 | @page.lock(Time.now, @author) |
303 | end |
304 | end |
305 | |
306 | def save |
307 | render(:status => 404, :text => 'Undefined page name', :layout => 'error') and return if @page_name.nil? |
308 | return unless is_post |
309 | author_name = params['author'].purify |
310 | author_name = 'AnonymousCoward' if author_name =~ /^\s*$/ |
311 | |
312 | begin |
313 | the_content = params['content'].purify |
314 | prev_content = '' |
315 | filter_spam(the_content) |
316 | cookies['author'] = { :value => author_name.dup.as_bytes, :expires => Time.utc(2030) } |
317 | if @page |
318 | new_name = params['new_name'] ? params['new_name'].purify : @page_name |
319 | new_name = @page_name if new_name.empty? |
320 | prev_content = @page.current_revision.content |
321 | raise Instiki::ValidationError.new('A page named "' + new_name.escapeHTML + '" already exists.') if |
322 | @page_name != new_name && @web.has_page?(new_name) |
323 | wiki.revise_page(@web_name, @page_name, new_name, the_content, Time.now, |
324 | Author.new(author_name, remote_ip), PageRenderer.new) |
325 | @page.unlock |
326 | @page_name = new_name |
327 | else |
328 | wiki.write_page(@web_name, @page_name, the_content, Time.now, |
329 | Author.new(author_name, remote_ip), PageRenderer.new) |
330 | end |
331 | redirect_to_page @page_name |
332 | rescue Instiki::ValidationError => e |
333 | flash[:error] = e.to_s |
334 | logger.error e |
335 | param_hash = {:web => @web_name, :id => @page_name} |
336 | # Work around Rails bug: flash will not display if query string is longer than 10192 bytes |
337 | param_hash.update( :content => the_content ) if the_content && |
338 | CGI::escape(the_content).length < 10183 && the_content != prev_content |
339 | if @page |
340 | @page.unlock |
341 | redirect_to param_hash.update( :action => 'edit' ) |
342 | else |
343 | redirect_to param_hash.update( :action => 'new' ) |
344 | end |
345 | end |
346 | end |
347 | |
348 | def show |
349 | if @page |
350 | begin |
351 | @renderer = PageRenderer.new(@page.revisions.last) |
352 | @show_diff = (params[:mode] == 'diff') |
353 | render :action => 'page' |
354 | # TODO this rescue should differentiate between errors due to rendering and errors in |
355 | # the application itself (for application errors, it's better not to rescue the error at all) |
356 | rescue => e |
357 | logger.error e |
358 | flash[:error] = e.to_s |
359 | if in_a_web? |
360 | redirect_to :action => 'edit', :web => @web_name, :id => @page_name |
361 | else |
362 | raise e |
363 | end |
364 | end |
365 | else |
366 | if not @page_name.nil? and not @page_name.empty? |
367 | real_page = WikiReference.page_that_redirects_for(@web, @page_name) |
368 | if real_page |
369 | flash[:info] = "Redirected from \"#{@page_name}\"." |
370 | redirect_to :web => @web_name, :action => 'show', :id => real_page, :status => 301 |
371 | else |
372 | flash[:info] = "Page \"#{@page_name}\" does not exist.\n" + |
373 | "Please create it now, or hit the \"back\" button in your browser." |
374 | redirect_to :web => @web_name, :action => 'new', :id => @page_name |
375 | end |
376 | else |
377 | render :text => 'Page name is not specified', :status => 404, :layout => 'error' |
378 | end |
379 | end |
380 | end |
381 | |
382 | def history |
383 | if @page |
384 | @revisions_by_day = Hash.new { |h, day| h[day] = [] } |
385 | @revision_numbers = Hash.new { |h, id| h[id] = [] } |
386 | revision_number = @page.revisions.size |
387 | @page.revisions.reverse.each do |rev| |
388 | day = Date.new(rev.revised_at.year, rev.revised_at.month, rev.revised_at.day) |
389 | @revisions_by_day[day] << rev |
390 | @revision_numbers[rev.id] = revision_number |
391 | revision_number = revision_number - 1 |
392 | end |
393 | render :action => 'history' |
394 | else |
395 | if not @page_name.nil? and not @page_name.empty? |
396 | redirect_to :web => @web_name, :action => 'new', :id => @page_name |
397 | else |
398 | render :text => 'Page name is not specified', :status => 404, :layout => 'error' |
399 | end |
400 | end |
401 | end |
402 | |
403 | def source |
404 | #to template |
405 | end |
406 | |
407 | def tex |
408 | if [:markdownMML, :markdownPNG, :markdown].include?(@web.markup) |
409 | @tex_content = Maruku.new(@page.content).to_latex |
410 | else |
411 | @tex_content = 'TeX export only supported with the Markdown text filters.' |
412 | end |
413 | render(:layout => 'tex') |
414 | end |
415 | |
416 | def s5 |
417 | if [:markdownMML, :markdownPNG, :markdown].include?(@web.markup) |
418 | my_rendered = PageRenderer.new(@page.revisions.last) |
419 | @s5_content = my_rendered.display_s5 |
420 | @s5_theme = my_rendered.s5_theme |
421 | else |
422 | @s5_content = "S5 not supported with this text filter" |
423 | @s5_theme = "default" |
424 | end |
425 | end |
426 | |
427 | protected |
428 | |
429 | def do_caching? |
430 | flash.empty? |
431 | end |
432 | |
433 | def load_page |
434 | @page_name = params['id'] ? params['id'].purify : nil |
435 | @page = @wiki.read_page(@web_name, @page_name) if @page_name |
436 | end |
437 | |
438 | private |
439 | |
440 | # def convert_tex_to_pdf(tex_path) |
441 | # # TODO remove earlier PDF files with the same prefix |
442 | # # TODO handle gracefully situation where pdflatex is not available |
443 | # begin |
444 | # wd = Dir.getwd |
445 | # Dir.chdir(File.dirname(tex_path)) |
446 | # logger.info `pdflatex --interaction=nonstopmode #{File.basename(tex_path)}` |
447 | # ensure |
448 | # Dir.chdir(wd) |
449 | # end |
450 | # end |
451 | |
452 | def export_page_to_tex(file_path) |
453 | if @web.markup == :markdownMML || @web.markup == :markdownPNG |
454 | @tex_content = Maruku.new(@page.content).to_latex |
455 | else |
456 | @tex_content = 'TeX export only supported with the Markdown text filters.' |
457 | end |
458 | File.open(file_path, 'w') { |f| f.write(render_to_string(:template => 'wiki/tex', :layout => 'tex')) } |
459 | end |
460 | |
461 | def export_pages_as_zip(file_type, &block) |
462 | |
463 | file_prefix = "#{@web.address}-#{file_type}-" |
464 | timestamp = @web.revised_at.strftime('%Y-%m-%d-%H-%M-%S') |
465 | file_path = @wiki.storage_path.join(file_prefix + timestamp + '.zip') |
466 | tmp_path = "#{file_path}.tmp" |
467 | |
468 | Zip::ZipFile.open(tmp_path, Zip::ZipFile::CREATE) do |zip_out| |
469 | @web.select.by_name.each do |page| |
470 | zip_out.get_output_stream("#{CGI.escape(page.name)}.#{file_type}") do |f| |
471 | f.puts(block.call(page)) |
472 | end |
473 | end |
474 | # add an index file, and the stylesheet and javascript directories, if exporting to HTML |
475 | if file_type.to_s.downcase == html_ext |
476 | zip_out.get_output_stream("index.#{html_ext}") do |f| |
477 | f.puts "<html xmlns='http://www.w3.org/1999/xhtml'><head>" + |
478 | "<meta http-equiv=\"Refresh\" content=\"0;URL=HomePage.#{html_ext}\" /></head></html>" |
479 | end |
480 | dir = Rails.root.join('public') |
481 | Dir["#{dir}/**/*"].each do |f| |
482 | zip_out.add "public#{f.sub(dir.to_s,'')}", f |
483 | end |
484 | end |
485 | files = @web.files_path |
486 | Dir["#{files}/**/*"].each do |f| |
487 | zip_out.add "files#{f.sub(files.to_s,'')}", f |
488 | end |
489 | end |
490 | FileUtils.rm_rf(Dir[@wiki.storage_path.join(file_prefix + '*.zip').to_s]) |
491 | FileUtils.mv(tmp_path, file_path) |
492 | send_file file_path |
493 | end |
494 | |
495 | # def export_web_to_tex(file_path) |
496 | # if @web.markup == :markdownMML |
497 | # @tex_content = Maruku.new(@page.content).to_latex |
498 | # else |
499 | # @tex_content = 'TeX export only supported with the Markdown text filters.' |
500 | # end |
501 | # @tex_content = table_of_contents(@web.page('HomePage').content, render_tex_web) |
502 | # File.open(file_path, 'w') { |f| f.write(render_to_string(:template => 'wiki/tex_web', :layout => tex)) } |
503 | # end |
504 | |
505 | def get_page_and_revision |
506 | if params['rev'] |
507 | @revision_number = params['rev'].to_i |
508 | else |
509 | @revision_number = @page.revisions.size |
510 | end |
511 | @revision = @page.revisions[@revision_number - 1] |
512 | end |
513 | |
514 | def parse_category |
515 | @categories = WikiReference.list_categories(@web).sort |
516 | @category = params['category'] |
517 | if @category |
518 | @set_name = "category '#{@category}'" |
519 | pages = WikiReference.pages_in_category(@web, @category).sort.map { |page_name| @web.page(page_name) } |
520 | @pages_in_category = PageSet.new(@web, pages) |
521 | else |
522 | # no category specified, return all pages of the web |
523 | @pages_in_category = @web.select_all.by_name |
524 | @set_name = 'the web' |
525 | end |
526 | end |
527 | |
528 | def remote_ip |
529 | ip = request.remote_ip |
530 | logger.info(ip) |
531 | ip.dup.gsub!(Regexp.union(Resolv::IPv4::Regex, Resolv::IPv6::Regex), '\0') || 'bogus address' |
532 | end |
533 | |
534 | def render_atom(hide_description = false, limit = 15) |
535 | @pages_by_revision = @web.select.by_revision.first(limit) |
536 | @hide_description = hide_description |
537 | @link_action = @web.password ? 'published' : 'show' |
538 | render :action => 'atom' |
539 | end |
540 | |
541 | def render_tex_web |
542 | @web.select.by_name.inject({}) do |tex_web, page| |
543 | if @web.markup == :markdownMML || @web.markup == :markdownPNG |
544 | tex_web[page.name] = Maruku.new(page.content).to_latex |
545 | else |
546 | tex_web[page.name] = 'TeX export only supported with the Markdown text filters.' |
547 | end |
548 | tex_web |
549 | end |
550 | end |
551 | |
552 | def rss_with_content_allowed? |
553 | @web.password.nil? or @web.published? |
554 | end |
555 | |
556 | def filter_spam(content) |
557 | @@spam_patterns ||= load_spam_patterns |
558 | @@spam_patterns.each do |pattern| |
559 | raise Instiki::ValidationError.new("Your edit was blocked by spam filtering") if content =~ pattern |
560 | end |
561 | end |
562 | |
563 | def load_spam_patterns |
564 | spam_patterns_file = Rails.root.join('config', 'spam_patterns.txt') |
565 | if File.exists?(spam_patterns_file) |
566 | spam_patterns_file.readlines.inject([]) { |patterns, line| patterns << Regexp.new(line.chomp, Regexp::IGNORECASE) } |
567 | else |
568 | [] |
569 | end |
570 | end |
571 | |
572 | end |