app/controllers/wiki.rb in Pimki-1.7.092 vs app/controllers/wiki.rb in Pimki-1.8.092
- old
+ new
@@ -1,943 +1,951 @@
-require "cgi"
-require "redcloth_for_tex"
-
-RenderedTodo = Struct.new( :text, :context, :due_date )
-
-class WikiController < ActionControllerServlet
- EXPORT_DIRECTORY = WikiService.storage_path
-
- def index
- if web_address
- check_external_req_and_redirect web
- elsif !wiki.setup?
- redirect_path "/new_system/"
- elsif wiki.webs.length == 1
- check_external_req_and_redirect wiki.webs.values.first
- else
- wiki.default_web ?
- check_external_req_and_redirect(wiki.webs[wiki.default_web]) :
- redirect_path("/web_list/")
- end
- end
-
- def check_external_req_and_redirect web
- if web.default_to_published and @req.addr[2] != @req.peeraddr[2]
- redirect_action("published/", web.address)
- else
- redirect_show("HomePage", web.address)
- 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
-
- def stop
- redirect_show("HomePage") unless wiki.authenticate(@params["system_password"])
-
- begin
- secs = @params['seconds'].to_i
- raise if secs.zero?
- @logger.warn "Pimki server will stop in #{secs} seconds!"
- WikiService.request_stop
- render_text "Pimki server will stop in #{secs} seconds!"
- Thread.new { sleep secs; Kernel.exit! }
- rescue
- redirect_show("HomePage")
- end
- end
-
- # Within a single web ---------------------------------------------------------
-
- def parse_category
- @categories = web.categories
- @category = @params["category"]
- @pages_in_category = web.select { |page| page.in_category?(@category) }
- @pages_without_category = web.select { |page| page.categories.length == 0 }
- if @category == 'none'
- @pages_in_category = @pages_without_category
- end
- @set_name = ( @categories.include?(@category) ? "category '#{@category}'" : "the web" )
- @category_links = @categories.map do |c|
- (@category == c ? "<span class=\"selected\">[#{c}]</span>" : "<a href=\"?category=#{c}\">#{c}</a>")
- end
- end
-
- def search
- set_menu_pages
- @query = @params["query"]
- search_content = [nil, 'both', 'contents'].include? @params['fields']
- search_names = [nil, 'both', 'names'].include? @params['fields']
-
- case @params['expression']
- when 'regex', nil
- rex = Regexp.new @query, (Regexp::IGNORECASE unless @params['case'])
- @results = if [nil, 'all', 'pages', nil].include? @params['where']
- web.select do |page|
- (search_names and rex.match(page.name)) or (search_content and rex.match(page.content))
- end
- else
- []
- end
- @bliki_results = if [nil, 'all', 'bliki'].include? @params['where']
- web.bliki.values.select do |entry|
- (search_names and rex.match(entry.name)) or (search_content and rex.match(entry.content))
- end
- else
- []
- end
-
- when 'all'
- words = @query.split(/\s/).reject { |w| w.empty? }
- @results = if [nil, 'all', 'pages'].include? @params['where']
- web.select do |page|
- words.all? do |word|
- (search_names and page.name.index(word)) or (search_content and page.content.index(word))
- end
- end
- else
- []
- end
- @bliki_results = if [nil, 'all', 'bliki'].include? @params['where']
- web.bliki.values.select do |entry|
- words.all? do |word|
- (search_names and entry.name.index(word)) or (search_content and entry.content.index(word))
- end
- end
- else
- []
- end
-
- when 'exact'
- @results = if [nil, 'all', 'pages'].include? @params['where']
- web.select do |page|
- (search_names and page.name.index(@query)) or (search_content and page.content.index(@query))
- end
- else
- []
- end
- @bliki_results = if [nil, 'all', 'bliki'].include? @params['where']
- web.bliki.values.select do |entry|
- (search_names and entry.name.index(@query)) or (search_content and entry.content.index(@query))
- end
- else
- []
- end
- end
-
- if !@params['category'].nil? and @params['category'] != 'noselect'
- @selected_categories = parse_multi_select 'category'
- @results.reject! { |page| (page.categories & @selected_categories).empty? }
- @bliki_results.reject! { |page| (page.categories & @selected_categories).empty? }
- end
-
- if !@params['author'].nil? and @params['author'] != 'noselect'
- @selected_authors = parse_multi_select 'author'
- @results.reject! { |page| (page.authors & @selected_authors).empty? }
- @bliki_results.reject! { |page| (page.authors & @selected_authors).empty? }
- end
-
- redirect_show(@results.first.name) if @results.length == 1 && @bliki_results.length == 0
- redirect_path("/#{web_address}/bliki_revision/#{@bliki_results.first.name}?rev=#{@bliki_results.first.revisions.size-1}") if @results.length == 0 && @bliki_results.length == 1
- render_action "search"
- end
-
- def glossary
- set_menu_pages
-
- rex = %r{([A-Z\d]+)\(([\w\s]+)\)}
- scan_results = web.select.map { |page| [page.link, page.content.scan(rex)] }
- scan_results += web.bliki.values.map { |entry| [link_to_bliki(entry), entry.content.scan(rex)] }
- results = Hash.new { Array.new }
- scan_results.each { |page, acronyms| acronyms.each { |ac| results[ac] += [page] } }
- @results = results.map{ |(ac, df), pg|[[ac,df], pg.uniq] }.sort_by{ |(ac, df), pg| ac }
-
- acronyms = @results.map { |(ac, df), pg| ac }
- rex = %r{(#{acronyms.join('|')})[^\(]}
- results = web.select.map { |page| [page.link, page.content.scan(rex)] }
- results += web.bliki.values.map { |entry| [link_to_bliki(entry), entry.content.scan(rex)] }
- @undefined_on = Hash.new { Array.new }
- results.each { |page, acronyms| acronyms.each { |ac| @undefined_on[ac[0]] += [page] } }
- @undefined_on = @undefined_on.inject({}) { |hsh, (k, v)| hsh[k] = v.uniq; hsh }
- end
-
- def authors
- set_menu_pages
- @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 = @rss_bliki_only ? [] : web.select.by_revision.first(15)
- @bliki_entries = web.bliki_entries_by_date
- @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 rss_bliki_only
- @rss_bliki_only = true
- rss_with_content
- end
-
- def rss_todo_items
- todo
- @display_todo = true
- rss_with_content
- end
-
- def feeds
- set_menu_pages
- 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
-
- if @req.query['Action']
- # redirect_action 'list/' if web.check_pass_on_edit and not password_check(@params['password'])
-
- case @req.query['Action']
- when 'Delete' # Handle page deletion
- wiki.delete_page(web_address, @req.query['del_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['ren_sel_page_name'], @req.query['newpage'])
- redirect_action "list/"
- end
- end
-
- end
-
- def export
- set_menu_pages
- end
-
- def export_html
- file_name = "#{web.address}-html-#{web.revised_on.strftime("%Y-%m-%d-%H-%M")}.zip"
- file_path = File.join 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 = File.join 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 = File.join 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 = File.join EXPORT_DIRECTORY, file_name
-
- export_web_to_tex(file_path) unless FileTest.exists?(file_path)
- send_export(file_name, file_path)
- end
-
- def edit_web #{{{
- parse_category
- set_mm_options
- @snapshot_interval = WikiService.snapshot_interval_hours
- end #}}}
-
- def update_web
- redirect_show("HomePage") unless wiki.authenticate(@params["system_password"])
-
- set_mm_options
-
- 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['default_to_published'] ? true : false,
- @params["brackets_only"] ? true : false,
- @params["count_pages"] ? true : false,
- @params['mind_map_size'],
- @params['symbols_map'],
- @params['links_map'],
- @params['snapshots_interval'],
- @params['enable_dclick_edit'],
- @params['enable_menu'],
- @params['check_pass_on_edit'] == 'each_edit',
- @prog, @graph_type, @missing, @show_authors, @show_leaves, @selected_categories
- )
-
- redirect_show("HomePage", @params["address"])
- end
-
- def administrate
- @logger.info "Taking administrative action: #{@params['action']}"
- redirect_show 'HomePage' unless wiki.authenticate(@params['system_password'])
- case @params['action']
- when 'Delete Orphan Pages'
- wiki.remove_orphaned_pages(web_address)
-
- when 'Clear Render Cache'
- clear_render_cache true
-
- when 'Force Data Snapshot'
- WikiService.take_snapshot
-
- when 'Clean Storage'
- WikiService.clean_old_snapshots
-
- when 'Make This Web Default'
- wiki.default_web = web_address
-
- when 'Remove This Web'
- wiki.webs.delete web_address
- redirect_path '/'
-
- end
- @message = 'Operation succeeded'
- redirect_action 'edit_web/'
- end
-
- FAR_FUTURE = Date.new(4000,1,1).freeze
- TODO_RE = %r{<todo-tag context='(.*?)' due_date='(.*?)'><span class="todo"><strong>TODO(?:[^:]*)?:</strong> (.*?)</span></todo-tag>}
-
- def todo #{{{
- parse_category
- set_menu_pages
-
- @context = @params['context']
- @sort_order = @params['sort_order']
-
- # the clear_render_cache hack to make sure we don't have old-style rendered
- # todos is no longer needed - can go thru the edit web to explicitely clear the cache.
- @todo_items = analyse_rendered_todo_items @pages_in_category.by_name
- @bliki_todo_items = analyse_rendered_todo_items web.bliki.values
-
- @context_links = @todo_items.clone.update(@bliki_todo_items).map { |page, items|
- # 'items' contain the full 'todo' info
- items.map { |item| item.context }
- }.flatten.compact.uniq.reject { |c| c.nil? || c.empty? }.map { |context|
- @context == context ?
- "[<span class='selected'>#{context}</span>]" :
- "<a href='?context=#{context}#{"&sort_order=#{@sort_order}" if @sort_order}'>#{context}</a>"
- }
-
- @todo_items = sort_and_filter_todo_items @todo_items, @sort_order, @context
- @bliki_todo_items = sort_and_filter_todo_items @bliki_todo_items, @sort_order, @context
-
- end #}}}
-
- def analyse_rendered_todo_items pages
- items = Hash.new { Array.new }
- pages.each do |page|
- if page.has_todos?
- # Page has todo items. Get the rendered version (marked-up and with links):
- # I specifically don't use the todo chunkss because I want the fully marked-up
- # text of the item.
- content = page.revisions.last.display_content
- items[page] = content.scan(TODO_RE).map { |match|
- RenderedTodo.new match[2], (match[0].empty? ? [] : match[0].split(',') ), (Date.parse(match[1]) rescue FAR_FUTURE)
- }
- end
- end
- items
- end
-
- def sort_and_filter_todo_items items, sort_order, context
- case sort_order
- when 'due_date'
- result = items.map { |page, todos|
- # sort the to items themselves
- [page, todos.sort_by { |i| i.due_date } ]
- }.sort_by { |page, todos|
- # sort the pages by the one with the most urgent todo
- todos.map{ |i| i.due_date }.min
- }
-
- else # default = sort by page name
- result = items.sort_by { |page, items| page.name }
-
- end
-
- if context
- # filter the items to those that are in context
- result = result.map { |page, items|
- [ page, items.select { |item| item.context.include? context } ]
- }.select { |page, items| not items.empty? }
- end
- result
- end
-
- def get_todo_display_style due_date
- # default is the muted 'darkred', to prevent to many bright red
- # items on one page: (See also chunks/todo.rb)
- (due_date <=> Date.today) > -1 ? "todoFuture" : "todo"
- end
-
- def clear_render_cache dont_redirect=false
- web.refresh_revisions
- redirect_path "/#{web_address}/edit_web/" unless dont_redirect
- end
-
- def set_menu_pages published = false #{{{
- 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 'category' then web.select { |page| page.in_category?(web.menu_category) }
- when 'user'
- @menu_content = if Page === web.menu_content
- web.menu_content.revisions.last.display_content
- else
- web.menu_content
- end
- @menu_content = @menu_content.gsub('/show/', '/published/').gsub( %r{<a href="../published/.*?">\?</a>}, '') if published
- nil
- when 'linkers'
- web.select { |page|
- page.wiki_words.size > 0
- }.sort_by { |page| page.name }
- end
- if web.menu_limit && @menu_pages
- @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
- set_mm_options
-
- @pngFile = @mapFile = nil
- case @graph_type
- when 'normal'
- @pngFile, @mapFile = web.create_mind_map(@prog, @missing,
- @show_authors, @show_leaves, @selected_categories, @mm_size)
-
- when 'author'
- @pngFile, @mapFile = web.create_author_graph(@prog, @selected_categories, @mm_size)
-
- when 'category'
- @pngFile, @mapFile = web.create_category_graph(@prog,
- @show_authors, @selected_categories, @mm_size)
- end
- end #}}}
-
- def set_mm_options #{{{
- if @req.query.empty?
- @prog = web.mm_prog
- @graph_type = web.mm_graph_type
- @missing = @pages_in_category.wanted_pages if web.mm_show_missing
- @show_authors = web.mm_show_authors
- @show_leaves = web.mm_show_leaves
- @selected_categories = web.mm_selected_categories
- @mm_size = web.mind_map_size
- else
- @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'
- @show_leaves = @req.query.empty? || @req.query['show_leaves'] == 'on'
-
- @selected_categories = parse_multi_select 'selected_categs'
- @selected_categories = [] if @selected_categories.include? 'all'
- @mm_size = @params['mind_map_size'] || web.mind_map_size
- end
- end #}}}
-
- def parse_multi_select field #{{{
- if @req.body
- @req.body.split('&').map { |pair|
- pair.split('=') }.select { |k,v|
- k == field }.map { |k,v| v }
- else
- []
- 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
- @author = default_author
- end #}}}
-
- def save_menu #{{{
- redirect_show("HomePage") unless wiki.authenticate(@params["system_password"])
-
- unless @req.query['action'] == 'Cancel Update'
- type = @req.query['type']
- content = @req.query['content']
- category = @req.query['category']
- author = @req.query['author']
-
- 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_address, type, limit, content, category, Author.new(author, remote_ip))
- end
-
- redirect_action 'edit_web/' # go back to web options page
- end #}}}
-
- def get_map_img
- file_name = "map.png"
- file_path = File.join WikiService.storage_path, file_name
- send_export(file_name, file_path, "image/png")
- end
-
- def adv_search
- parse_category
- set_menu_pages
- 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
- if page_name
- redirect_action "new/#{CGI.escape(page_name)}"
- else
- redirect_show "HomePage"
- end
- end
- end
-
- def published
- set_menu_pages true
- 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 = File.join 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
- # redirect_show("HomePage") if web.check_pass_on_edit and not password_check(@params['password'])
- @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.check_pass_on_edit and not password_check(@params['password'])
- # wiki.read_page(web_address, page_name).unlock if web.pages[page_name]
- # redirect_show("HomePage")
- # end
-
- if web.pages[page_name]
- page = wiki.revise_page(
- web_address, page_name, @params["content"], Time.now,
- Author.new(@params["author"], remote_ip), @params['edit_type']
- )
-
- 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
- redirect_show 'HomePage' if page_name.nil?
- set_menu_pages
- @page = wiki.read_page(web_address, page_name)
- @revision = @page.revisions[@params["rev"].to_i]
- end
-
- def rollback
- # redirect_show("HomePage") if web.check_pass_on_edit and not password_check(@params['password'])
-
- @page = wiki.read_page(web_address, page_name)
- @revision = @page.revisions[@params["rev"].to_i]
- end
-
- # Bliki ----------------------------------------------------------------------
-
- def bliki_delete
- # redirect_bliki if web.check_pass_on_edit and not password_check(@params['password'])
-
- wiki.delete_bliki_entry(web_address, page_name)
- redirect_bliki
- end
-
- def bliki_edit
- # redirect_bliki if web.check_pass_on_edit and not password_check(@params['password'])
-
- @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
- @bliki_entry = true
- render "wiki/locked"
- end
- end
-
- def cancel_bliki_edit
- @page = wiki.read_bliki_entry(web_address, page_name)
- @page.unlock if @page
- redirect_bliki
- end
-
- def bliki_new
- @entry_name = @params['entry_name']
- @author = default_author
- end
-
- def bliki_save
- # redirect_bliki if web.check_pass_on_edit and not password_check(@params['password'])
-
- 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
- parse_category
- set_menu_pages
- @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
- # redirect_bliki if web.check_pass_on_edit and not password_check(@params['password'])
-
- @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
- redirect_path "/#{web_address}/bliki/"
- end
-
- def redirect_action(action, web = web_address)
- redirect_path "/#{web}/#{action}"
- end
-
- def link_to_bliki(entry, web = web_address) #{{{
- "<a class='existingWikiWord' href='/#{web}/bliki_revision/#{entry.name}?rev=#{entry.revisions.size-1}'>#{entry.name}</a>"
- 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.nil? ||
- 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 "pages-metadata.txt"
- web.select.by_name.each do |page|
- zos.puts "#{page.name}: by #{page.author}, created on #{page.pretty_created_at}"
- end
-
- web.select_bliki.by_name.each do |@page|
- zos.put_next_entry("bliki/#{@page.name}.html")
- zos.puts(template_engine("print").result(binding))
- end
-
- zos.put_next_entry "bliki/bliki-metadata.txt"
- web.select_bliki.by_name.each do |page|
- zos.puts "#{page.name}: by #{page.author}, created on #{page.revisions.first.pretty_created_at}"
- end
-
- zos.put_next_entry("index.html")
- zos.puts('<html><head><META HTTP-EQUIV="Refresh" CONTENT="0;URL=HomePage.html"></head></html>')
- 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
-
- zos.put_next_entry "pages-metadata.txt"
- web.select.by_name.each do |page|
- zos.puts "#{page.name}: by #{page.author}, created on #{page.pretty_created_at}"
- end
-
- web.select_bliki.by_name.each do |page|
- zos.put_next_entry("bliki/#{page.name}.#{web.markup}")
- zos.puts(page.content)
- end
-
- zos.put_next_entry "bliki/bliki-metadata.txt"
- web.select_bliki.by_name.each do |page|
- zos.puts "#{page.name}: by #{page.author}, created on #{page.revisions.first.pretty_created_at}"
- 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
- pages = web.select.by_name.inject({}) do |tex_web, page|
- tex_web[page.name] = RedClothForTex.new(page.content).to_tex
- tex_web
- end
-
- bliki_entries = web.select_bliki.by_name.inject({}) do |tex_web, page|
- tex_web["bliki/#{page.name}"] = RedClothForTex.new(page.content).to_tex
- tex_web
- end
-
- pages.update bliki_entries
- 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
- if web
- markup = web.markup
- markup = 'markdown' if markup.to_s =~ /markdown/
- sub_template("#{markup}_help")
- else
- ''
- end
- 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
-
+require "cgi"
+require "redcloth_for_tex"
+
+RenderedTodo = Struct.new( :text, :context, :due_date )
+
+class WikiController < ActionControllerServlet
+ EXPORT_DIRECTORY = WikiService.storage_path
+
+ def index
+ if web_address
+ check_external_req_and_redirect web
+ elsif !wiki.setup?
+ redirect_path "/new_system/"
+ elsif wiki.webs.length == 1
+ check_external_req_and_redirect wiki.webs.values.first
+ else
+ wiki.default_web ?
+ check_external_req_and_redirect(wiki.webs[wiki.default_web]) :
+ redirect_path("/web_list/")
+ end
+ end
+
+ def check_external_req_and_redirect web
+ if web.default_to_published and @req.addr[2] != @req.peeraddr[2]
+ redirect_action("published/", web.address)
+ else
+ redirect_show("HomePage", web.address)
+ 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
+
+ def stop
+ redirect_show("HomePage") unless wiki.authenticate(@params["system_password"])
+
+ begin
+ secs = @params['seconds'].to_i
+ raise if secs.zero?
+ @logger.warn "Pimki server will stop in #{secs} seconds!"
+ WikiService.request_stop
+ render_text "Pimki server will stop in #{secs} seconds!"
+ Thread.new { sleep secs; Kernel.exit! }
+ rescue
+ redirect_show("HomePage")
+ end
+ end
+
+ # Within a single web ---------------------------------------------------------
+
+ def parse_category
+ @categories = web.categories
+ @category = @params["category"]
+ @pages_in_category = web.select { |page| page.in_category?(@category) }
+ @pages_without_category = web.select { |page| page.categories.length == 0 }
+ if @category == 'none'
+ @pages_in_category = @pages_without_category
+ end
+ @set_name = ( @categories.include?(@category) ? "category '#{@category}'" : "the web" )
+ @category_links = @categories.map do |c|
+ (@category == c ? "<span class=\"selected\">[#{c}]</span>" : "<a href=\"?category=#{c}\">#{c}</a>")
+ end
+ end
+
+ def search
+ set_menu_pages
+ @query = @params["query"]
+ search_content = [nil, 'both', 'contents'].include? @params['fields']
+ search_names = [nil, 'both', 'names'].include? @params['fields']
+
+ case @params['expression']
+ when 'regex', nil
+ rex = Regexp.new @query, (Regexp::IGNORECASE unless @params['case'])
+ @results = if [nil, 'all', 'pages', nil].include? @params['where']
+ web.select do |page|
+ (search_names and rex.match(page.name)) or (search_content and rex.match(page.content))
+ end
+ else
+ []
+ end
+ @bliki_results = if [nil, 'all', 'bliki'].include? @params['where']
+ web.bliki.values.select do |entry|
+ (search_names and rex.match(entry.name)) or (search_content and rex.match(entry.content))
+ end
+ else
+ []
+ end
+
+ when 'all'
+ words = @query.split(/\s/).reject { |w| w.empty? }
+ @results = if [nil, 'all', 'pages'].include? @params['where']
+ web.select do |page|
+ words.all? do |word|
+ (search_names and page.name.index(word)) or (search_content and page.content.index(word))
+ end
+ end
+ else
+ []
+ end
+ @bliki_results = if [nil, 'all', 'bliki'].include? @params['where']
+ web.bliki.values.select do |entry|
+ words.all? do |word|
+ (search_names and entry.name.index(word)) or (search_content and entry.content.index(word))
+ end
+ end
+ else
+ []
+ end
+
+ when 'exact'
+ @results = if [nil, 'all', 'pages'].include? @params['where']
+ web.select do |page|
+ (search_names and page.name.index(@query)) or (search_content and page.content.index(@query))
+ end
+ else
+ []
+ end
+ @bliki_results = if [nil, 'all', 'bliki'].include? @params['where']
+ web.bliki.values.select do |entry|
+ (search_names and entry.name.index(@query)) or (search_content and entry.content.index(@query))
+ end
+ else
+ []
+ end
+ end
+
+ if !@params['category'].nil? and @params['category'] != 'noselect'
+ @selected_categories = parse_multi_select 'category'
+ @results.reject! { |page| (page.categories & @selected_categories).empty? }
+ @bliki_results.reject! { |page| (page.categories & @selected_categories).empty? }
+ end
+
+ if !@params['author'].nil? and @params['author'] != 'noselect'
+ @selected_authors = parse_multi_select 'author'
+ @results.reject! { |page| (page.authors & @selected_authors).empty? }
+ @bliki_results.reject! { |page| (page.authors & @selected_authors).empty? }
+ end
+
+ redirect_show(@results.first.name) if @results.length == 1 && @bliki_results.length == 0
+ redirect_path("/#{web_address}/bliki_revision/#{@bliki_results.first.name}?rev=#{@bliki_results.first.revisions.size-1}") if @results.length == 0 && @bliki_results.length == 1
+ render_action "search"
+ end
+
+ def glossary
+ set_menu_pages
+
+ rex = %r{([A-Z\d]+)\(([\w\s]+)\)}
+ scan_results = web.select.map { |page| [page.link, page.content.scan(rex)] }
+ scan_results += web.bliki.values.map { |entry| [link_to_bliki(entry), entry.content.scan(rex)] }
+ results = Hash.new { Array.new }
+ scan_results.each { |page, acronyms| acronyms.each { |ac| results[ac] += [page] } }
+ @results = results.map{ |(ac, df), pg|[[ac,df], pg.uniq] }.sort_by{ |(ac, df), pg| ac }
+
+ acronyms = @results.map { |(ac, df), pg| ac }
+ rex = %r{(#{acronyms.join('|')})[^\(]}
+ results = web.select.map { |page| [page.link, page.content.scan(rex)] }
+ results += web.bliki.values.map { |entry| [link_to_bliki(entry), entry.content.scan(rex)] }
+ @undefined_on = Hash.new { Array.new }
+ results.each { |page, acronyms| acronyms.each { |ac| @undefined_on[ac[0]] += [page] } }
+ @undefined_on = @undefined_on.inject({}) { |hsh, (k, v)| hsh[k] = v.uniq; hsh }
+ end
+
+ def authors
+ set_menu_pages
+ @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 = @rss_bliki_only ? [] : web.select.by_revision.first(15)
+ @bliki_entries = web.bliki_entries_by_date
+ @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 rss_bliki_only
+ @rss_bliki_only = true
+ rss_with_content
+ end
+
+ def rss_todo_items
+ todo
+ @display_todo = true
+ rss_with_content
+ end
+
+ def feeds
+ set_menu_pages
+ 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
+
+ if @req.query['Action']
+ # redirect_action 'list/' if web.check_pass_on_edit and not password_check(@params['password'])
+
+ case @req.query['Action']
+ when 'Delete' # Handle page deletion
+ wiki.delete_page(web_address, @req.query['del_sel_page_name'])
+ clear_render_cache true
+ 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['ren_sel_page_name'], @req.query['ren_newpage'])
+ clear_render_cache true
+ redirect_action "list/"
+ end
+ end
+
+ end
+
+ def export
+ set_menu_pages
+ end
+
+ def export_html
+ file_name = "#{web.address}-html-#{web.revised_on.strftime("%Y-%m-%d-%H-%M")}.zip"
+ file_path = File.join 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 = File.join 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 = File.join 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 = File.join EXPORT_DIRECTORY, file_name
+
+ export_web_to_tex(file_path) unless FileTest.exists?(file_path)
+ send_export(file_name, file_path)
+ end
+
+ def edit_web #{{{
+ parse_category
+ set_mm_options
+ @snapshot_interval = WikiService.snapshot_interval_hours
+ end #}}}
+
+ def update_web
+ redirect_show("HomePage") unless wiki.authenticate(@params["system_password"])
+
+ parse_category
+ set_mm_options
+
+ 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['default_to_published'] ? true : false,
+ @params["brackets_only"] ? true : false,
+ @params["count_pages"] ? true : false,
+ @params['mind_map_size'],
+ @params['symbols_map'],
+ @params['links_map'],
+ @params['snapshots_interval'],
+ @params['enable_dclick_edit'] ? true : false,
+ @params['enable_menu'] ? true : false,
+ @params['check_pass_on_edit'] == 'each_edit',
+ @prog, @graph_type, @missing, @show_authors, @show_leaves, @selected_categories
+ )
+
+ redirect_show("HomePage", @params["address"])
+ end
+
+ def administrate
+ @logger.info "Taking administrative action: #{@params['action']}"
+ redirect_show 'HomePage' unless wiki.authenticate(@params['system_password'])
+ case @params['action']
+ when 'Delete Orphan Pages'
+ wiki.remove_orphaned_pages(web_address)
+
+ when 'Clear Render Cache'
+ clear_render_cache true
+
+ when 'Force Data Snapshot'
+ WikiService.take_snapshot
+
+ when 'Clean Storage'
+ WikiService.clean_old_snapshots
+
+ when 'Make This Web Default'
+ wiki.default_web = web_address
+
+ when 'Remove This Web'
+ wiki.webs.delete web_address
+ redirect_path '/'
+
+ end
+ @message = 'Operation succeeded'
+ redirect_action 'edit_web/'
+ end
+
+ FAR_FUTURE = Date.new(4000,1,1).freeze
+ TODO_RE = %r{<todo-tag context='(.*?)' due_date='(.*?)'><span class="todo"><strong>TODO(?:[^:]*)?:</strong> (.*?)</span></todo-tag>}
+
+ def todo #{{{
+ parse_category
+ set_menu_pages
+
+ @context = @params['context']
+ @sort_order = @params['sort_order']
+
+ # the clear_render_cache hack to make sure we don't have old-style rendered
+ # todos is no longer needed - can go thru the edit web to explicitely clear the cache.
+ @todo_items = analyse_rendered_todo_items @pages_in_category.by_name
+ @bliki_todo_items = analyse_rendered_todo_items web.bliki.values
+
+ @context_links = @todo_items.clone.update(@bliki_todo_items).map { |page, items|
+ # 'items' contain the full 'todo' info
+ items.map { |item| item.context }
+ }.flatten.compact.uniq.reject { |c| c.nil? || c.empty? }.map { |context|
+ @context == context ?
+ "[<span class='selected'>#{context}</span>]" :
+ "<a href='?context=#{context}#{"&sort_order=#{@sort_order}" if @sort_order}'>#{context}</a>"
+ }
+
+ @todo_items = sort_and_filter_todo_items @todo_items, @sort_order, @context
+ @bliki_todo_items = sort_and_filter_todo_items @bliki_todo_items, @sort_order, @context
+
+ end #}}}
+
+ def analyse_rendered_todo_items pages
+ items = Hash.new { Array.new }
+ pages.each do |page|
+ if page.has_todos?
+ # Page has todo items. Get the rendered version (marked-up and with links):
+ # I specifically don't use the todo chunkss because I want the fully marked-up
+ # text of the item.
+ content = page.revisions.last.display_content
+ items[page] = content.scan(TODO_RE).map { |match|
+ RenderedTodo.new match[2], (match[0].empty? ? [] : match[0].split(',') ), (Date.parse(match[1]) rescue FAR_FUTURE)
+ }
+ end
+ end
+ items
+ end
+
+ def sort_and_filter_todo_items items, sort_order, context
+ case sort_order
+ when 'due_date'
+ result = items.map { |page, todos|
+ # sort the to items themselves
+ [page, todos.sort_by { |i| i.due_date } ]
+ }.sort_by { |page, todos|
+ # sort the pages by the one with the most urgent todo
+ todos.map{ |i| i.due_date }.min
+ }
+
+ else # default = sort by page name
+ result = items.sort_by { |page, items| page.name }
+
+ end
+
+ if context
+ # filter the items to those that are in context
+ result = result.map { |page, items|
+ [ page, items.select { |item| item.context.include? context } ]
+ }.select { |page, items| not items.empty? }
+ end
+ result
+ end
+
+ def get_todo_display_style due_date
+ # default is the muted 'darkred', to prevent to many bright red
+ # items on one page: (See also chunks/todo.rb)
+ (due_date <=> Date.today) > -1 ? "todoFuture" : "todo"
+ end
+
+ def clear_render_cache dont_redirect=false
+ web.refresh_revisions
+ redirect_path "/#{web_address}/edit_web/" unless dont_redirect
+ end
+
+ def set_menu_pages published = false #{{{
+ 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 'category' then web.select { |page| page.in_category?(web.menu_category) }
+ when 'user'
+ @menu_content = if Page === web.menu_content
+ web.menu_content.revisions.last.display_content
+ else
+ web.menu_content
+ end
+ @menu_content = @menu_content.gsub('/show/', '/published/').gsub( %r{<a href="../published/.*?">\?</a>}, '') if published
+ nil
+ when 'linkers'
+ web.select { |page|
+ page.wiki_words.size > 0
+ }.sort_by { |page| page.name }
+ end
+ if web.menu_limit && @menu_pages
+ @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
+ set_mm_options
+
+ @pngFile = @mapFile = nil
+ case @graph_type
+ when 'normal'
+ @pngFile, @mapFile = web.create_mind_map(@prog, @missing,
+ @show_authors, @show_leaves, @selected_categories, @mm_size)
+
+ when 'author'
+ @pngFile, @mapFile = web.create_author_graph(@prog, @selected_categories, @mm_size)
+
+ when 'category'
+ @pngFile, @mapFile = web.create_category_graph(@prog,
+ @show_authors, @selected_categories, @mm_size)
+ end
+ end #}}}
+
+ def set_mm_options #{{{
+ if @req.query.empty?
+ @prog = web.mm_prog
+ @graph_type = web.mm_graph_type
+ @missing = @pages_in_category.wanted_pages if web.mm_show_missing
+ @show_authors = web.mm_show_authors
+ @show_leaves = web.mm_show_leaves
+ @selected_categories = web.mm_selected_categories
+ @mm_size = web.mind_map_size
+ else
+ @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'
+ @show_leaves = @req.query.empty? || @req.query['show_leaves'] == 'on'
+
+ @selected_categories = parse_multi_select 'selected_categs'
+ @selected_categories = [] if @selected_categories.include? 'all'
+ @mm_size = @params['mind_map_size'] || web.mind_map_size
+ end
+ end #}}}
+
+ def parse_multi_select field #{{{
+ if @req.body
+ @req.body.split('&').map { |pair|
+ pair.split('=') }.select { |k,v|
+ k == field }.map { |k,v| v }
+ else
+ []
+ 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
+ @author = default_author
+ end #}}}
+
+ def save_menu #{{{
+ redirect_show("HomePage") unless wiki.authenticate(@params["system_password"])
+
+ unless @req.query['action'] == 'Cancel Update'
+ type = @req.query['type']
+ content = @req.query['content']
+ sel_category = @req.query['sel_category']
+ author = @req.query['author']
+
+ 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_address, type, limit, content, sel_category, Author.new(author, remote_ip))
+ end
+
+ redirect_action 'edit_web/' # go back to web options page
+ end #}}}
+
+ def get_map_img
+ file_name = "map.png"
+ file_path = File.join WikiService.storage_path, file_name
+ send_export(file_name, file_path, "image/png")
+ end
+
+ def adv_search
+ parse_category
+ set_menu_pages
+ 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
+ if page_name
+ redirect_action "new/#{CGI.escape(page_name)}"
+ else
+ redirect_show "HomePage"
+ end
+ end
+ end
+
+ def published
+ set_menu_pages true
+ 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 = File.join 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
+ # redirect_show("HomePage") if web.check_pass_on_edit and not password_check(@params['password'])
+ @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.check_pass_on_edit and not password_check(@params['password'])
+ # wiki.read_page(web_address, page_name).unlock if web.pages[page_name]
+ # redirect_show("HomePage")
+ # end
+
+ if web.pages[page_name]
+ page = wiki.revise_page(
+ web_address, page_name, @params["content"], Time.now,
+ Author.new(@params["author"], remote_ip), @params['edit_type']
+ )
+
+ 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
+ redirect_show 'HomePage' if page_name.nil?
+ set_menu_pages
+ @page = wiki.read_page(web_address, page_name)
+ @revision = @page.revisions[@params["rev"].to_i]
+ end
+
+ def rollback
+ # redirect_show("HomePage") if web.check_pass_on_edit and not password_check(@params['password'])
+
+ @page = wiki.read_page(web_address, page_name)
+ @revision = @page.revisions[@params["rev"].to_i]
+ end
+
+ # Bliki ----------------------------------------------------------------------
+
+ def bliki_delete
+ # redirect_bliki if web.check_pass_on_edit and not password_check(@params['password'])
+
+ wiki.delete_bliki_entry(web_address, page_name)
+ clear_render_cache true
+ redirect_bliki
+ end
+
+ def bliki_edit
+ # redirect_bliki if web.check_pass_on_edit and not password_check(@params['password'])
+
+ @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
+ @bliki_entry = true
+ render "wiki/locked"
+ end
+ end
+
+ def cancel_bliki_edit
+ @page = wiki.read_bliki_entry(web_address, page_name)
+ @page.unlock if @page
+ redirect_bliki
+ end
+
+ def bliki_new
+ @entry_name = @params['entry_name']
+ @author = default_author
+ end
+
+ def bliki_save
+ # redirect_bliki if web.check_pass_on_edit and not password_check(@params['password'])
+
+ 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
+ parse_category
+ set_menu_pages
+ @page = wiki.read_bliki_entry(web_address, page_name || @params['pagename'])
+ if @page.nil?
+ render_text "Unable to find bliki entry #{page_name || @params['pagename']}"
+ return
+ end
+ @revision = @page.revisions[@params["rev"].to_i] || @page.revisions.last
+ end
+
+ def rollback_bliki
+ # redirect_bliki if web.check_pass_on_edit and not password_check(@params['password'])
+
+ @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
+ redirect_path "/#{web_address}/bliki/"
+ end
+
+ def redirect_action(action, web = web_address)
+ redirect_path "/#{web}/#{action}"
+ end
+
+ def link_to_bliki(entry, web = web_address) #{{{
+ "<a class='existingWikiWord' href='/#{web}/bliki_revision/#{entry.name}?rev=#{entry.revisions.size-1}'>#{entry.name}</a>"
+ 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.nil? ||
+ 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 "pages-metadata.txt"
+ web.select.by_name.each do |page|
+ zos.puts "#{page.name}: by #{page.author}, created on #{page.pretty_created_at}"
+ end
+
+ web.select_bliki.by_name.each do |@page|
+ zos.put_next_entry("bliki/#{@page.name}.html")
+ zos.puts(template_engine("print").result(binding))
+ end
+
+ zos.put_next_entry "bliki/bliki-metadata.txt"
+ web.select_bliki.by_name.each do |page|
+ zos.puts "#{page.name}: by #{page.author}, created on #{page.revisions.first.pretty_created_at}"
+ end
+
+ zos.put_next_entry("index.html")
+ zos.puts('<html><head><META HTTP-EQUIV="Refresh" CONTENT="0;URL=HomePage.html"></head></html>')
+ 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
+
+ zos.put_next_entry "pages-metadata.txt"
+ web.select.by_name.each do |page|
+ zos.puts "#{page.name}: by #{page.author}, created on #{page.pretty_created_at}"
+ end
+
+ web.select_bliki.by_name.each do |page|
+ zos.put_next_entry("bliki/#{page.name}.#{web.markup}")
+ zos.puts(page.content)
+ end
+
+ zos.put_next_entry "bliki/bliki-metadata.txt"
+ web.select_bliki.by_name.each do |page|
+ zos.puts "#{page.name}: by #{page.author}, created on #{page.revisions.first.pretty_created_at}"
+ 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
+ pages = web.select.by_name.inject({}) do |tex_web, page|
+ tex_web[page.name] = RedClothForTex.new(page.content).to_tex
+ tex_web
+ end
+
+ bliki_entries = web.select_bliki.by_name.inject({}) do |tex_web, page|
+ tex_web["bliki/#{page.name}"] = RedClothForTex.new(page.content).to_tex
+ tex_web
+ end
+
+ pages.update bliki_entries
+ 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
+ if web
+ markup = web.markup
+ markup = 'markdown' if markup.to_s =~ /markdown/
+ sub_template("#{markup}_help")
+ else
+ ''
+ end
+ 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:
\ No newline at end of file