instiki 0.9.2 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (102) hide show
  1. data/CHANGELOG +165 -0
  2. data/README +68 -172
  3. data/app/controllers/admin_controller.rb +94 -0
  4. data/app/controllers/application.rb +131 -0
  5. data/app/controllers/file_controller.rb +129 -0
  6. data/app/controllers/wiki_controller.rb +354 -0
  7. data/{libraries/view_helper.rb → app/helpers/application_helper.rb} +68 -33
  8. data/app/models/author.rb +3 -3
  9. data/app/models/chunks/category.rb +33 -31
  10. data/app/models/chunks/chunk.rb +86 -20
  11. data/app/models/chunks/engines.rb +54 -38
  12. data/app/models/chunks/include.rb +41 -29
  13. data/app/models/chunks/literal.rb +31 -19
  14. data/app/models/chunks/nowiki.rb +28 -31
  15. data/app/models/chunks/test.rb +18 -18
  16. data/app/models/chunks/uri.rb +182 -97
  17. data/app/models/chunks/wiki.rb +141 -82
  18. data/app/models/file_yard.rb +58 -0
  19. data/app/models/page.rb +112 -86
  20. data/app/models/page_lock.rb +22 -23
  21. data/app/models/page_set.rb +89 -64
  22. data/app/models/revision.rb +123 -90
  23. data/app/models/web.rb +176 -89
  24. data/app/models/wiki_content.rb +207 -105
  25. data/app/models/wiki_service.rb +233 -83
  26. data/app/models/wiki_words.rb +23 -25
  27. data/app/views/{wiki/new_system.rhtml → admin/create_system.rhtml} +83 -78
  28. data/app/views/{wiki/new_web.rhtml → admin/create_web.rhtml} +69 -64
  29. data/app/views/admin/edit_web.rhtml +136 -0
  30. data/app/views/file/file.rhtml +19 -0
  31. data/app/views/file/import.rhtml +23 -0
  32. data/app/views/layouts/default.rhtml +85 -0
  33. data/app/views/markdown_help.rhtml +12 -16
  34. data/app/views/mixed_help.rhtml +7 -0
  35. data/app/views/navigation.rhtml +30 -19
  36. data/app/views/rdoc_help.rhtml +12 -16
  37. data/app/views/textile_help.rhtml +24 -28
  38. data/app/views/wiki/authors.rhtml +11 -13
  39. data/app/views/wiki/edit.rhtml +39 -31
  40. data/app/views/wiki/export.rhtml +12 -14
  41. data/app/views/wiki/feeds.rhtml +14 -10
  42. data/app/views/wiki/list.rhtml +64 -57
  43. data/app/views/wiki/locked.rhtml +23 -14
  44. data/app/views/wiki/login.rhtml +14 -11
  45. data/app/views/wiki/new.rhtml +31 -27
  46. data/app/views/wiki/page.rhtml +115 -81
  47. data/app/views/wiki/print.rhtml +14 -16
  48. data/app/views/wiki/published.rhtml +9 -10
  49. data/app/views/wiki/recently_revised.rhtml +27 -30
  50. data/app/views/wiki/revision.rhtml +103 -81
  51. data/app/views/wiki/rollback.rhtml +14 -9
  52. data/app/views/wiki/rss_feed.rhtml +22 -22
  53. data/app/views/wiki/search.rhtml +38 -15
  54. data/app/views/wiki/tex.rhtml +22 -22
  55. data/app/views/wiki/tex_web.rhtml +34 -34
  56. data/app/views/wiki/web_list.rhtml +18 -13
  57. data/app/views/wiki_words_help.rhtml +9 -8
  58. data/config/environment.rb +82 -0
  59. data/config/environments/development.rb +5 -0
  60. data/config/environments/production.rb +4 -0
  61. data/config/environments/test.rb +17 -0
  62. data/config/routes.rb +18 -0
  63. data/instiki +6 -67
  64. data/instiki.rb +3 -0
  65. data/lib/active_record_stub.rb +31 -0
  66. data/{libraries/diff → lib}/diff.rb +444 -475
  67. data/lib/instiki_errors.rb +15 -0
  68. data/{libraries → lib}/rdocsupport.rb +151 -155
  69. data/lib/redcloth_for_tex.rb +736 -0
  70. data/natives/osx/desktop_launcher/AppDelegate.h +18 -0
  71. data/natives/osx/desktop_launcher/AppDelegate.mm +109 -0
  72. data/natives/osx/desktop_launcher/Credits.html +16 -0
  73. data/natives/osx/desktop_launcher/English.lproj/InfoPlist.strings +0 -0
  74. data/natives/osx/desktop_launcher/English.lproj/MainMenu.nib/classes.nib +13 -0
  75. data/natives/osx/desktop_launcher/English.lproj/MainMenu.nib/info.nib +24 -0
  76. data/natives/osx/desktop_launcher/English.lproj/MainMenu.nib/objects.nib +0 -0
  77. data/natives/osx/desktop_launcher/Info.plist +13 -0
  78. data/natives/osx/desktop_launcher/Instiki.xcode/project.pbxproj +592 -0
  79. data/natives/osx/desktop_launcher/Instiki_Prefix.pch +7 -0
  80. data/natives/osx/desktop_launcher/MakeDMG.sh +9 -0
  81. data/natives/osx/desktop_launcher/main.mm +14 -0
  82. data/natives/osx/desktop_launcher/version.plist +16 -0
  83. data/public/404.html +6 -0
  84. data/public/500.html +6 -0
  85. data/public/dispatch.rb +10 -0
  86. data/public/favicon.ico +0 -0
  87. data/public/javascripts/edit_web.js +52 -0
  88. data/public/javascripts/prototype.js +336 -0
  89. data/{app/views/static_style_sheet.rhtml → public/stylesheets/instiki.css} +221 -198
  90. data/script/breakpointer +4 -0
  91. data/script/server +93 -0
  92. metadata +59 -32
  93. data/app/controllers/wiki.rb +0 -389
  94. data/app/models/chunks/match.rb +0 -19
  95. data/app/views/bottom.rhtml +0 -4
  96. data/app/views/top.rhtml +0 -49
  97. data/app/views/wiki/edit_web.rhtml +0 -138
  98. data/libraries/action_controller_servlet.rb +0 -177
  99. data/libraries/erb.rb +0 -490
  100. data/libraries/madeleine_service.rb +0 -68
  101. data/libraries/redcloth_for_tex.rb +0 -869
  102. data/libraries/web_controller_server.rb +0 -81
@@ -0,0 +1,131 @@
1
+ # The filters added to this controller will be run for all controllers in the application.
2
+ # Likewise will all the methods added be available for all controllers.
3
+ class ApplicationController < ActionController::Base
4
+
5
+ before_filter :set_utf8_http_header, :connect_to_model
6
+ after_filter :remember_location
7
+
8
+ # For injecting a different wiki model implementation. Intended for use in tests
9
+ def self.wiki=(the_wiki)
10
+ # a global variable is used here because Rails reloads controller and model classes in the
11
+ # development environment; therefore, storing it as a class variable does not work
12
+ # class variable is, anyway, not much different from a global variable
13
+ $instiki_wiki_service = the_wiki
14
+ logger.debug("Wiki service: #{the_wiki.to_s}")
15
+ end
16
+
17
+ def self.wiki
18
+ $instiki_wiki_service
19
+ end
20
+
21
+ protected
22
+
23
+ def authorized?
24
+ @web.nil? ||
25
+ @web.password.nil? ||
26
+ cookies['web_address'] == @web.password ||
27
+ password_check(@params['password'])
28
+ end
29
+
30
+ def check_authorization
31
+ if in_a_web? and needs_authorization?(@action_name) and not authorized? and
32
+ redirect_to :controller => 'wiki', :action => 'login', :web => @web_name
33
+ return false
34
+ end
35
+ end
36
+
37
+ def connect_to_model
38
+ @action_name = @params['action'] || 'index'
39
+ @web_name = @params['web']
40
+ @wiki = wiki
41
+ if @web_name
42
+ @web = @wiki.webs[@web_name]
43
+ if @web.nil?
44
+ render_text "Unknown web '#{@web_name}'", '404 Not Found'
45
+ return false
46
+ end
47
+ end
48
+ @page_name = @file_name = @params['id']
49
+ @page = @wiki.read_page(@web_name, @page_name) unless @page_name.nil?
50
+ @author = cookies['author'] || 'AnonymousCoward'
51
+ check_authorization
52
+ end
53
+
54
+ FILE_TYPES = {
55
+ '.exe' => 'application/octet-stream',
56
+ '.gif' => 'image/gif',
57
+ '.jpg' => 'image/jpeg',
58
+ '.pdf' => 'application/pdf',
59
+ '.png' => 'image/png',
60
+ '.txt' => 'text/plain',
61
+ '.zip' => 'application/zip'
62
+ } unless defined? FILE_TYPES
63
+
64
+ def send_file(file, options = {})
65
+ options[:type] ||= (FILE_TYPES[File.extname(file)] || 'application/octet-stream')
66
+ super(file, options)
67
+ end
68
+
69
+ def in_a_web?
70
+ not @web_name.nil?
71
+ end
72
+
73
+ def password_check(password)
74
+ if password == @web.password
75
+ cookies['web_address'] = password
76
+ true
77
+ else
78
+ false
79
+ end
80
+ end
81
+
82
+ def password_error(password)
83
+ if password.nil? or password.empty?
84
+ 'Please enter the password.'
85
+ else
86
+ 'You entered a wrong password. Please enter the right one.'
87
+ end
88
+ end
89
+
90
+ def redirect_show(page_name = @page_name, web = @web_name)
91
+ redirect_to :web => web, :controller => 'wiki', :action => 'show',
92
+ :id => (page_name || 'HomePage')
93
+ end
94
+
95
+ @@REMEMBER_NOT = ['locked', 'save', 'back', 'file', 'pic', 'import']
96
+ def remember_location
97
+ if @response.headers['Status'] == '200 OK'
98
+ unless @@REMEMBER_NOT.include? action_name or @request.method != :get
99
+ @session[:return_to] = @request.request_uri
100
+ logger.debug("Session ##{session.object_id}: remembered URL '#{@session[:return_to]}'")
101
+ end
102
+ end
103
+ end
104
+
105
+ def return_to_last_remembered
106
+ # Forget the redirect location
107
+ redirect_target, @session[:return_to] = @session[:return_to], nil
108
+ # then try to redirect to it
109
+ if redirect_target.nil?
110
+ logger.debug("Session ##{session.object_id}: no remembered redirect location, trying /")
111
+ redirect_to_url '/'
112
+ else
113
+ logger.debug("Session ##{session.object_id}: " +
114
+ "redirect to the last remembered URL #{redirect_target}")
115
+ redirect_to_url(redirect_target)
116
+ end
117
+ end
118
+
119
+ def set_utf8_http_header
120
+ @response.headers['Content-Type'] = 'text/html; charset=UTF-8'
121
+ end
122
+
123
+ def wiki
124
+ $instiki_wiki_service
125
+ end
126
+
127
+ def needs_authorization?(action)
128
+ not %w( login authenticate published rss_with_content rss_with_headlines ).include?(action)
129
+ end
130
+
131
+ end
@@ -0,0 +1,129 @@
1
+ require 'fileutils'
2
+ require 'application'
3
+ require 'instiki_errors'
4
+
5
+ # Controller that is responsible for serving files and pictures.
6
+ # Disabled in version 0.10
7
+
8
+ class FileController < ApplicationController
9
+
10
+ layout 'default'
11
+
12
+ before_filter :check_allow_uploads
13
+
14
+ def file
15
+ check_path
16
+ if @params['file']
17
+ # form supplied
18
+ file_yard.upload_file(@file_name, @params['file'])
19
+ flash[:info] = "File '#{@file_name}' successfully uploaded"
20
+ @web.refresh_pages_with_references(@file_name)
21
+ return_to_last_remembered
22
+ elsif file_yard.has_file?(@file_name)
23
+ send_file(file_yard.file_path(@file_name))
24
+ else
25
+ logger.debug("File not found: #{file_yard.files_path}/#{@file_name}")
26
+ # go to the template, which is a file upload form
27
+ end
28
+ end
29
+
30
+ def cancel_upload
31
+ return_to_last_remembered
32
+ end
33
+
34
+ def pic
35
+ check_path
36
+ if @params['file']
37
+ # form supplied
38
+ file_yard.upload_file(@file_name, @params['file'])
39
+ flash[:info] = "Image '#{@file_name}' successfully uploaded"
40
+ @web.refresh_pages_with_references(@file_name)
41
+ return_to_last_remembered
42
+ elsif file_yard.has_file?(@file_name)
43
+ send_file(file_yard.file_path(@file_name))
44
+ else
45
+ logger.debug("Image not found: #{file_yard.files_path}/#{@file_name}")
46
+ render_action 'file'
47
+ end
48
+ end
49
+
50
+ def import
51
+ return if file_uploads_disabled?
52
+
53
+ check_authorization
54
+ if @params['file']
55
+ @problems = []
56
+ import_file_name = "#{@web.address}-import-#{Time.now.strftime('%Y-%m-%d-%H-%M-%S')}.zip"
57
+ file_yard.upload_file(import_file_name, @params['file'])
58
+ import_from_archive(file_yard.file_path(import_file_name))
59
+ if @problems.empty?
60
+ flash[:info] = 'Import successfully finished'
61
+ else
62
+ flash[:info] = "Import finished, but some pages were not imported:<li>" +
63
+ @problems.join('</li><li>') + '</li>'
64
+ end
65
+ return_to_last_remembered
66
+ else
67
+ # to template
68
+ end
69
+ end
70
+
71
+ protected
72
+
73
+ def check_allow_uploads
74
+
75
+ # TODO enable file uploads again after 0.10 release
76
+ unless RAILS_ENV == 'test'
77
+ render_text 'File uploads are not ready for general use in Instiki 0.10', '403 Forbidden'
78
+ return false
79
+ end
80
+
81
+ unless @web.allow_uploads
82
+ render_text 'File uploads are blocked by the webmaster', '403 Forbidden'
83
+ return false
84
+ end
85
+ end
86
+
87
+
88
+ private
89
+
90
+ def check_path
91
+ raise Instiki::ValidationError.new("Invalid path: no file name") unless @file_name
92
+ raise Instiki::ValidationError.new("Invalid path: no web name") unless @web_name
93
+ raise Instiki::ValidationError.new("Invalid path: unknown web name") unless @web
94
+ end
95
+
96
+ def file_yard
97
+ @wiki.file_yard(@web)
98
+ end
99
+
100
+ def import_from_archive(archive)
101
+ logger.info "Importing pages from #{archive}"
102
+ zip = Zip::ZipInputStream.open(archive)
103
+ while (entry = zip.get_next_entry) do
104
+ ext_length = File.extname(entry.name).length
105
+ page_name = entry.name[0..-(ext_length + 1)]
106
+ page_content = entry.get_input_stream.read
107
+ logger.info "Processing page '#{page_name}'"
108
+ begin
109
+ existing_page = @wiki.read_page(@web.address, page_name)
110
+ if existing_page
111
+ if existing_page.content == page_content
112
+ logger.info "Page '#{page_name}' with the same content already exists. Skipping."
113
+ next
114
+ else
115
+ logger.info "Page '#{page_name}' already exists. Adding a new revision to it."
116
+ wiki.revise_page(@web.address, page_name, page_content, Time.now, @author)
117
+ end
118
+ else
119
+ wiki.write_page(@web.address, page_name, page_content, Time.now, @author)
120
+ end
121
+ rescue => e
122
+ logger.error(e)
123
+ @problems << "#{page_name} : #{e.message}"
124
+ end
125
+ end
126
+ logger.info "Import from #{archive} finished"
127
+ end
128
+
129
+ end
@@ -0,0 +1,354 @@
1
+ require 'application'
2
+ require 'fileutils'
3
+ require 'redcloth_for_tex'
4
+ require 'parsedate'
5
+
6
+ class WikiController < ApplicationController
7
+
8
+ layout 'default', :except => [:rss_feed, :rss_with_content, :rss_with_headlines, :tex, :export_tex, :export_html]
9
+
10
+ def index
11
+ if @web_name
12
+ redirect_show 'HomePage'
13
+ elsif not @wiki.setup?
14
+ redirect_to :controller => 'admin', :action => 'create_system'
15
+ elsif @wiki.webs.length == 1
16
+ redirect_show 'HomePage', @wiki.webs.values.first.address
17
+ else
18
+ redirect_to :action => 'web_list'
19
+ end
20
+ end
21
+
22
+ # Outside a single web --------------------------------------------------------
23
+
24
+ def authenticate
25
+ if password_check(@params['password'])
26
+ redirect_show('HomePage')
27
+ else
28
+ flash[:info] = password_error(@params['password'])
29
+ redirect_to :action => 'login', :web => @web_name
30
+ end
31
+ end
32
+
33
+ def login
34
+ # to template
35
+ end
36
+
37
+ def web_list
38
+ @webs = wiki.webs.values.sort_by { |web| web.name }
39
+ end
40
+
41
+
42
+ # Within a single web ---------------------------------------------------------
43
+
44
+ def authors
45
+ @authors = @web.select.authors
46
+ end
47
+
48
+ def export_html
49
+ export_pages_as_zip('html') do |page|
50
+ @page = page
51
+ @link_mode = :export
52
+ render_to_string 'wiki/print'
53
+ end
54
+ end
55
+
56
+ def export_markup
57
+ export_pages_as_zip(@web.markup) { |page| page.content }
58
+ end
59
+
60
+ def export_pdf
61
+ file_name = "#{@web.address}-tex-#{@web.revised_on.strftime('%Y-%m-%d-%H-%M-%S')}"
62
+ file_path = File.join(@wiki.storage_path, file_name)
63
+
64
+ export_web_to_tex "#{file_path}.tex" unless FileTest.exists? "#{file_path}.tex"
65
+ convert_tex_to_pdf "#{file_path}.tex"
66
+ send_file "#{file_path}.pdf"
67
+ end
68
+
69
+ def export_tex
70
+ file_name = "#{@web.address}-tex-#{@web.revised_on.strftime('%Y-%m-%d-%H-%M-%S')}.tex"
71
+ file_path = File.join(@wiki.storage_path, file_name)
72
+ export_web_to_tex(file_path) unless FileTest.exists?(file_path)
73
+ send_file file_path
74
+ end
75
+
76
+ def feeds
77
+ @rss_with_content_allowed = rss_with_content_allowed?
78
+ # show the template
79
+ end
80
+
81
+ def list
82
+ parse_category
83
+ @pages_by_name = @pages_in_category.by_name
84
+ @page_names_that_are_wanted = @pages_in_category.wanted_pages
85
+ @pages_that_are_orphaned = @pages_in_category.orphaned_pages
86
+ end
87
+
88
+ def recently_revised
89
+ parse_category
90
+ @pages_by_revision = @pages_in_category.by_revision
91
+ end
92
+
93
+ def rss_with_content
94
+ if rss_with_content_allowed?
95
+ render_rss(hide_description = false, *parse_rss_params)
96
+ else
97
+ render_text 'RSS feed with content for this web is blocked for security reasons. ' +
98
+ 'The web is password-protected and not published', '403 Forbidden'
99
+ end
100
+ end
101
+
102
+ def rss_with_headlines
103
+ render_rss(hide_description = true, *parse_rss_params)
104
+ end
105
+
106
+ def search
107
+ @query = @params['query']
108
+ @title_results = @web.select { |page| page.name =~ /#{@query}/i }.sort
109
+ @results = @web.select { |page| page.content =~ /#{@query}/i }.sort
110
+ all_pages_found = (@results + @title_results).uniq
111
+ if all_pages_found.size == 1
112
+ redirect_show(all_pages_found.first.name)
113
+ end
114
+ end
115
+
116
+ # Within a single page --------------------------------------------------------
117
+
118
+ def cancel_edit
119
+ @page.unlock
120
+ redirect_show
121
+ end
122
+
123
+ def edit
124
+ if @page.nil?
125
+ redirect_to :action => 'index'
126
+ elsif @page.locked?(Time.now) and not @params['break_lock']
127
+ redirect_to :web => @web_name, :action => 'locked', :id => @page_name
128
+ else
129
+ @page.lock(Time.now, @author)
130
+ end
131
+ end
132
+
133
+ def locked
134
+ # to template
135
+ end
136
+
137
+ def new
138
+ # to template
139
+ end
140
+
141
+ def pdf
142
+ page = wiki.read_page(@web_name, @page_name)
143
+ safe_page_name = @page.name.gsub(/\W/, '')
144
+ file_name = "#{safe_page_name}-#{@web.address}-#{@page.created_at.strftime('%Y-%m-%d-%H-%M-%S')}"
145
+ file_path = File.join(@wiki.storage_path, file_name)
146
+
147
+ export_page_to_tex("#{file_path}.tex") unless FileTest.exists?("#{file_path}.tex")
148
+ # NB: this is _very_ slow
149
+ convert_tex_to_pdf("#{file_path}.tex")
150
+ send_file "#{file_path}.pdf"
151
+ end
152
+
153
+ def print
154
+ @link_mode ||= :show
155
+ # to template
156
+ end
157
+
158
+ def published
159
+ if @web.published
160
+ @page = wiki.read_page(@web_name, @page_name || 'HomePage')
161
+ else
162
+ redirect_show('HomePage')
163
+ end
164
+ end
165
+
166
+ def revision
167
+ get_page_and_revision
168
+ end
169
+
170
+ def rollback
171
+ get_page_and_revision
172
+ end
173
+
174
+ def save
175
+ redirect_to :action => 'index' if @page_name.nil?
176
+ cookies['author'] = @params['author']
177
+
178
+ begin
179
+ page = @web.pages[@page_name]
180
+ if @web.pages[@page_name]
181
+ wiki.revise_page(
182
+ @web_name, @page_name, @params['content'], Time.now,
183
+ Author.new(@params['author'], remote_ip)
184
+ )
185
+ page.unlock
186
+ else
187
+ wiki.write_page(
188
+ @web_name, @page_name, @params['content'], Time.now,
189
+ Author.new(@params['author'], remote_ip)
190
+ )
191
+ end
192
+ redirect_show(@page_name)
193
+ rescue Instiki::ValidationError => e
194
+ page.unlock if defined? page
195
+ flash[:error] = e
196
+ return_to_last_remembered
197
+ end
198
+ end
199
+
200
+ def show
201
+ if @page
202
+ begin
203
+ render_action 'page'
204
+ # TODO this rescue should differentiate between errors due to rendering and errors in
205
+ # the application itself (for application errors, it's better not to rescue the error at all)
206
+ rescue => e
207
+ logger.error e
208
+ if in_a_web?
209
+ redirect_to :web => @web_name, :action => 'edit',
210
+ :action_suffix => "#{@page_name}?msg=#{e.message}"
211
+ else
212
+ raise e
213
+ end
214
+ end
215
+ else
216
+ if not @page_name.nil? and not @page_name.empty?
217
+ redirect_to :web => @web_name, :action => 'new', :id => @page_name
218
+ else
219
+ render_text 'Page name is not specified', '404 Not Found'
220
+ end
221
+ end
222
+ end
223
+
224
+ def tex
225
+ @tex_content = RedClothForTex.new(@page.content).to_tex
226
+ end
227
+
228
+
229
+ private
230
+
231
+ def convert_tex_to_pdf(tex_path)
232
+ # TODO remove earlier PDF files with the same prefix
233
+ # TODO handle gracefully situation where pdflatex is not available
234
+ begin
235
+ wd = Dir.getwd
236
+ Dir.chdir(File.dirname(tex_path))
237
+ logger.info `pdflatex --interaction=nonstopmode #{File.basename(tex_path)}`
238
+ ensure
239
+ Dir.chdir(wd)
240
+ end
241
+ end
242
+
243
+ def export_page_to_tex(file_path)
244
+ tex
245
+ File.open(file_path, 'w') { |f| f.write(render_to_string('wiki/tex')) }
246
+ end
247
+
248
+ def export_pages_as_zip(file_type, &block)
249
+
250
+ file_prefix = "#{@web.address}-#{file_type}-"
251
+ timestamp = @web.revised_on.strftime('%Y-%m-%d-%H-%M-%S')
252
+ file_path = File.join(@wiki.storage_path, file_prefix + timestamp + '.zip')
253
+ tmp_path = "#{file_path}.tmp"
254
+
255
+ Zip::ZipOutputStream.open(tmp_path) do |zip_out|
256
+ @web.select.by_name.each do |page|
257
+ zip_out.put_next_entry("#{CGI.escape(page.name)}.#{file_type}")
258
+ zip_out.puts(block.call(page))
259
+ end
260
+ # add an index file, if exporting to HTML
261
+ if file_type.to_s.downcase == 'html'
262
+ zip_out.put_next_entry 'index.html'
263
+ zip_out.puts <<-EOL
264
+ <html>
265
+ <head>
266
+ <META HTTP-EQUIV="Refresh" CONTENT="0;URL=HomePage.#{file_type}">
267
+ </head>
268
+ </html>
269
+ EOL
270
+ end
271
+ end
272
+ FileUtils.rm_rf(Dir[File.join(@wiki.storage_path, file_prefix + '*.zip')])
273
+ FileUtils.mv(tmp_path, file_path)
274
+ send_file file_path
275
+ end
276
+
277
+ def export_web_to_tex(file_path)
278
+ @tex_content = table_of_contents(@web.pages['HomePage'].content, render_tex_web)
279
+ File.open(file_path, 'w') { |f| f.write(render_to_string('wiki/tex_web')) }
280
+ end
281
+
282
+ def get_page_and_revision
283
+ @revision = @page.revisions[@params['rev'].to_i]
284
+ end
285
+
286
+ def parse_category
287
+ @categories = @web.categories
288
+ @category = @params['category']
289
+ if @categories.include?(@category)
290
+ @pages_in_category = @web.select { |page| page.in_category?(@category) }
291
+ @set_name = "category '#{@category}'"
292
+ else
293
+ @pages_in_category = PageSet.new(@web).by_name
294
+ @set_name = 'the web'
295
+ end
296
+ end
297
+
298
+ def parse_rss_params
299
+ if @params.include? 'limit'
300
+ limit = @params['limit'].to_i rescue nil
301
+ limit = nil if limit == 0
302
+ else
303
+ limit = 15
304
+ end
305
+ start_date = Time.local(*ParseDate::parsedate(@params['start'])) rescue nil
306
+ end_date = Time.local(*ParseDate::parsedate(@params['end'])) rescue nil
307
+ [ limit, start_date, end_date ]
308
+ end
309
+
310
+ def remote_ip
311
+ ip = @request.remote_ip
312
+ logger.info(ip)
313
+ ip
314
+ end
315
+
316
+ def render_rss(hide_description = false, limit = 15, start_date = nil, end_date = nil)
317
+ if limit && !start_date && !end_date
318
+ @pages_by_revision = @web.select.by_revision.first(limit)
319
+ else
320
+ @pages_by_revision = @web.select.by_revision
321
+ @pages_by_revision.reject! { |page| page.created_at < start_date } if start_date
322
+ @pages_by_revision.reject! { |page| page.created_at > end_date } if end_date
323
+ end
324
+
325
+ @hide_description = hide_description
326
+ @response.headers['Content-Type'] = 'text/xml'
327
+ @link_action = @web.password ? 'published' : 'show'
328
+
329
+ render 'wiki/rss_feed'
330
+ end
331
+
332
+ def render_tex_web
333
+ @web.select.by_name.inject({}) do |tex_web, page|
334
+ tex_web[page.name] = RedClothForTex.new(page.content).to_tex
335
+ tex_web
336
+ end
337
+ end
338
+
339
+ def render_to_string(template_name)
340
+ add_variables_to_assigns
341
+ render template_name
342
+ @performed_render = false
343
+ @template.render_file(template_name)
344
+ end
345
+
346
+ def rss_with_content_allowed?
347
+ @web.password.nil? or @web.published
348
+ end
349
+
350
+ def truncate(text, length = 30, truncate_string = '...')
351
+ if text.length > length then text[0..(length - 3)] + truncate_string else text end
352
+ end
353
+
354
+ end