instiki 0.9.2

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 (61) hide show
  1. data/README +172 -0
  2. data/app/controllers/wiki.rb +389 -0
  3. data/app/models/author.rb +4 -0
  4. data/app/models/chunks/category.rb +31 -0
  5. data/app/models/chunks/chunk.rb +20 -0
  6. data/app/models/chunks/engines.rb +38 -0
  7. data/app/models/chunks/include.rb +29 -0
  8. data/app/models/chunks/literal.rb +19 -0
  9. data/app/models/chunks/match.rb +19 -0
  10. data/app/models/chunks/nowiki.rb +31 -0
  11. data/app/models/chunks/test.rb +18 -0
  12. data/app/models/chunks/uri.rb +97 -0
  13. data/app/models/chunks/wiki.rb +82 -0
  14. data/app/models/page.rb +86 -0
  15. data/app/models/page_lock.rb +24 -0
  16. data/app/models/page_set.rb +64 -0
  17. data/app/models/revision.rb +90 -0
  18. data/app/models/web.rb +89 -0
  19. data/app/models/wiki_content.rb +105 -0
  20. data/app/models/wiki_service.rb +83 -0
  21. data/app/models/wiki_words.rb +25 -0
  22. data/app/views/bottom.rhtml +4 -0
  23. data/app/views/markdown_help.rhtml +16 -0
  24. data/app/views/navigation.rhtml +19 -0
  25. data/app/views/rdoc_help.rhtml +16 -0
  26. data/app/views/static_style_sheet.rhtml +199 -0
  27. data/app/views/textile_help.rhtml +28 -0
  28. data/app/views/top.rhtml +49 -0
  29. data/app/views/wiki/authors.rhtml +13 -0
  30. data/app/views/wiki/edit.rhtml +31 -0
  31. data/app/views/wiki/edit_web.rhtml +138 -0
  32. data/app/views/wiki/export.rhtml +14 -0
  33. data/app/views/wiki/feeds.rhtml +10 -0
  34. data/app/views/wiki/list.rhtml +57 -0
  35. data/app/views/wiki/locked.rhtml +14 -0
  36. data/app/views/wiki/login.rhtml +11 -0
  37. data/app/views/wiki/new.rhtml +27 -0
  38. data/app/views/wiki/new_system.rhtml +78 -0
  39. data/app/views/wiki/new_web.rhtml +64 -0
  40. data/app/views/wiki/page.rhtml +81 -0
  41. data/app/views/wiki/print.rhtml +16 -0
  42. data/app/views/wiki/published.rhtml +10 -0
  43. data/app/views/wiki/recently_revised.rhtml +30 -0
  44. data/app/views/wiki/revision.rhtml +81 -0
  45. data/app/views/wiki/rollback.rhtml +31 -0
  46. data/app/views/wiki/rss_feed.rhtml +22 -0
  47. data/app/views/wiki/search.rhtml +15 -0
  48. data/app/views/wiki/tex.rhtml +23 -0
  49. data/app/views/wiki/tex_web.rhtml +35 -0
  50. data/app/views/wiki/web_list.rhtml +13 -0
  51. data/app/views/wiki_words_help.rhtml +8 -0
  52. data/instiki +67 -0
  53. data/libraries/action_controller_servlet.rb +177 -0
  54. data/libraries/diff/diff.rb +475 -0
  55. data/libraries/erb.rb +490 -0
  56. data/libraries/madeleine_service.rb +68 -0
  57. data/libraries/rdocsupport.rb +156 -0
  58. data/libraries/redcloth_for_tex.rb +869 -0
  59. data/libraries/view_helper.rb +33 -0
  60. data/libraries/web_controller_server.rb +81 -0
  61. metadata +142 -0
data/README ADDED
@@ -0,0 +1,172 @@
1
+ ===What is Instiki?
2
+
3
+ Admitted, it's YetAnotherWikiClone[http://c2.com/cgi/wiki?WikiWikiClones], but with a strong focus
4
+ on simplicity of installation and running:
5
+
6
+ Step 1. Download
7
+
8
+ Step 2. Run "instiki"
9
+
10
+ Step 3. Chuckle... "There's no step three!" (TM)
11
+
12
+ You're now running a perfectly suitable wiki on port 2500
13
+ that'll present you with one-step setup, followed by a textarea for the home page
14
+ on http://localhost:2500.
15
+
16
+ Instiki lowers the barriers of interest for when you might consider
17
+ using a wiki. It's so simple to get running that you'll find yourself
18
+ using it for anything -- taking notes, brainstorming, organizing a
19
+ gathering.
20
+
21
+ ===Features:
22
+ * Regular expression search: Find deep stuff really fast
23
+ * Revisions: Follow the changes on every page from birth. Rollback to an earlier rev
24
+ * Export to HTML or markup in a zip: Take the entire wiki with you home or for reference
25
+ * RSS feeds to track recently revised pages
26
+ * Multiple webs: Create separate wikis with their own namespace
27
+ * Password-protected webs: Keep it private
28
+ * Authors: Each revision is associated with an author, so you can see who changed what
29
+ * Reference tracker: Which other pages are pointing to the current?
30
+ * Speed: Using Madelein[http://madeleine.sourceforge.net] for persistence (all pages are in memory)
31
+ * Three markup choices: Textile[http://www.textism.com/tools/textile]
32
+ (default / RedCloth[http://www.whytheluckystiff.net/ruby/redcloth]),
33
+ Markdown (BlueCloth[http://bluecloth.rubyforge.org]), and RDoc[http://rdoc.sourceforge.net/doc]
34
+ * Embedded webserver: Through WEBrick[http://www.webrick.org]
35
+ * Internationalization: Wiki words in any latin, greek, cyrillian, or armenian characters
36
+ * Color diffs: Track changes through revisions
37
+
38
+ ===Missing:
39
+ * File attachments
40
+
41
+ ===Install from gem:
42
+ * Install rubygems
43
+ * Run "gem install instiki"
44
+ * Change to a directory where you want Instiki to keep its data files (for example, ~/instiki/)
45
+ * Run "instiki" - this will create a "storage" directory (for example, ~/instiki/storage), and start a new Wiki service
46
+
47
+ Make sure that you always launch Instiki from the same working directory, or specify the storage directory in runtime parameters, such as:
48
+ instiki --storage ~/instiki/storage
49
+
50
+ ===Command-line options:
51
+ * Run "instiki --help"
52
+
53
+ ===History:
54
+ * 0.9.2: Rollback takes the user to an edit form. The form has to be submitted for the change to take place.
55
+ Changed to use inline style on published pages
56
+ Fixed "forward in time" on the last revision before current page
57
+ Instiki won't log bogus error messages when creating a new Wiki.
58
+ Fixed deprecation warning for Object.id (introduced in Ruby 1.8.2)
59
+ Madeleine upgraded to 0.7.1
60
+ Madeleine snapshots are compressed
61
+ Packaged as a gem
62
+ * 0.9.1: Added performance improvements for updating existing pages
63
+ Fixed IP logging and RSS feeds behind proxies [With help from Guan Yang]
64
+ Fixed default storage directory (borked running on Windows) [Spotted by Curt Hibbs]
65
+ * 0.9.0: Added aliased links such as [[HomePage|that nice home page]] [Mark Reid]
66
+ Added include other page content with [[!include TableOfContents]] [Mark Reid]
67
+ Added delete orphan pages from the Edit Web screen [by inspiration from Simon Arnaud]
68
+ Added logging of IP address for authors (who's behind the rollback wars)
69
+ Added Categories pages through backlinks (use "categories: news, instiki" on start of line) [Mark Reid]
70
+ Added option to use bracket-style wiki links only (and hence ban WikiWords)
71
+ Added command-line option to specify different storage path
72
+ Added print view without navigation
73
+ Added character and page (2275 characters including spaces) counter (important for student papers)
74
+ Off by default, activate it on the Edit Web screen
75
+ Added LaTeX/PDF integration on Textile installations with pdflatex installed on system (EXPERIMENTAL)
76
+ Use the home page as a table of contents with a unordered list to control sections
77
+ Added limit of 15 to the number of pages included in RSS feed
78
+ Moved static parts of stylesheet to separate file [Lau T�rnskov]
79
+ Fixed better semantics for revision movement [Ryan Singer]
80
+ Fixed color diffs to work much better [Xen/Mertz/Atkins]
81
+ Fixed performance problems for All Pages list [Dennis Mertz]
82
+ Fixed lots of rendering bugs [Mark Reid]
83
+ Upgraded to RedCloth 2.0.11 [integrating the fine work of Dennis Mertz]
84
+ * 0.8.9: Added color diffs to see changes between revisions [Bill Atkins]
85
+ They're aren't quite perfect yet as new paragraphs split the <ins> tags (hence 0.8.9, not 0.9.0)
86
+ Added redirect to edit if content of page generates an error
87
+ (so the page doesn't become unusable on bugs in the markup engines)
88
+ Fixed update Web with different address bug [Denis Metz]
89
+ Fixed a bunch of wiki word rendering issues by doing wiki word detection and replacment at once
90
+ Upgraded to BlueCloth 0.0.3b (should fix loads of problems on Markdown wikis)
91
+ * 0.8.5: Instiki can now serve as a CMS by running a password-protected web with a published front
92
+ Added version check at startup (Instiki needs Ruby 1.8.1)
93
+ * 0.8.1: Actually included RedCloth 2.0.7 in the release
94
+ * 0.8.0: NOTE: Single-web wikis created in versions prior to 0.8.0 have "instiki" as their system password
95
+ Accepts wiki words in bracket style. Ex: [[wiki word]], [[c]], [[We could'nt have done it!]]
96
+ Accepts camel-case wiki words in all latin, greek, cyrillian, and armenian unicode characters
97
+ Many thanks to Guan Yang for building the higher- and lower-case lookup tables
98
+ And thanks to Simon Arnaud for the initial patch that got the work started
99
+ Changed charset to UTF-8
100
+ Cut down on command-line options and replaced them with an per-web config screen
101
+ Added option to extend the stylesheet on a per-web basis to tweak the look in details
102
+ Added simple color options for variety
103
+ Added option to add/remove password protection on each web
104
+ Added the wiki name of the author locking a given page (instead of just "someone")
105
+ Removed single/multi-web distinction -- all Instikis are now multi-web
106
+ Load libraries from an unshifted load path, so that old installed libraries doesn't clash [Emiel van de Laar]
107
+ Keeps the author cookie forever, so you don't have to enter your name again and again
108
+ Fixed XHTML so it validates [Bruce D'Arcus]
109
+ Authors are no longer listed under orphan pages
110
+ Added export to markup (great for backups, potentially for switching wiki engine)
111
+ Don't link wiki words that proceeds from either /, = or ?
112
+ (http://c2.com/cgi/wiki?WikiWikiClones, /show/HomePage, cgi.pl?show=WikiWord without escaping)
113
+ Accessing an unexisting page redirects to a different url (/new/PageName)
114
+ Increased snapshot time to just once a day (cuts down on disk storage requirements)
115
+ Made RDoc support work better with 1.8.1 [Mauricio Fern�ndez]
116
+ Added convinient redirect from /wiki/ to /wiki/show/HomePage
117
+ Fixed BlueCloth bug with backticks at start of line
118
+ Updated to RedCloth 2.0.7 (and linked to the new Textile reference)
119
+ * 0.7.0: Added Markdown (BlueCloth) and RDoc [Mauricio Fern�ndez] as command-line markup choices
120
+ Added wanted and orphan page lists to All pages (only show up if there's actually orphan or wanted pages)
121
+ Added ISO-8859-1 as XML encoding in RSS feeds (makes FeedReader among others happy for special entities)
122
+ Added proper links in the RSS feed (but the body links are still relative, which NNW and others doesn't grok)
123
+ Added access keys: E => Edit, H => HomePage, A => All Pages, U => Recently Revised, X => Export
124
+ Added password-login through URL (so you can subscribe to feed on a protected web)
125
+ Added web passwords to the feed links for protected webs, so they work without manual login
126
+ Added the web name in small letters above all pages within a web
127
+ Polished authors and recently revised
128
+ Updated to RedCloth 2.0.6
129
+ Changed content type for RSS feeds to text/xml (makes Mozilla Aggreg8 happy)
130
+ Changed searching to be case insensitive
131
+ Changed HomePage to display the name of the web instead
132
+ Changed exported HTML pages to be valid XHTML (which can be preprocessed by XSLT)
133
+ Fixed broken recently revised
134
+ * 0.6.0: Fixed Windows compatibility [Florian]
135
+ Fixed bug that would prevent Madeleine from taking snapshots in Daemon mode
136
+ Added export entire web as HTML in a zip file
137
+ Added RSS feeds
138
+ Added proper getops support for the growing number of options [Florian]
139
+ Added safe mode that forbids style options in RedCloth [Florian]
140
+ Updated RedCloth to 2.0.5
141
+ * 0.5.0: NOTE: 0.5.0 is NOT compatible with databases from earlier versions
142
+ Added revisions
143
+ Added multiple webs
144
+ Added password protection for webs on multi-web setups
145
+ Added the notion of authors (that are saved in a cookie)
146
+ Added command-line option for not running as a Daemon on Unix
147
+ * 0.3.1: Added option to escape wiki words with \
148
+ * 0.3.0: Brought all files into common style (including Textile help on the edit page)
149
+ Added page locking (if someone already is editing a page there's a warning)
150
+ Added daemon abilities on Unix (keep Instiki running after you close the terminal)
151
+ Made port 2500 the default port, so Instiki can be launched by dobbelt-click
152
+ Added Textile cache to speed-up rendering of large pages
153
+ Made WikiWords look like "Wiki Words"
154
+ Updated RedCloth to 2.0.4
155
+ * 0.2.5: Upgraded to RedCloth 2.0.2 and Madeleine 0.6.1, which means the
156
+ Windows problems are gone. Also fixed a problem with wikiwords
157
+ that used part of other wikiwords.
158
+ * 0.2.0: First public release
159
+
160
+ ===Download latest from:
161
+ * http://rubyforge.org/project/showfiles.php?group_id=186
162
+
163
+ ===Visit the official Instiki wiki:
164
+ * http://www.instiki.org
165
+
166
+ ===License:
167
+ * same as Ruby's
168
+
169
+ ---
170
+ Author:: David Heinemeier Hansson
171
+ Email:: david@loudthinking.com
172
+ Weblog:: http://www.loudthinking.com
@@ -0,0 +1,389 @@
1
+ require "cgi"
2
+ require "redcloth_for_tex"
3
+
4
+ class WikiController < ActionControllerServlet
5
+ EXPORT_DIRECTORY = File.dirname(__FILE__) + "/../../storage/" unless const_defined?("EXPORT_DIRECTORY")
6
+
7
+ def index
8
+ if web_address
9
+ redirect_show "HomePage"
10
+ elsif !wiki.setup?
11
+ redirect_path "/new_system/"
12
+ elsif wiki.webs.length == 1
13
+ redirect_show "HomePage", wiki.webs.values.first.address
14
+ else
15
+ redirect_path "/web_list/"
16
+ end
17
+ end
18
+
19
+ # Administrating the Instiki setup --------------------------------------------
20
+
21
+ def new_system
22
+ wiki.setup? ? redirect_path("/") : render
23
+ end
24
+
25
+ def new_web
26
+ redirect_path("/") if wiki.system["password"].nil?
27
+ end
28
+
29
+ def create_system
30
+ wiki.setup(@params["password"], @params["web_name"], @params["web_address"]) unless wiki.setup?
31
+ redirect_path "/"
32
+ end
33
+
34
+ def create_web
35
+ redirect_path("/") unless wiki.authenticate(@params["system_password"])
36
+ wiki.create_web(@params["name"], @params["address"])
37
+ redirect_show("HomePage", @params["address"])
38
+ end
39
+
40
+
41
+ # Outside a single web --------------------------------------------------------
42
+
43
+ def web_list
44
+ @system, @webs = wiki.system, wiki.webs.values
45
+ render "wiki/web_list"
46
+ end
47
+
48
+ def login
49
+ render "wiki/login"
50
+ end
51
+
52
+ def authenticate
53
+ password_check(@params["password"]) ? redirect_show("HomePage") : redirect_action("login")
54
+ end
55
+
56
+ def static_style_sheet() render "static_style_sheet" end
57
+
58
+
59
+ # Within a single web ---------------------------------------------------------
60
+
61
+ def parse_category
62
+ @categories = web.categories
63
+ @category = @params["category"]
64
+ @pages_in_category = web.select { |page| page.in_category?(@category) }
65
+ @set_name = ( @categories.include?(@category) ? "category '#{@category}'" : "the web" )
66
+ @category_links = @categories.map do |c|
67
+ (@category == c ? "<span class=\"selected\">#{c}</span>" : "<a href=\"?category=#{c}\">#{c}</a>")
68
+ end
69
+ end
70
+
71
+ def search
72
+ @query = @params["query"]
73
+ @results = web.select { |page| page.content =~ /#{@query}/i }
74
+ @results.length == 1 ? redirect_show(@results.first.name) : render
75
+ end
76
+
77
+ def authors
78
+ @authors = web.select.authors
79
+ end
80
+
81
+ def recently_revised
82
+ parse_category
83
+ @pages_by_revision = @pages_in_category.by_revision
84
+ end
85
+
86
+ def rss_with_content
87
+ @pages_by_revision = web.select.by_revision.first(15)
88
+ @uri = @req.request_uri
89
+ host = @req.meta_vars["HTTP_X_FORWARDED_HOST"] || "#{@uri.host}:#{@uri.port.to_s}"
90
+ @web_url = "#{@uri.scheme}://#{host}/#{@web.address}"
91
+ @res["Content-Type"] = "text/xml"
92
+ render "wiki/rss_feed"
93
+ end
94
+
95
+ def rss_with_headlines
96
+ @hide_description = true
97
+ rss_with_content
98
+ end
99
+
100
+ def list
101
+ parse_category
102
+ @pages_by_name = @pages_in_category.by_name
103
+ @page_names_that_are_wanted = @pages_in_category.wanted_pages
104
+ @pages_that_are_orphaned = @pages_in_category.orphaned_pages
105
+ end
106
+
107
+ def export_html
108
+ file_name = "#{web.address}-html-#{web.revised_on.strftime("%Y-%m-%d-%H-%M")}.zip"
109
+ file_path = EXPORT_DIRECTORY + file_name
110
+
111
+ export_pages_to_zip_file(file_path) unless FileTest.exists?(file_path)
112
+ send_export(file_name, file_path)
113
+ end
114
+
115
+ def export_markup
116
+ file_name = "#{web.address}-markup-#{web.revised_on.strftime("%Y-%m-%d-%H-%M")}.zip"
117
+ file_path = EXPORT_DIRECTORY + file_name
118
+
119
+ export_markup_to_zip_file(file_path) unless FileTest.exists?(file_path)
120
+ send_export(file_name, file_path)
121
+ end
122
+
123
+ def export_pdf
124
+ file_name = "#{web.address}-tex-#{web.revised_on.strftime("%Y-%m-%d-%H-%M")}"
125
+ file_path = EXPORT_DIRECTORY + file_name
126
+
127
+ export_web_to_tex(file_path + ".tex") unless FileTest.exists?(file_path + ".tex")
128
+ convert_tex_to_pdf(file_path + ".tex")
129
+ send_export(file_name + ".pdf", file_path + ".pdf")
130
+ end
131
+
132
+ def export_tex
133
+ file_name = "#{web.address}-tex-#{web.revised_on.strftime("%Y-%m-%d-%H-%M")}.tex"
134
+ file_path = EXPORT_DIRECTORY + file_name
135
+
136
+ export_web_to_tex(file_path) unless FileTest.exists?(file_path)
137
+ send_export(file_name, file_path)
138
+ end
139
+
140
+ def update_web
141
+ redirect_show("HomePage") unless wiki.authenticate(@params["system_password"])
142
+
143
+ wiki.update_web(
144
+ web.address, @params["address"], @params["name"],
145
+ @params["markup"].intern,
146
+ @params["color"], @params["additional_style"],
147
+ @params["safe_mode"] ? true : false,
148
+ @params["password"].empty? ? nil : @params["password"],
149
+ @params["published"] ? true : false,
150
+ @params["brackets_only"] ? true : false,
151
+ @params["count_pages"] ? true : false
152
+ )
153
+
154
+ redirect_show("HomePage", @params["address"])
155
+ end
156
+
157
+ def remove_orphaned_pages
158
+ if wiki.authenticate(@params["system_password"])
159
+ wiki.remove_orphaned_pages(web_address)
160
+ redirect_action "list/"
161
+ else
162
+ redirect_show "HomePage"
163
+ end
164
+ end
165
+
166
+ # Within a single page --------------------------------------------------------
167
+
168
+ def show
169
+ if @page = wiki.read_page(web_address, page_name)
170
+ begin
171
+ render_action "page"
172
+ rescue => e
173
+ $stderr << e.backtrace.join("\n")
174
+ redirect_action "edit/#{CGI.escape(page_name)}?msg=#{CGI.escape(e.message)}"
175
+ end
176
+ else
177
+ redirect_action "new/#{CGI.escape(page_name)}"
178
+ end
179
+ end
180
+
181
+ def published
182
+ if web.published then @page = wiki.read_page(web_address, page_name || "HomePage") else redirect_show("HomePage") end
183
+ end
184
+
185
+ def print
186
+ @page = wiki.read_page(web_address, page_name)
187
+ end
188
+
189
+ def tex
190
+ @page = wiki.read_page(web_address, page_name)
191
+ @tex_content = RedClothForTex.new(@page.content).to_tex
192
+ end
193
+
194
+ def pdf
195
+ page = wiki.read_page(web_address, page_name)
196
+ safe_page_name = page.name.gsub(/\W/, "")
197
+ file_name = "#{safe_page_name}-#{web.address}-#{page.created_at.strftime("%Y-%m-%d-%H-%M")}"
198
+ file_path = EXPORT_DIRECTORY + file_name
199
+
200
+ export_page_to_tex(file_path + ".tex") unless FileTest.exists?(file_path + ".tex")
201
+ convert_tex_to_pdf(file_path + ".tex")
202
+ send_export(file_name + ".pdf", file_path + ".pdf")
203
+ end
204
+
205
+ def new
206
+ @page_name, @author = page_name, default_author
207
+ end
208
+
209
+ def edit
210
+ @page = wiki.read_page(web_address, page_name)
211
+
212
+ if !@page.locked?(Time.now) || @params["break_lock"]
213
+ @page.lock(Time.now, default_author)
214
+ @author = default_author
215
+ render
216
+ else
217
+ render "wiki/locked"
218
+ end
219
+ end
220
+
221
+ def cancel_edit
222
+ @page = wiki.read_page(web_address, page_name)
223
+ @page.unlock
224
+ redirect_show
225
+ end
226
+
227
+ def save
228
+ if web.pages[page_name]
229
+ page = wiki.revise_page(
230
+ web_address, page_name, @params["content"], Time.now,
231
+ Author.new(@params["author"], remote_ip)
232
+ )
233
+
234
+ page.unlock
235
+ else
236
+ page = wiki.write_page(
237
+ web_address, page_name, @params["content"], Time.now,
238
+ Author.new(@params["author"], remote_ip)
239
+ )
240
+ end
241
+
242
+ write_cookie("author", @params["author"], true)
243
+ redirect_show(page_name)
244
+ end
245
+
246
+ def revision
247
+ @page = wiki.read_page(web_address, page_name)
248
+ @revision = @page.revisions[@params["rev"].to_i]
249
+ end
250
+
251
+ def rollback
252
+ @page = wiki.read_page(web_address, page_name)
253
+ @revision = @page.revisions[@params["rev"].to_i]
254
+ end
255
+
256
+
257
+ protected
258
+ def before_action
259
+ if in_a_web? && !authorized?(web_address) && !%w( login authenticate published ).include?(action_name)
260
+ redirect_action("login")
261
+ return false
262
+ elsif in_a_web?
263
+ @web, @page_name, @action_name = web, page_name, action_name
264
+ end
265
+ end
266
+
267
+ def action_name
268
+ if in_a_web?
269
+ request_path[1]
270
+ elsif action_methods.include?(request_path[0])
271
+ request_path[0]
272
+ else
273
+ "index"
274
+ end
275
+ end
276
+
277
+ def redirect_show(page = @page.name, web = web_address)
278
+ redirect_path "/#{web}/show/#{CGI.escape(page)}"
279
+ end
280
+
281
+ def redirect_action(action, web = web_address)
282
+ redirect_path "/#{web}/#{action}"
283
+ end
284
+
285
+
286
+
287
+ private
288
+ def wiki
289
+ WikiService.instance
290
+ end
291
+
292
+ def web
293
+ wiki.webs[web_address]
294
+ end
295
+
296
+ def in_a_web?
297
+ request_path.length > 1
298
+ end
299
+
300
+ def web_address
301
+ request_path[0]
302
+ end
303
+
304
+ def page_name
305
+ CGI.unescape(request_path[2]) if request_path[2]
306
+ end
307
+
308
+ def authorized?(web_address)
309
+ web.nil? ||
310
+ web.password.nil? ||
311
+ (read_cookie(web_address) && read_cookie(web_address) == web.password) ||
312
+ password_check(@params["password"])
313
+ end
314
+
315
+ def default_author
316
+ read_cookie("author") || "AnonymousCoward"
317
+ end
318
+
319
+ def password_check(password)
320
+ @params["password"] == web.password && write_cookie(web_address, @params["password"])
321
+ end
322
+
323
+ def export_pages_to_zip_file(zip_file_path)
324
+ Zip::ZipOutputStream.open(zip_file_path) do |zos|
325
+ web.select.by_name.each do |@page|
326
+ zos.put_next_entry(@page.name + ".html")
327
+ zos.puts(template_engine("print").result(binding))
328
+ end
329
+
330
+ zos.put_next_entry("index.html")
331
+ zos.puts('<html><head><META HTTP-EQUIV="Refresh" CONTENT="0;URL=HomePage.html"></head></html>')
332
+ end
333
+ end
334
+
335
+ def export_markup_to_zip_file(zip_file_path)
336
+ Zip::ZipOutputStream.open(zip_file_path) do |zos|
337
+ web.select.by_name.each do |page|
338
+ zos.put_next_entry(page.name + ".#{web.markup}")
339
+ zos.puts(page.content)
340
+ end
341
+ end
342
+ end
343
+
344
+ def export_web_to_tex(file_path)
345
+ @web_name = web.name
346
+ @tex_content = table_of_contents(web.pages["HomePage"].content.dup, render_tex_web)
347
+ File.open(file_path, "w") { |f| f.write(template_engine("tex_web").result(binding)) }
348
+ end
349
+
350
+ def render_tex_web
351
+ web.select.by_name.inject({}) do |tex_web, page|
352
+ tex_web[page.name] = RedClothForTex.new(page.content).to_tex
353
+ tex_web
354
+ end
355
+ end
356
+
357
+ def export_page_to_tex(file_path)
358
+ tex
359
+ File.open(file_path, "w") { |f| f.write(template_engine("tex").result(binding)) }
360
+ end
361
+
362
+ def convert_tex_to_pdf(tex_path)
363
+ `cd #{File.dirname(tex_path)}; pdflatex --interaction=scrollmode '#{File.basename(tex_path)}'`
364
+ end
365
+
366
+ def truncate(text, length = 30, truncate_string = "...")
367
+ if text.length > length then text[0..(length - 3)] + truncate_string else text end
368
+ end
369
+
370
+ def render_markup_help
371
+ web ? sub_template("#{web.markup}_help") : ''
372
+ end
373
+
374
+ def send_export(file_name, file_path, content_type = "application/zip")
375
+ @res["Content-Type"] = content_type
376
+ @res["Content-Disposition"] = "attachment; filename=#{file_name}"
377
+ @res["Content-Length"] = File.size(file_path)
378
+ File.open(file_path, "rb") { |f| @res.body = f.read }
379
+ end
380
+
381
+ def template_engine(template_name)
382
+ ERB.new(IO.readlines(action_template_path(template_name)).join)
383
+ end
384
+
385
+ def remote_ip
386
+ $stderr << "#{@req.meta_vars['HTTP_X_FORWARDED_FOR']} || #{@req.meta_vars['REMOTE_ADDR']}"
387
+ @req.meta_vars["HTTP_X_FORWARDED_FOR"] || @req.meta_vars["REMOTE_ADDR"]
388
+ end
389
+ end