Pimki 1.0.092

Sign up to get free protection for your applications and to get access to all the features.
Files changed (85) hide show
  1. data/README +158 -0
  2. data/README-PIMKI +87 -0
  3. data/app/controllers/wiki.rb +563 -0
  4. data/app/models/author.rb +4 -0
  5. data/app/models/chunks/category.rb +31 -0
  6. data/app/models/chunks/category_test.rb +21 -0
  7. data/app/models/chunks/chunk.rb +20 -0
  8. data/app/models/chunks/engines.rb +34 -0
  9. data/app/models/chunks/include.rb +29 -0
  10. data/app/models/chunks/literal.rb +19 -0
  11. data/app/models/chunks/match.rb +19 -0
  12. data/app/models/chunks/nowiki.rb +31 -0
  13. data/app/models/chunks/nowiki_test.rb +14 -0
  14. data/app/models/chunks/test.rb +18 -0
  15. data/app/models/chunks/todo.rb +22 -0
  16. data/app/models/chunks/uri.rb +97 -0
  17. data/app/models/chunks/uri_test.rb +92 -0
  18. data/app/models/chunks/wiki.rb +82 -0
  19. data/app/models/chunks/wiki_test.rb +36 -0
  20. data/app/models/page.rb +91 -0
  21. data/app/models/page_lock.rb +24 -0
  22. data/app/models/page_set.rb +73 -0
  23. data/app/models/page_test.rb +76 -0
  24. data/app/models/revision.rb +91 -0
  25. data/app/models/revision_test.rb +252 -0
  26. data/app/models/web.rb +277 -0
  27. data/app/models/web_test.rb +53 -0
  28. data/app/models/wiki_content.rb +113 -0
  29. data/app/models/wiki_service.rb +137 -0
  30. data/app/models/wiki_service_test.rb +15 -0
  31. data/app/models/wiki_words.rb +26 -0
  32. data/app/models/wiki_words_test.rb +12 -0
  33. data/app/views/bottom.rhtml +4 -0
  34. data/app/views/markdown_help.rhtml +16 -0
  35. data/app/views/menu.rhtml +20 -0
  36. data/app/views/navigation.rhtml +26 -0
  37. data/app/views/rdoc_help.rhtml +16 -0
  38. data/app/views/static_style_sheet.rhtml +231 -0
  39. data/app/views/style.rhtml +179 -0
  40. data/app/views/textile_help.rhtml +28 -0
  41. data/app/views/top.rhtml +52 -0
  42. data/app/views/wiki/authors.rhtml +15 -0
  43. data/app/views/wiki/bliki.rhtml +101 -0
  44. data/app/views/wiki/bliki_edit.rhtml +33 -0
  45. data/app/views/wiki/bliki_new.rhtml +61 -0
  46. data/app/views/wiki/bliki_revision.rhtml +51 -0
  47. data/app/views/wiki/edit.rhtml +34 -0
  48. data/app/views/wiki/edit_menu.rhtml +27 -0
  49. data/app/views/wiki/edit_web.rhtml +139 -0
  50. data/app/views/wiki/export.rhtml +14 -0
  51. data/app/views/wiki/feeds.rhtml +10 -0
  52. data/app/views/wiki/list.rhtml +164 -0
  53. data/app/views/wiki/locked.rhtml +14 -0
  54. data/app/views/wiki/login.rhtml +11 -0
  55. data/app/views/wiki/mind.rhtml +39 -0
  56. data/app/views/wiki/new.rhtml +27 -0
  57. data/app/views/wiki/new_system.rhtml +78 -0
  58. data/app/views/wiki/new_web.rhtml +64 -0
  59. data/app/views/wiki/page.rhtml +84 -0
  60. data/app/views/wiki/print.rhtml +16 -0
  61. data/app/views/wiki/published.rhtml +10 -0
  62. data/app/views/wiki/recently_revised.rhtml +31 -0
  63. data/app/views/wiki/revision.rhtml +87 -0
  64. data/app/views/wiki/rss_feed.rhtml +22 -0
  65. data/app/views/wiki/search.rhtml +26 -0
  66. data/app/views/wiki/tex.rhtml +23 -0
  67. data/app/views/wiki/tex_web.rhtml +35 -0
  68. data/app/views/wiki/todo.rhtml +39 -0
  69. data/app/views/wiki/web_list.rhtml +13 -0
  70. data/app/views/wiki_words_help.rhtml +8 -0
  71. data/libraries/action_controller_servlet.rb +177 -0
  72. data/libraries/bluecloth.rb +1127 -0
  73. data/libraries/diff/diff.rb +475 -0
  74. data/libraries/diff/diff_test.rb +80 -0
  75. data/libraries/erb.rb +490 -0
  76. data/libraries/madeleine/automatic.rb +357 -0
  77. data/libraries/madeleine/clock.rb +94 -0
  78. data/libraries/madeleine_service.rb +69 -0
  79. data/libraries/rdocsupport.rb +156 -0
  80. data/libraries/redcloth_for_tex.rb +869 -0
  81. data/libraries/redcloth_for_tex_test.rb +41 -0
  82. data/libraries/view_helper.rb +33 -0
  83. data/libraries/web_controller_server.rb +95 -0
  84. data/pimki.rb +97 -0
  85. metadata +169 -0
data/README ADDED
@@ -0,0 +1,158 @@
1
+ <pre>
2
+ What is Instiki?
3
+ ================
4
+
5
+ Admitted, it's Yet Another Wiki Clone[1], but with a strong focus
6
+ on simplicity of installation and running:
7
+
8
+ Step 1. Download
9
+ Step 2. Run "instiki.rb"
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 for persistence (all pages are in memory)
31
+ * Three markup choices: Textile (default / RedCloth), Markdown (BlueCloth), and RDoc
32
+ * Embedded webserver: Through WEBrick
33
+ * Internationalization: Wiki words in any latin, greek, cyrillian, or armenian characters
34
+ * Color diffs: Track changes through revisions
35
+
36
+ Missing:
37
+ * File attachments
38
+
39
+ Command-line options:
40
+ Run "ruby instiki.rb --help"
41
+
42
+ History:
43
+ * 0.9.2: Changed rollback link to be powered by javascript so it's not trigged by search engines
44
+ Changed to use inline style on published pages
45
+ Fixed "forward in time" on the last revision before current page
46
+ * 0.9.1: Added performance improvements for updating existing pages
47
+ Fixed IP logging and RSS feeds behind proxies [With help from Guan Yang]
48
+ Fixed default storage directory (borked running on Windows) [Spotted by Curt Hibbs]
49
+ * 0.9.0: Added aliased links such as [[HomePage|that nice home page]] [Mark Reid]
50
+ Added include other page content with [[!include TableOfContents]] [Mark Reid]
51
+ Added delete orphan pages from the Edit Web screen [by inspiration from Simon Arnaud]
52
+ Added logging of IP address for authors (who's behind the rollback wars)
53
+ Added Categories pages through backlinks (use "categories: news, instiki" on start of line) [Mark Reid]
54
+ Added option to use bracket-style wiki links only (and hence ban WikiWords)
55
+ Added command-line option to specify different storage path
56
+ Added print view without navigation
57
+ Added character and page (2275 characters including spaces) counter (important for student papers)
58
+ Off by default, activate it on the Edit Web screen
59
+ Added LaTeX/PDF integration on Textile installations with pdflatex installed on system (EXPERIMENTAL)
60
+ Use the home page as a table of contents with a unordered list to control sections
61
+ Added limit of 15 to the number of pages included in RSS feed
62
+ Moved static parts of stylesheet to separate file [Lau T�rnskov]
63
+ Fixed better semantics for revision movement [Ryan Singer]
64
+ Fixed color diffs to work much better [Xen/Mertz/Atkins]
65
+ Fixed performance problems for All Pages list [Dennis Mertz]
66
+ Fixed lots of rendering bugs [Mark Reid]
67
+ Upgraded to RedCloth 2.0.11 [integrating the fine work of Dennis Mertz]
68
+ * 0.8.9: Added color diffs to see changes between revisions [Bill Atkins]
69
+ They're aren't quite perfect yet as new paragraphs split the <ins> tags (hence 0.8.9, not 0.9.0)
70
+ Added redirect to edit if content of page generates an error
71
+ (so the page doesn't become unusable on bugs in the markup engines)
72
+ Fixed update Web with different address bug [Denis Metz]
73
+ Fixed a bunch of wiki word rendering issues by doing wiki word detection and replacment at once
74
+ Upgraded to BlueCloth 0.0.3b (should fix loads of problems on Markdown wikis)
75
+ * 0.8.5: Instiki can now serve as a CMS by running a password-protected web with a published front
76
+ Added version check at startup (Instiki needs Ruby 1.8.1)
77
+ * 0.8.1: Actually included RedCloth 2.0.7 in the release
78
+ * 0.8.0: NOTE: Single-web wikis created in versions prior to 0.8.0 have "instiki" as their system password
79
+ Accepts wiki words in bracket style. Ex: [[wiki word]], [[c]], [[We could'nt have done it!]]
80
+ Accepts camel-case wiki words in all latin, greek, cyrillian, and armenian unicode characters
81
+ Many thanks to Guan Yang for building the higher- and lower-case lookup tables
82
+ And thanks to Simon Arnaud for the initial patch that got the work started
83
+ Changed charset to UTF-8
84
+ Cut down on command-line options and replaced them with an per-web config screen
85
+ Added option to extend the stylesheet on a per-web basis to tweak the look in details
86
+ Added simple color options for variety
87
+ Added option to add/remove password protection on each web
88
+ Added the wiki name of the author locking a given page (instead of just "someone")
89
+ Removed single/multi-web distinction -- all Instikis are now multi-web
90
+ Load libraries from an unshifted load path, so that old installed libraries doesn't clash [Emiel van de Laar]
91
+ Keeps the author cookie forever, so you don't have to enter your name again and again
92
+ Fixed XHTML so it validates [Bruce D'Arcus]
93
+ Authors are no longer listed under orphan pages
94
+ Added export to markup (great for backups, potentially for switching wiki engine)
95
+ Don't link wiki words that proceeds from either /, = or ?
96
+ (http://c2.com/cgi/wiki?WikiWikiClones, /show/HomePage, cgi.pl?show=WikiWord without escaping)
97
+ Accessing an unexisting page redirects to a different url (/new/PageName)
98
+ Increased snapshot time to just once a day (cuts down on disk storage requirements)
99
+ Made RDoc support work better with 1.8.1 [Mauricio Fern�ndez]
100
+ Added convinient redirect from /wiki/ to /wiki/show/HomePage
101
+ Fixed BlueCloth bug with backticks at start of line
102
+ Updated to RedCloth 2.0.7 (and linked to the new Textile reference)
103
+ * 0.7.0: Added Markdown (BlueCloth) and RDoc [Mauricio Fern�ndez] as command-line markup choices
104
+ Added wanted and orphan page lists to All pages (only show up if there's actually orphan or wanted pages)
105
+ Added ISO-8859-1 as XML encoding in RSS feeds (makes FeedReader among others happy for special entities)
106
+ Added proper links in the RSS feed (but the body links are still relative, which NNW and others doesn't grok)
107
+ Added access keys: E => Edit, H => HomePage, A => All Pages, U => Recently Revised, X => Export
108
+ Added password-login through URL (so you can subscribe to feed on a protected web)
109
+ Added web passwords to the feed links for protected webs, so they work without manual login
110
+ Added the web name in small letters above all pages within a web
111
+ Polished authors and recently revised
112
+ Updated to RedCloth 2.0.6
113
+ Changed content type for RSS feeds to text/xml (makes Mozilla Aggreg8 happy)
114
+ Changed searching to be case insensitive
115
+ Changed HomePage to display the name of the web instead
116
+ Changed exported HTML pages to be valid XHTML (which can be preprocessed by XSLT)
117
+ Fixed broken recently revised
118
+ * 0.6.0: Fixed Windows compatibility [Florian]
119
+ Fixed bug that would prevent Madeleine from taking snapshots in Daemon mode
120
+ Added export entire web as HTML in a zip file
121
+ Added RSS feeds
122
+ Added proper getops support for the growing number of options [Florian]
123
+ Added safe mode that forbids style options in RedCloth [Florian]
124
+ Updated RedCloth to 2.0.5
125
+ * 0.5.0: NOTE: 0.5.0 is NOT compatible with databases from earlier versions
126
+ Added revisions
127
+ Added multiple webs
128
+ Added password protection for webs on multi-web setups
129
+ Added the notion of authors (that are saved in a cookie)
130
+ Added command-line option for not running as a Daemon on Unix
131
+ * 0.3.1: Added option to escape wiki words with \
132
+ * 0.3.0: Brought all files into common style (including Textile help on the edit page)
133
+ Added page locking (if someone already is editing a page there's a warning)
134
+ Added daemon abilities on Unix (keep Instiki running after you close the terminal)
135
+ Made port 2500 the default port, so Instiki can be launched by dobbelt-click
136
+ Added Textile cache to speed-up rendering of large pages
137
+ Made WikiWords look like "Wiki Words"
138
+ Updated RedCloth to 2.0.4
139
+ * 0.2.5: Upgraded to RedCloth 2.0.2 and Madeleine 0.6.1, which means the
140
+ Windows problems are gone. Also fixed a problem with wikiwords
141
+ that used part of other wikiwords.
142
+ * 0.2.0: First public release
143
+
144
+ Download latest from:
145
+ <a href="http://rubyforge.org/project/showfiles.php?group_id=186">http://rubyforge.org/project/showfiles.php?group_id=186</a>
146
+
147
+ Visit the official Instiki wiki:
148
+ http://www.instiki.org/
149
+
150
+ License is the same as Ruby's
151
+
152
+ [1] <a href="http://c2.com/cgi/wiki?WikiWikiClones">http://c2.com/cgi/wiki?WikiWikiClones</a>
153
+ [2] Textile Syntax: <a href="http://www.textism.com/tools/textile/">http://www.textism.com/tools/textile/</a>
154
+ --
155
+ David Heinemeier Hansson,
156
+ david@loudthinking.com
157
+ http://www.loudthinking.com/
158
+ </pre>
@@ -0,0 +1,87 @@
1
+ <pre>
2
+ What is Pimki?
3
+ ================
4
+
5
+ Pimki is a Personal Information Manager based on Instiki's Wiki technology.
6
+
7
+ It has some added features over Instiki, while keeping the simplicity of
8
+
9
+ Instiki Features:
10
+ * Regular expression search: Find deep stuff really fast
11
+ * Revisions: Follow the changes on every page from birth. Rollback to an earlier rev
12
+ * Export to HTML or markup in a zip: Take the entire wiki with you home or for reference
13
+ * RSS feeds to track recently revised pages
14
+ * Multiple webs: Create separate wikis with their own namespace
15
+ * Password-protected webs: Keep it private
16
+ * Authors: Each revision is associated with an author, so you can see who changed what
17
+ * Reference tracker: Which other pages are pointing to the current?
18
+ * Speed: Using Madelein for persistence (all pages are in memory)
19
+ * Three markup choices: Textile (default / RedCloth), Markdown (BlueCloth), and RDoc
20
+ * Embedded webserver: Through WEBrick
21
+ * Internationalization: Wiki words in any latin, greek, cyrillian, or armenian characters
22
+ * Color diffs: Track changes through revisions
23
+
24
+ Pimki added features:
25
+ * Mind Map: a graph of wiki connections (made with GraphViz). All graphs can be
26
+ laid-out with the 4 GraphViz engines. Graph contents can be arranged as:
27
+ * Page ? linked pages
28
+ * Authors ? pages
29
+ * Categories ? pages
30
+ * Bliki: a blog integrated with the wiki. Blog entries are simply wiki-pages in
31
+ a special space. Can link from an entry to wiki pages.
32
+ * Todo Items & List:
33
+ * �todo:� items are highlighted on each page.
34
+ * Added a capacity to pull and list todo items from all pages.
35
+ * On main list, items are highlighted according to date (if there is one).
36
+ * Added capacity to (persistently :) delete/rename pages through the 'All Pages'
37
+ list.
38
+ * Added left-side menu. Content options are:
39
+ * Only pages that reference other pages (default)
40
+ * All pages: by name
41
+ * All pages: recently revised
42
+ * All pages: recently visited
43
+ * All pages: most often visited
44
+ * User definable wiki-text
45
+ * Expanded Search:
46
+ * Search also tries to match the page names (not just contents).
47
+ * Now showing part of sentance around match in search-results page
48
+ * Removed unnecessary (for me) stuff from the nav-bar: RSS, authors, export.
49
+ Moved to bottom of Home Page.
50
+
51
+ Missing:
52
+
53
+ * Expand todo with more task types?
54
+ * Expand Search
55
+ * Highlight on individual page when clicked form search results
56
+ * Advanced Search (not just regexp, case sensitivity)?
57
+ * Editable left-side menu options: by search results? by author?
58
+ * Bliki: allow linking from wiki-pages to bliki entries.
59
+
60
+
61
+ Command-line options:
62
+ Run "ruby pimki.rb --help"
63
+
64
+ History:
65
+
66
+ 0.9.2-7 Initial Public Release
67
+ I have been working on Pimki for my own use for quite some time. It is
68
+ fairly mature and stable. The version number reflects the base Instiki
69
+ version (0.9.2; or actually the latest CVS that's markes so) and the
70
+ running number of my feature-addition releases.
71
+
72
+
73
+ Download latest from:
74
+ <a href="http://rubyforge.org/project/showfiles.php?group_id=447">http://rubyforge.org/project/showfiles.php?group_id=447</a>
75
+
76
+ Visit the official Pimki home page at:
77
+ http://pimki.rubyforge.org/
78
+
79
+ Visit the official Instiki wiki:
80
+ http://www.instiki.org/
81
+
82
+ License is the same as Ruby's.
83
+
84
+ --
85
+ Assaph Mehr
86
+ assaph@gmail.com
87
+ </pre>
@@ -0,0 +1,563 @@
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
+ # Within a single web ---------------------------------------------------------
59
+
60
+ def parse_category
61
+ @categories = web.categories
62
+ @category = @params["category"]
63
+ @pages_in_category = web.select { |page| page.in_category?(@category) }
64
+ @set_name = ( @categories.include?(@category) ? "category '#{@category}'" : "the web" )
65
+ @category_links = @categories.map do |c|
66
+ (@category == c ? "<span class=\"selected\">#{c}</span>" : "<a href=\"?category=#{c}\">#{c}</a>")
67
+ end
68
+ end
69
+
70
+ def search
71
+ set_menu_pages
72
+ @query = @params["query"]
73
+ rex = /#{@query}/i
74
+ @results = web.select { |page| rex.match(page.name) or rex.match(page.content) }
75
+ @results.length == 1 ? redirect_show(@results.first.name) : render
76
+ end
77
+
78
+ def authors
79
+ @authors = web.select.authors
80
+ end
81
+
82
+ def recently_revised
83
+ parse_category
84
+ set_menu_pages
85
+ @pages_by_revision = @pages_in_category.by_revision
86
+ end
87
+
88
+ def rss_with_content
89
+ @pages_by_revision = web.select.by_revision.first(15)
90
+ @uri = @req.request_uri
91
+ host = @req.meta_vars["HTTP_X_FORWARDED_HOST"] || "#{@uri.host}:#{@uri.port.to_s}"
92
+ @web_url = "#{@uri.scheme}://#{host}/#{@web.address}"
93
+ @res["Content-Type"] = "text/xml"
94
+ render "wiki/rss_feed"
95
+ end
96
+
97
+ def rss_with_headlines
98
+ @hide_description = true
99
+ rss_with_content
100
+ end
101
+
102
+ def list
103
+ parse_category
104
+ set_menu_pages
105
+ @pages_by_name = @pages_in_category.by_name
106
+ @page_names_that_are_wanted = @pages_in_category.wanted_pages
107
+ @pages_that_are_orphaned = @pages_in_category.orphaned_pages
108
+ case @req.query['Action']
109
+ when 'Delete' # Handle page deletion
110
+ wiki.delete_page(web_address, @req.query['sel_page_name'])
111
+ redirect_action "list/"
112
+
113
+ when 'Create' # Handle page creation
114
+ redirect_show @req.query['newpage']
115
+
116
+ when 'Rename' # Handle page rename
117
+ wiki.rename_page(web_address, @req.query['sel_page_name'], @req.query['newpage'])
118
+ redirect_action "list/"
119
+ end
120
+
121
+ end
122
+
123
+ def export_html
124
+ file_name = "#{web.address}-html-#{web.revised_on.strftime("%Y-%m-%d-%H-%M")}.zip"
125
+ file_path = EXPORT_DIRECTORY + file_name
126
+
127
+ export_pages_to_zip_file(file_path) unless FileTest.exists?(file_path)
128
+ send_export(file_name, file_path)
129
+ end
130
+
131
+ def export_markup
132
+ file_name = "#{web.address}-markup-#{web.revised_on.strftime("%Y-%m-%d-%H-%M")}.zip"
133
+ file_path = EXPORT_DIRECTORY + file_name
134
+
135
+ export_markup_to_zip_file(file_path) unless FileTest.exists?(file_path)
136
+ send_export(file_name, file_path)
137
+ end
138
+
139
+ def export_pdf
140
+ file_name = "#{web.address}-tex-#{web.revised_on.strftime("%Y-%m-%d-%H-%M")}"
141
+ file_path = EXPORT_DIRECTORY + file_name
142
+
143
+ export_web_to_tex(file_path + ".tex") unless FileTest.exists?(file_path + ".tex")
144
+ convert_tex_to_pdf(file_path + ".tex")
145
+ send_export(file_name + ".pdf", file_path + ".pdf")
146
+ end
147
+
148
+ def export_tex
149
+ file_name = "#{web.address}-tex-#{web.revised_on.strftime("%Y-%m-%d-%H-%M")}.tex"
150
+ file_path = EXPORT_DIRECTORY + file_name
151
+
152
+ export_web_to_tex(file_path) unless FileTest.exists?(file_path)
153
+ send_export(file_name, file_path)
154
+ end
155
+
156
+ def update_web
157
+ redirect_show("HomePage") unless wiki.authenticate(@params["system_password"])
158
+
159
+ wiki.update_web(
160
+ web.address, @params["address"], @params["name"],
161
+ @params["markup"].intern,
162
+ @params["color"], @params["additional_style"],
163
+ @params["safe_mode"] ? true : false,
164
+ @params["password"].empty? ? nil : @params["password"],
165
+ @params["published"] ? true : false,
166
+ @params["brackets_only"] ? true : false,
167
+ @params["count_pages"] ? true : false
168
+ )
169
+
170
+ redirect_show("HomePage", @params["address"])
171
+ end
172
+
173
+ def remove_orphaned_pages
174
+ if wiki.authenticate(@params["system_password"])
175
+ wiki.remove_orphaned_pages(web_address)
176
+ redirect_action "list/"
177
+ else
178
+ redirect_show "HomePage"
179
+ end
180
+ end
181
+
182
+ def todo #{{{
183
+ parse_category
184
+ set_menu_pages
185
+ @pages_by_name = @pages_in_category.by_name
186
+ @todo_items = Hash.new { Array.new }
187
+ @pages_by_name.each do |page|
188
+ if page.content =~ Todo.pattern
189
+ # Page has todo items. Get the rendered version (marked-up and with links):
190
+ content = page.revisions.last.display_content
191
+ @todo_items[page] = content.scan /<span class="todo"><strong>TODO:<\/strong> (.*?)<\/span>/
192
+ end
193
+ end
194
+ @todo_items = @todo_items.sort_by { |page, items| page.name }
195
+ end #}}}
196
+
197
+ def set_menu_pages #{{{
198
+ parse_category
199
+ @menu_pages = case web.menu_type
200
+ when 'all' then @pages_in_category.by_name
201
+ when 'recent' then @pages_in_category.by_last_visited
202
+ when 'viewed' then @pages_in_category.by_most_viewed
203
+ when 'revised' then @pages_in_category.by_revision
204
+ when 'user' then @menu_content = web.rendered_menu; nil
205
+ when 'linkers'
206
+ web.select { |page|
207
+ page.wiki_words.size > 0
208
+ }.sort_by { |page| page.name }
209
+ end
210
+ if web.menu_limit
211
+ @menu_pages = @menu_pages[0..web.menu_limit]
212
+ end
213
+ end #}}}
214
+
215
+ def bliki #{{{
216
+ set_menu_pages
217
+ @entries = web.bliki_entries_by_date
218
+ unless @req.query['authorname'].nil? || @req.query['authorname'] == 'noselect'
219
+ @entries = @entries.select { |page|
220
+ page.authors.include?(@req.query['authorname'])
221
+ }
222
+ end
223
+ unless @req.query['regexp'].nil?
224
+ @entries = @entries.select { |page|
225
+ page.content =~ /#{@req.query['regexp']}/i
226
+ }
227
+ end
228
+ @color = web.color
229
+ @authors = web.authors
230
+ end #}}}
231
+
232
+ def mind #{{{
233
+ parse_category
234
+ set_menu_pages
235
+
236
+ @prog = @req.query['draw_type'] || 'neato'
237
+ @graph_type = @req.query['graph_type'] || 'normal'
238
+ missing = @pages_in_category.wanted_pages if @req.query['missing']
239
+ show_authors = @req.query['show_authors'] == 'on'
240
+ @pngFile = @mapFile = nil
241
+ case @graph_type
242
+ when 'normal' then @pngFile, @mapFile = web.create_mind_map(@prog, missing, show_authors)
243
+ when 'author' then @pngFile, @mapFile = web.create_author_graph(@prog)
244
+ when 'category' then @pngFile, @mapFile = web.create_category_graph(@prog, show_authors)
245
+ end
246
+ end #}}}
247
+
248
+ def edit_menu #{{{
249
+ @menu_type = web.menu_type
250
+ @menu_content = web.menu_content
251
+ @list_limit = web.menu_limit
252
+ @list_limit += 1 if @list_limit >= -1
253
+ end #}}}
254
+
255
+ def save_menu #{{{
256
+ unless @req.query['action'] == 'Cancel Update'
257
+ type = @req.query['type']
258
+ content = @req.query['content']
259
+
260
+ limit = @req.query['limit'].to_i rescue nil
261
+ limit = 20 unless limit
262
+ limit -= 1 if limit >= 0
263
+
264
+ # need to go through the WikiService to persist the command:
265
+ wiki.save_menu_pref web, type, limit, content
266
+ end
267
+
268
+ if web_address
269
+ redirect_show "HomePage"
270
+ elsif wiki.webs.length == 1
271
+ redirect_show "HomePage", wiki.webs.values.first.address
272
+ else
273
+ redirect_path "/web_list/"
274
+ end
275
+ end #}}}
276
+
277
+
278
+ # Within a single page --------------------------------------------------------
279
+
280
+ def show
281
+ set_menu_pages
282
+ if @page = wiki.read_page(web_address, page_name)
283
+ unless page_name == 'HomePage'
284
+ # HomePage should not be in the menu as there's a link at the top.
285
+ @page.last_visited = Time.now
286
+ @page.viewed += 1
287
+ end
288
+ begin
289
+ render_action "page"
290
+ rescue => e
291
+ $stderr << e.backtrace.join("\n")
292
+ redirect_action "edit/#{CGI.escape(page_name)}?msg=#{CGI.escape(e.message)}"
293
+ end
294
+ else
295
+ redirect_action "new/#{CGI.escape(page_name)}"
296
+ end
297
+ end
298
+
299
+ def published
300
+ if web.published then @page = wiki.read_page(web_address, page_name || "HomePage") else redirect_show("HomePage") end
301
+ end
302
+
303
+ def print
304
+ @page = wiki.read_page(web_address, page_name)
305
+ end
306
+
307
+ def tex
308
+ @page = wiki.read_page(web_address, page_name)
309
+ @tex_content = RedClothForTex.new(@page.content).to_tex
310
+ end
311
+
312
+ def pdf
313
+ page = wiki.read_page(web_address, page_name)
314
+ safe_page_name = page.name.gsub(/\W/, "")
315
+ file_name = "#{safe_page_name}-#{web.address}-#{page.created_at.strftime("%Y-%m-%d-%H-%M")}"
316
+ file_path = EXPORT_DIRECTORY + file_name
317
+
318
+ export_page_to_tex(file_path + ".tex") unless FileTest.exists?(file_path + ".tex")
319
+ convert_tex_to_pdf(file_path + ".tex")
320
+ send_export(file_name + ".pdf", file_path + ".pdf")
321
+ end
322
+
323
+ def new
324
+ @page_name, @author = page_name, default_author
325
+ end
326
+
327
+ def edit
328
+ @page = wiki.read_page(web_address, page_name)
329
+
330
+ if !@page.locked?(Time.now) || @params["break_lock"]
331
+ @page.lock(Time.now, default_author)
332
+ @author = default_author
333
+ render
334
+ else
335
+ render "wiki/locked"
336
+ end
337
+ end
338
+
339
+ def cancel_edit
340
+ @page = wiki.read_page(web_address, page_name)
341
+ @page.unlock
342
+ redirect_show
343
+ end
344
+
345
+ def save
346
+ if web.pages[page_name]
347
+ page = wiki.revise_page(
348
+ web_address, page_name, @params["content"], Time.now,
349
+ Author.new(@params["author"], remote_ip)
350
+ )
351
+
352
+ page.unlock
353
+ else
354
+ page = wiki.write_page(
355
+ web_address, page_name, @params["content"], Time.now,
356
+ Author.new(@params["author"], remote_ip)
357
+ )
358
+ end
359
+
360
+ write_cookie("author", @params["author"], true)
361
+ redirect_show(page_name)
362
+ end
363
+
364
+ def revision
365
+ @page = wiki.read_page(web_address, page_name)
366
+ @revision = @page.revisions[@params["rev"].to_i]
367
+ end
368
+
369
+ def rollback
370
+ @page = wiki.read_page(web_address, page_name)
371
+ wiki.rollback_page(web_address, page_name, @params["rev"].to_i, Time.now, remote_ip)
372
+ redirect_show
373
+ end
374
+
375
+ # Bliki ----------------------------------------------------------------------
376
+
377
+ def bliki_delete
378
+ wiki.delete_bliki_entry(web_address, page_name)
379
+ redirect_bliki("")
380
+ end
381
+
382
+ def bliki_edit
383
+ @page = wiki.read_bliki_entry(web_address, page_name)
384
+
385
+ if !@page.locked?(Time.now) || @params["break_lock"]
386
+ @page.lock(Time.now, default_author)
387
+ @author = default_author
388
+ render
389
+ else
390
+ redirect_path "#{web_address}/locked"
391
+ end
392
+ end
393
+
394
+ def cancel_bliki_edit
395
+ @page = wiki.read_bliki_entry(web_address, page_name)
396
+ @page.unlock if @page
397
+ redirect_bliki(@page? @page.name : "")
398
+ end
399
+
400
+ def bliki_save
401
+ pname = page_name || @params["pagename"]
402
+ if web.bliki[pname]
403
+ page = wiki.revise_bliki_entry(web_address, pname, @params["content"], Time.now, @params["author"])
404
+ page.unlock
405
+ else
406
+ page = wiki.write_bliki_entry(web_address, pname, @params["content"], Time.now, @params["author"])
407
+ end
408
+
409
+ write_cookie("author", @params["author"])
410
+ redirect_bliki('')
411
+ end
412
+
413
+ def bliki_revision
414
+ @page = wiki.read_bliki_entry(web_address, page_name || @params['pagename'])
415
+ @revision = @page.revisions[@params["rev"].to_i] || @page.revisions.last
416
+ end
417
+
418
+ def rollback_bliki
419
+ @page = wiki.read_bliki_entry(web_address, page_name)
420
+ wiki.rollback_bliki_entry(web_address, page_name, @params["rev"].to_i-1, Time.now)
421
+ redirect_bliki
422
+ end
423
+
424
+ # ----------------------------------------------------------------------------
425
+
426
+ protected
427
+ def before_action
428
+ if in_a_web? && !authorized?(web_address) && !%w( login authenticate published ).include?(action_name)
429
+ redirect_action("login")
430
+ return false
431
+ elsif in_a_web?
432
+ @web, @page_name, @action_name = web, page_name, action_name
433
+ end
434
+ end
435
+
436
+ def action_name
437
+ if in_a_web?
438
+ request_path[1]
439
+ elsif action_methods.include?(request_path[0])
440
+ request_path[0]
441
+ else
442
+ "index"
443
+ end
444
+ end
445
+
446
+ def redirect_show(page = @page.name, web = web_address)
447
+ redirect_path "/#{web}/show/#{CGI.escape(page)}"
448
+ end
449
+
450
+ def redirect_bliki(page = @page.name, web = web_address)
451
+ redirect_path "/#{web}/bliki/#{page}"
452
+ end
453
+
454
+ def redirect_action(action, web = web_address)
455
+ redirect_path "/#{web}/#{action}"
456
+ end
457
+
458
+
459
+
460
+ private
461
+ def wiki
462
+ WikiService.instance
463
+ end
464
+
465
+ def web
466
+ wiki.webs[web_address]
467
+ end
468
+
469
+ def in_a_web?
470
+ request_path.length > 1
471
+ end
472
+
473
+ def web_address
474
+ request_path[0]
475
+ end
476
+
477
+ def page_name
478
+ CGI.unescape(request_path[2]) if request_path[2]
479
+ end
480
+
481
+ def authorized?(web_address)
482
+ (web && web.password.nil?) ||
483
+ (read_cookie(web_address) && read_cookie(web_address) == web.password) ||
484
+ password_check(@params["password"])
485
+ end
486
+
487
+ def default_author
488
+ read_cookie("author") || "AnonymousCoward"
489
+ end
490
+
491
+ def password_check(password)
492
+ web && @params["password"] == web.password && write_cookie(web_address, @params["password"])
493
+ end
494
+
495
+ def export_pages_to_zip_file(zip_file_path)
496
+ Zip::ZipOutputStream.open(zip_file_path) do |zos|
497
+ web.select.by_name.each do |@page|
498
+ zos.put_next_entry(@page.name + ".html")
499
+ zos.puts(template_engine("print").result(binding))
500
+ end
501
+
502
+ zos.put_next_entry("index.html")
503
+ zos.puts('<html><head><META HTTP-EQUIV="Refresh" CONTENT="0;URL=HomePage.html"></head></html>')
504
+ end
505
+ end
506
+
507
+ def export_markup_to_zip_file(zip_file_path)
508
+ Zip::ZipOutputStream.open(zip_file_path) do |zos|
509
+ web.select.by_name.each do |page|
510
+ zos.put_next_entry(page.name + ".#{web.markup}")
511
+ zos.puts(page.content)
512
+ end
513
+ end
514
+ end
515
+
516
+ def export_web_to_tex(file_path)
517
+ @web_name = web.name
518
+ @tex_content = table_of_contents(web.pages["HomePage"].content.dup, render_tex_web)
519
+ File.open(file_path, "w") { |f| f.write(template_engine("tex_web").result(binding)) }
520
+ end
521
+
522
+ def render_tex_web
523
+ web.select.by_name.inject({}) do |tex_web, page|
524
+ tex_web[page.name] = RedClothForTex.new(page.content).to_tex
525
+ tex_web
526
+ end
527
+ end
528
+
529
+ def export_page_to_tex(file_path)
530
+ tex
531
+ File.open(file_path, "w") { |f| f.write(template_engine("tex").result(binding)) }
532
+ end
533
+
534
+ def convert_tex_to_pdf(tex_path)
535
+ `cd #{File.dirname(tex_path)}; pdflatex --interaction=scrollmode '#{File.basename(tex_path)}'`
536
+ end
537
+
538
+ def truncate(text, length = 30, truncate_string = "...")
539
+ if text.length > length then text[0..(length - 3)] + truncate_string else text end
540
+ end
541
+
542
+ def render_markup_help
543
+ sub_template "#{web.markup}_help"
544
+ end
545
+
546
+ def send_export(file_name, file_path, content_type = "application/zip")
547
+ @res["Content-Type"] = content_type
548
+ @res["Content-Disposition"] = "attachment; filename=#{file_name}"
549
+ @res["Content-Length"] = File.size(file_path)
550
+ File.open(file_path, "rb") { |f| @res.body = f.read }
551
+ end
552
+
553
+ def template_engine(template_name)
554
+ ERB.new(IO.readlines(action_template_path(template_name)).join)
555
+ end
556
+
557
+ def remote_ip
558
+ $stderr << "#{@req.meta_vars['HTTP_X_FORWARDED_FOR']} || #{@req.meta_vars['REMOTE_ADDR']}"
559
+ @req.meta_vars["HTTP_X_FORWARDED_FOR"] || @req.meta_vars["REMOTE_ADDR"]
560
+ end
561
+ end
562
+
563
+ # jEdit :folding=indent:collapseFolds=2: