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