This repository has been archived on 2023-02-21. You can view files and clone it, but cannot push or open issues or pull requests.
wiki_external_filter/app/helpers/wiki_external_filter_helper.rb

180 lines
4.9 KiB
Ruby
Raw Normal View History

2010-01-11 13:38:44 +01:00
require 'digest/sha2'
2012-08-02 12:09:00 +02:00
include Redmine::WikiFormatting::Macros::Definitions
2010-01-11 13:38:44 +01:00
module WikiExternalFilterHelper
def load_config
unless @config
2012-08-02 12:09:00 +02:00
config_file = "#{Rails.root}/plugins/wiki_external_filter/config/wiki_external_filter.yml"
2010-01-11 13:38:44 +01:00
unless File.exists?(config_file)
raise "Config not found: #{config_file}"
end
2012-08-02 12:09:00 +02:00
@config = YAML.load_file(config_file)[Rails.env]
2010-01-11 13:38:44 +01:00
end
@config
end
def has_macro(macro)
config = load_config
config.key?(macro)
end
module_function :load_config, :has_macro
def construct_cache_key(macro, name)
['wiki_external_filter', macro, name].join("/")
end
def build(text, attachments, macro, info)
2010-01-11 13:38:44 +01:00
2012-08-02 12:09:00 +02:00
name = Digest::SHA256.hexdigest(text.to_s)
2010-01-11 13:38:44 +01:00
result = {}
content = nil
cache_key = nil
expires = 0
if info.key?('cache_seconds')
expires = info['cache_seconds']
else
expires = Setting.plugin_wiki_external_filter['cache_seconds'].to_i
end
if expires > 0
cache_key = self.construct_cache_key(macro, name)
begin
2012-08-02 12:09:00 +02:00
content = Rails.cache.read cache_key, :expires_in => expires.seconds
rescue
2012-08-02 12:09:00 +02:00
Rails.logger.error "Failed to load cache: #{cache_key}, error: $! #{error} #{$@}"
end
2010-01-11 13:38:44 +01:00
end
if content
2012-08-02 12:09:00 +02:00
result[:source] = text.to_s
2010-01-11 13:38:44 +01:00
result[:content] = content
2012-08-02 12:09:00 +02:00
Rails.logger.debug "from cache: #{cache_key}"
2010-01-11 13:38:44 +01:00
else
result = self.build_forced(text, attachments, info)
2010-01-11 13:38:44 +01:00
if result[:status]
if expires > 0
begin
2012-08-02 12:09:00 +02:00
Rails.cache.write cache_key, result[:content], :expires_in => expires.seconds
Rails.logger.debug "cache saved: #{cache_key} expires #{expires.seconds}"
rescue
2012-08-02 12:09:00 +02:00
Rails.logger.error "Failed to save cache: #{cache_key}, result content #{result[:content]}, error: $!"
end
else
raise "please set expires time under plugins settings"
end
2010-01-11 13:38:44 +01:00
else
raise "Error applying external filter: stdout is #{result[:content]}, stderr is #{result[:errors]}"
2010-01-11 13:38:44 +01:00
end
end
result[:name] = name
result[:macro] = macro
result[:content_types] = info['outputs'].map { |out| out['content_type'] }
result[:template] = info['template']
2010-01-11 13:38:44 +01:00
return result
end
def build_forced(text, attachments, info)
if info['replace_attachments'] and attachments
attachments.each do |att|
2012-08-02 12:09:00 +02:00
text.to_s.gsub!(/#{att.filename.downcase}/i, att.diskfile)
end
end
2010-01-11 13:38:44 +01:00
result = {}
content = []
errors = ""
2012-08-02 12:09:00 +02:00
text = text.first.to_s.gsub("<br />", "\n")
Rails.logger.debug "\n Text #{text} \n"
info['outputs'].each do |out|
2012-08-02 12:09:00 +02:00
Rails.logger.info "executing command: #{out['command']}"
2010-01-11 13:38:44 +01:00
c = nil
e = nil
2010-01-11 13:38:44 +01:00
# If popen4 is available - use it as it provides stderr
# redirection so we can get more info in the case of error.
begin
require 'open4'
Open4::popen4(out['command']) { |pid, fin, fout, ferr|
fin.write out['prolog'] if out.key?('prolog')
2012-08-02 12:09:00 +02:00
fin.write text
fin.write out['epilog'] if out.key?('epilog')
fin.close
c, e = [fout.read, ferr.read]
}
rescue LoadError
IO.popen(out['command'], 'r+b') { |f|
f.write out['prolog'] if out.key?('prolog')
2012-08-02 12:09:00 +02:00
f.write text
f.write out['epilog'] if out.key?('epilog')
f.close_write
c = f.read
2012-08-02 12:09:00 +02:00
}
end
2012-08-02 12:09:00 +02:00
Rails.logger.debug("child status: sig=#{$?.termsig}, exit=#{$?.exitstatus}")
content << c
errors += e if e
end
2010-01-11 13:38:44 +01:00
result[:content] = content
result[:errors] = errors
2010-01-11 13:38:44 +01:00
result[:source] = text
result[:status] = $?.exitstatus == 0
return result
end
def render_tag(result)
result = result.dup
result[:render_type] = 'inline'
html = render_common(result).chop
html << headers_common(result).chop
html
2010-01-11 13:38:44 +01:00
end
def render_block(result, wiki_name)
result = result.dup
result[:render_type] = 'block'
2010-01-11 13:38:44 +01:00
result[:wiki_name] = wiki_name
result[:inside] = render_common(result)
html = render_to_string(:template => 'wiki_external_filter/block', :layout => false, :locals => result).chop
html << headers_common(result).chop
html
end
def render_common(result)
render_to_string :template => "wiki_external_filter/macro_#{result[:template]}", :layout => false, :locals => result
end
def headers_common(result)
render_to_string :template => 'wiki_external_filter/headers', :layout => false, :locals => result
2010-01-11 13:38:44 +01:00
end
class Macro
def initialize(view, source, attachments, macro, info)
2010-01-11 13:38:44 +01:00
@view = view
@view.controller.extend(WikiExternalFilterHelper)
@result = @view.controller.build(source, attachments, macro, info)
2010-01-11 13:38:44 +01:00
end
def render()
@view.controller.render_tag(@result)
end
def render_block(wiki_name)
@view.controller.render_block(@result, wiki_name)
end
end
end