require "cgi"
require "redcloth_for_tex"
class WikiController < ActionControllerServlet
EXPORT_DIRECTORY = WikiService.storage_path unless const_defined?("EXPORT_DIRECTORY")
def index
if web_address
redirect_show "HomePage"
elsif !wiki.setup?
redirect_path "/new_system/"
elsif wiki.webs.length == 1
redirect_show "HomePage", wiki.webs.values.first.address
else
redirect_path "/web_list/"
end
end
# Administrating the Instiki setup --------------------------------------------
def new_system
wiki.setup? ? redirect_path("/") : render
end
def new_web
redirect_path("/") if wiki.system["password"].nil?
end
def create_system
wiki.setup(@params["password"], @params["web_name"], @params["web_address"]) unless wiki.setup?
redirect_path "/"
end
def create_web
redirect_path("/") unless wiki.authenticate(@params["system_password"])
wiki.create_web(@params["name"], @params["address"])
redirect_show("HomePage", @params["address"])
end
# Outside a single web --------------------------------------------------------
def web_list
@system, @webs = wiki.system, wiki.webs.values
render "wiki/web_list"
end
def login
render "wiki/login"
end
def authenticate
password_check(@params["password"]) ? redirect_show("HomePage") : redirect_action("login")
end
def static_style_sheet() render "static_style_sheet" end
# Within a single web ---------------------------------------------------------
def parse_category
@categories = web.categories
@category = @params["category"]
@pages_in_category = web.select { |page| page.in_category?(@category) }
@set_name = ( @categories.include?(@category) ? "category '#{@category}'" : "the web" )
@category_links = @categories.map do |c|
(@category == c ? "#{c}" : "#{c}")
end
end
def search
set_menu_pages
@query = @params["query"]
rex = /#{@query}/i
@results = web.select { |page| rex.match(page.name) or rex.match(page.content) }
@results.length == 1 ? redirect_show(@results.first.name) : render
end
def authors
@authors = web.select.authors
end
def recently_revised
parse_category
set_menu_pages
@pages_by_revision = @pages_in_category.by_revision
end
def rss_with_content
@pages_by_revision = web.select.by_revision.first(15)
@uri = @req.request_uri
host = @req.meta_vars["HTTP_X_FORWARDED_HOST"] || "#{@uri.host}:#{@uri.port.to_s}"
@web_url = "#{@uri.scheme}://#{host}/#{@web.address}"
@res["Content-Type"] = "text/xml"
render "wiki/rss_feed"
end
def rss_with_headlines
@hide_description = true
rss_with_content
end
def list
parse_category
set_menu_pages
@pages_by_name = @pages_in_category.by_name
@page_names_that_are_wanted = @pages_in_category.wanted_pages
@pages_that_are_orphaned = @pages_in_category.orphaned_pages
case @req.query['Action']
when 'Delete' # Handle page deletion
wiki.delete_page(web_address, @req.query['sel_page_name'])
redirect_action "list/"
when 'Create' # Handle page creation
redirect_show @req.query['newpage']
when 'Rename' # Handle page rename
wiki.rename_page(web_address, @req.query['sel_page_name'], @req.query['newpage'])
redirect_action "list/"
end
end
def export_html
file_name = "#{web.address}-html-#{web.revised_on.strftime("%Y-%m-%d-%H-%M")}.zip"
file_path = EXPORT_DIRECTORY + file_name
export_pages_to_zip_file(file_path) unless FileTest.exists?(file_path)
send_export(file_name, file_path)
end
def export_markup
file_name = "#{web.address}-markup-#{web.revised_on.strftime("%Y-%m-%d-%H-%M")}.zip"
file_path = EXPORT_DIRECTORY + file_name
export_markup_to_zip_file(file_path) unless FileTest.exists?(file_path)
send_export(file_name, file_path)
end
def export_pdf
file_name = "#{web.address}-tex-#{web.revised_on.strftime("%Y-%m-%d-%H-%M")}"
file_path = EXPORT_DIRECTORY + file_name
export_web_to_tex(file_path + ".tex") unless FileTest.exists?(file_path + ".tex")
convert_tex_to_pdf(file_path + ".tex")
send_export(file_name + ".pdf", file_path + ".pdf")
end
def export_tex
file_name = "#{web.address}-tex-#{web.revised_on.strftime("%Y-%m-%d-%H-%M")}.tex"
file_path = EXPORT_DIRECTORY + file_name
export_web_to_tex(file_path) unless FileTest.exists?(file_path)
send_export(file_name, file_path)
end
def update_web
redirect_show("HomePage") unless wiki.authenticate(@params["system_password"])
wiki.update_web(
web.address, @params["address"], @params["name"],
@params["markup"].intern,
@params["color"], @params["additional_style"],
@params["safe_mode"] ? true : false,
@params["password"].empty? ? nil : @params["password"],
@params["published"] ? true : false,
@params["brackets_only"] ? true : false,
@params["count_pages"] ? true : false
)
redirect_show("HomePage", @params["address"])
end
def remove_orphaned_pages
if wiki.authenticate(@params["system_password"])
wiki.remove_orphaned_pages(web_address)
redirect_action "list/"
else
redirect_show "HomePage"
end
end
def todo #{{{
parse_category
set_menu_pages
@pages_by_name = @pages_in_category.by_name
@todo_items = Hash.new { Array.new }
@bliki_todo_items = Hash.new { Array.new }
@pages_by_name.each do |page|
if page.content =~ Todo.pattern
# Page has todo items. Get the rendered version (marked-up and with links):
content = page.revisions.last.display_content
@todo_items[page] = content.scan /TODO:<\/strong> (.*?)<\/span>/
end
end
@todo_items = @todo_items.sort_by { |page, items| page.name }
web.bliki.each do |pname, entry|
if entry.content =~ Todo.pattern
# Entry has todo items. Get the rendered version (marked-up and with links):
content = entry.revisions.last.display_content
@bliki_todo_items[entry] = content.scan /TODO:<\/strong> (.*?)<\/span>/
end
end
@bliki_todo_items = @bliki_todo_items.sort_by { |entry, items| entry.name }
end #}}}
def set_menu_pages #{{{
parse_category
@all_pages = web.select { true }
@menu_pages = case web.menu_type
when 'all' then @all_pages.by_name
when 'recent' then @all_pages.by_last_visited
when 'viewed' then @all_pages.by_most_viewed
when 'revised' then @all_pages.by_revision
when 'user' then @menu_content = web.rendered_menu; nil
when 'category' then web.select { |page| page.in_category?(web.menu_category) }
when 'linkers'
web.select { |page|
page.wiki_words.size > 0
}.sort_by { |page| page.name }
end
if web.menu_limit
@menu_pages = @menu_pages[0..web.menu_limit]
end
end #}}}
def bliki #{{{
set_menu_pages
@entries = web.bliki_entries_by_date
unless @req.query['authorname'].nil? || @req.query['authorname'] == 'noselect'
@entries = @entries.select { |page|
page.authors.include?(@req.query['authorname'])
}
end
unless @req.query['regexp'].nil?
@entries = @entries.select { |page|
page.content =~ /#{@req.query['regexp']}/i
}
end
@color = web.color
@authors = web.authors
end #}}}
def mind #{{{
parse_category
set_menu_pages
@prog = @req.query['draw_type'] || 'neato'
@graph_type = @req.query['graph_type'] || 'normal'
missing = @pages_in_category.wanted_pages if @req.query['missing']
show_authors = @req.query['show_authors'] == 'on'
@pngFile = @mapFile = nil
case @graph_type
when 'normal' then @pngFile, @mapFile = web.create_mind_map(@prog, missing, show_authors)
when 'author' then @pngFile, @mapFile = web.create_author_graph(@prog)
when 'category' then @pngFile, @mapFile = web.create_category_graph(@prog, show_authors)
end
end #}}}
def edit_menu #{{{
@menu_type = web.menu_type
@menu_content = web.menu_content
@list_limit = web.menu_limit
@list_limit += 1 if @list_limit >= -1
end #}}}
def save_menu #{{{
unless @req.query['action'] == 'Cancel Update'
type = @req.query['type']
content = @req.query['content']
category = @req.query['category']
limit = @req.query['limit'].to_i rescue nil
limit = 20 unless limit
limit -= 1 if limit >= 0
# need to go through the WikiService to persist the command:
wiki.save_menu_pref web, type, limit, content, category
end
if web_address
redirect_show "HomePage"
elsif wiki.webs.length == 1
redirect_show "HomePage", wiki.webs.values.first.address
else
redirect_path "/web_list/"
end
end #}}}
# Within a single page --------------------------------------------------------
def show
set_menu_pages
if @page = wiki.read_page(web_address, page_name)
unless page_name == 'HomePage'
# HomePage should not be in the menu as there's a link at the top.
@page.last_visited = Time.now
@page.viewed += 1
end
begin
render_action "page"
rescue => e
$stderr << e.backtrace.join("\n")
redirect_action "edit/#{CGI.escape(page_name)}?msg=#{CGI.escape(e.message)}"
end
else
redirect_action "new/#{CGI.escape(page_name)}"
end
end
def published
if web.published then @page = wiki.read_page(web_address, page_name || "HomePage") else redirect_show("HomePage") end
end
def print
@page = wiki.read_page(web_address, page_name)
end
def tex
@page = wiki.read_page(web_address, page_name)
@tex_content = RedClothForTex.new(@page.content).to_tex
end
def pdf
page = wiki.read_page(web_address, page_name)
safe_page_name = page.name.gsub(/\W/, "")
file_name = "#{safe_page_name}-#{web.address}-#{page.created_at.strftime("%Y-%m-%d-%H-%M")}"
file_path = EXPORT_DIRECTORY + file_name
export_page_to_tex(file_path + ".tex") unless FileTest.exists?(file_path + ".tex")
convert_tex_to_pdf(file_path + ".tex")
send_export(file_name + ".pdf", file_path + ".pdf")
end
def new
@page_name, @author = page_name, default_author
end
def edit
@page = wiki.read_page(web_address, page_name)
if !@page.locked?(Time.now) || @params["break_lock"]
@page.lock(Time.now, default_author)
@author = default_author
render
else
render "wiki/locked"
end
end
def cancel_edit
@page = wiki.read_page(web_address, page_name)
@page.unlock
redirect_show
end
def save
if web.pages[page_name]
page = wiki.revise_page(
web_address, page_name, @params["content"], Time.now,
Author.new(@params["author"], remote_ip)
)
page.unlock
else
page = wiki.write_page(
web_address, page_name, @params["content"], Time.now,
Author.new(@params["author"], remote_ip)
)
end
write_cookie("author", @params["author"], true)
redirect_show(page_name)
end
def revision
@page = wiki.read_page(web_address, page_name)
@revision = @page.revisions[@params["rev"].to_i]
end
def rollback
@page = wiki.read_page(web_address, page_name)
wiki.rollback_page(web_address, page_name, @params["rev"].to_i, Time.now, remote_ip)
redirect_show
end
# Bliki ----------------------------------------------------------------------
def bliki_delete
wiki.delete_bliki_entry(web_address, page_name)
redirect_bliki("")
end
def bliki_edit
@page = wiki.read_bliki_entry(web_address, page_name)
if !@page.locked?(Time.now) || @params["break_lock"]
@page.lock(Time.now, default_author)
@author = default_author
render
else
redirect_path "#{web_address}/locked"
end
end
def cancel_bliki_edit
@page = wiki.read_bliki_entry(web_address, page_name)
@page.unlock if @page
redirect_bliki(@page? @page.name : "")
end
def bliki_save
pname = page_name || @params["pagename"]
if web.bliki[pname]
page = wiki.revise_bliki_entry(web_address, pname, @params["content"], Time.now, @params["author"])
page.unlock
else
page = wiki.write_bliki_entry(web_address, pname, @params["content"], Time.now, @params["author"])
end
write_cookie("author", @params["author"])
redirect_bliki('')
end
def bliki_revision
@page = wiki.read_bliki_entry(web_address, page_name || @params['pagename'])
@revision = @page.revisions[@params["rev"].to_i] || @page.revisions.last
end
def rollback_bliki
@page = wiki.read_bliki_entry(web_address, page_name)
wiki.rollback_bliki_entry(web_address, page_name, @params["rev"].to_i, Time.now)
redirect_bliki
end
# ----------------------------------------------------------------------------
protected
def before_action
if in_a_web? && !authorized?(web_address) && !%w( login authenticate published ).include?(action_name)
redirect_action("login")
return false
elsif in_a_web?
@web, @page_name, @action_name = web, page_name, action_name
end
end
def action_name
if in_a_web?
request_path[1]
elsif action_methods.include?(request_path[0])
request_path[0]
else
"index"
end
end
def redirect_show(page = @page.name, web = web_address)
redirect_path "/#{web}/show/#{CGI.escape(page)}"
end
def redirect_bliki(page = @page.name, web = web_address)
redirect_path "/#{web}/bliki/#{page}"
end
def redirect_action(action, web = web_address)
redirect_path "/#{web}/#{action}"
end
def link_to_bliki(entry, web = web_address) #{{{
"#{entry.name}"
end #}}}
private
def wiki
WikiService.instance
end
def web
wiki.webs[web_address]
end
def in_a_web?
request_path.length > 1
end
def web_address
request_path[0]
end
def page_name
CGI.unescape(request_path[2]) if request_path[2]
end
def authorized?(web_address)
(web && web.password.nil?) ||
(read_cookie(web_address) && read_cookie(web_address) == web.password) ||
password_check(@params["password"])
end
def default_author
read_cookie("author") || "AnonymousCoward"
end
def password_check(password)
web && @params["password"] == web.password && write_cookie(web_address, @params["password"])
end
def export_pages_to_zip_file(zip_file_path)
Zip::ZipOutputStream.open(zip_file_path) do |zos|
web.select.by_name.each do |@page|
zos.put_next_entry(@page.name + ".html")
zos.puts(template_engine("print").result(binding))
end
zos.put_next_entry("index.html")
zos.puts('')
end
end
def export_markup_to_zip_file(zip_file_path)
Zip::ZipOutputStream.open(zip_file_path) do |zos|
web.select.by_name.each do |page|
zos.put_next_entry(page.name + ".#{web.markup}")
zos.puts(page.content)
end
end
end
def export_web_to_tex(file_path)
@web_name = web.name
@tex_content = table_of_contents(web.pages["HomePage"].content.dup, render_tex_web)
File.open(file_path, "w") { |f| f.write(template_engine("tex_web").result(binding)) }
end
def render_tex_web
web.select.by_name.inject({}) do |tex_web, page|
tex_web[page.name] = RedClothForTex.new(page.content).to_tex
tex_web
end
end
def export_page_to_tex(file_path)
tex
File.open(file_path, "w") { |f| f.write(template_engine("tex").result(binding)) }
end
def convert_tex_to_pdf(tex_path)
`cd #{File.dirname(tex_path)}; pdflatex --interaction=scrollmode '#{File.basename(tex_path)}'`
end
def truncate(text, length = 30, truncate_string = "...")
if text.length > length then text[0..(length - 3)] + truncate_string else text end
end
def render_markup_help
sub_template "#{web.markup}_help"
end
def send_export(file_name, file_path, content_type = "application/zip")
@res["Content-Type"] = content_type
@res["Content-Disposition"] = "attachment; filename=#{file_name}"
@res["Content-Length"] = File.size(file_path)
File.open(file_path, "rb") { |f| @res.body = f.read }
end
def template_engine(template_name)
ERB.new(IO.readlines(action_template_path(template_name)).join)
end
def remote_ip
$stderr << "#{@req.meta_vars['HTTP_X_FORWARDED_FOR']} || #{@req.meta_vars['REMOTE_ADDR']}"
@req.meta_vars["HTTP_X_FORWARDED_FOR"] || @req.meta_vars["REMOTE_ADDR"]
end
end
# jEdit :folding=indent:collapseFolds=2: