lib/redmine_xapian/search_strategies/xapian_search.rb
require 'uri'
module RedmineXapian
module SearchStrategies
module XapianSearch
def xapian_search(tokens, limit_options, offset, projects_to_search, all_words, user_stem_lang, user_stem_strategy, xapian_file )
xpattachments = []
return [xpattachments,0] unless Setting.plugin_redmine_xapian['enable'] == "true"
Rails.logger.debug "DEBUG: global settings dump" + Setting.plugin_redmine_xapian.inspect
Rails.logger.debug "DEBUG: user_stem_lang: " + user_stem_lang.inspect
Rails.logger.debug "DEBUG: user_stem_strategy: " + user_stem_strategy.inspect
Rails.logger.debug "DEBUG: databasepath: " + get_database_path(user_stem_lang)
databasepath = get_database_path(user_stem_lang)
begin
database = Xapian::Database.new(databasepath)
rescue => error
raise databasepath
end
# Start an enquire session.
enquire = Xapian::Enquire.new(database)
# Combine the rest of the command line arguments with spaces between
# them, so that simple queries don't have to be quoted at the shell
# level.
#query_string = ARGV[1..-1].join(' ')
query_string = tokens.join(' ')
# Parse the query string to produce a Xapian::Query object.
qp = Xapian::QueryParser.new()
stemmer = Xapian::Stem.new(user_stem_lang)
qp.stemmer = stemmer
qp.database = database
case user_stem_strategy
when "STEM_NONE" then qp.stemming_strategy = Xapian::QueryParser::STEM_NONE
when "STEM_SOME" then qp.stemming_strategy = Xapian::QueryParser::STEM_SOME
when "STEM_ALL" then qp.stemming_strategy = Xapian::QueryParser::STEM_ALL
end
if all_words
qp.default_op = Xapian::Query::OP_AND
else
qp.default_op = Xapian::Query::OP_OR
end
query = qp.parse_query(query_string)
Rails.logger.debug "DEBUG query_string is: #{query_string}"
Rails.logger.debug "DEBUG: Parsed query is: #{query.description()} "
# Find the top 100 results for the query.
enquire.query = query
matchset = enquire.mset(0, 1000)
return [xpattachments,0] if matchset.nil?
# Display the results.
#logger.debug "#{@matchset.matches_estimated()} results found."
Rails.logger.debug "DEBUG: Matches 1-#{matchset.size}:\n"
matchset.matches.each do |m|
#Rails.logger.debug "#{m.rank + 1}: #{m.percent}% docid=#{m.docid} [#{m.document.data}]\n"
Rails.logger.debug "DEBUG: m: " + m.document.data.inspect
docdata = m.document.data{url}
dochash = Hash[*docdata.scan(/(url|sample|modtime|type|size)=\/?([^\n\]]+)/).flatten]
dochash["url"]=URI.unescape(dochash["url"].to_s)
if dochash
Rails.logger.debug "DEBUG: dochash not nil.. " + dochash.fetch('url').to_s
Rails.logger.debug "DEBUG: limit_conditions " + limit_options[:limit].inspect
if dochash["url"].to_s =~ /^repos\// and xapian_file == "Repofile" then
Rails.logger.debug "DEBUG: searching for repofiles"
if repo_file = process_repo_file(projects_to_search, dochash)
xpattachments << repo_file
end
elsif xapian_file == "Attachment"
Rails.logger.debug "DEBUG: searching for attachments"
if attachment = process_attachment(projects_to_search, dochash)
xpattachments << attachment
end
end
end
end
xpattachments = xpattachments.sort_by{|x| x[:created_on] }
if RUBY_VERSION >= "1.9"
xpattachments = xpattachments.each do |attachment|
attachment[:description].force_encoding('UTF-8')
end
end
Rails.logger.debug "DEBUG: xapian searched"
[xpattachments, xpattachments.size]
end
private
def process_attachment(projects_to_search, dochash)
docattach = Attachment.where( :disk_filename => dochash.fetch('url') ).first
if docattach
Rails.logger.debug "DEBUG: attach event_datetime" + docattach.event_datetime.inspect
Rails.logger.debug "DEBUG: attach project" + docattach.project.inspect
Rails.logger.debug "DEBUG: docattach not nil..: " + docattach.inspect
if docattach["container_type"] == "KbArticle" && !Redmine::Search.available_search_types.include?("kb_articles")
Rails.logger.debug "DEBUG: Knowledgebase plugin is not installed.."
elsif docattach.container
Rails.logger.debug "DEBUG: adding attach.. "
user = User.current
project = docattach.container.project
container_type = docattach["container_type"]
container_permission = SearchStrategies::ContainerTypeHelper.to_permission(container_type)
can_view_container = user.allowed_to?(container_permission, project)
allowed = case container_type
when "KbArticle"
true
when "Issue"
can_view_issue = Issue.find_by_id(docattach[:container_id]).visible?
can_view_container && can_view_issue
else
can_view_container
end
if allowed && project_included(docattach.container.project.id, projects_to_search)
docattach[:description] = dochash["sample"]
docattach
else
Rails.logger.debug "DEBUG: user without permissions"
nil
end
end
end
end
def process_repo_file(projects_to_search, dochash)
Rails.logger.debug "DEBUG: repo file: " + dochash.fetch('url').inspect
dochash2=Hash[ [:project_identifier, :repo_identifier, :file ].zip(dochash.fetch('url').split('/',4).drop(1)) ]
project=Project.where(:identifier => dochash2[:project_identifier]).first
repository=Repository.where( :project_id=>project.id, :identifier=>dochash2[:repo_identifier] ).first unless project.nil?
Rails.logger.debug "DEBUG: repository found " + repository.inspect
if repository
allowed = User.current.allowed_to?(:browse_repository, repository.project)
if (allowed and project_included( project.id, projects_to_search ))
fmtime=file_timestamp(dochash2[:file], project.identifier, repository.identifier)
docattach=Repofile.new( :filename=>dochash2[:file],
:created_on=>fmtime,
:project_id=>project.id,
:description=>dochash["sample"],
:repository_id=>repository.id)
Rails.logger.debug "DEBUG: push attach" + docattach.inspect
docattach[:description]=dochash["sample"]
docattach[:created_on]=fmtime
docattach[:project_id]=project.id
docattach[:repository_id]=repository.id
docattach[:filename]=dochash2[:file]
#load 'acts_as_event.rb'
docattach[:project_id]=project.id
Rails.logger.debug "DEBUG: attach event_datetime" + docattach.event_datetime.inspect
Rails.logger.debug "DEBUG: push attach" + docattach.inspect
docattach
else
Rails.logger.debug "DEBUG: user without :browse_repository permissions"
nil
end
end
end
def project_included( project_id, projects_to_search )
Rails.logger.debug "DEBUG: project id: " + project_id.inspect
Rails.logger.debug "DEBUG: projects to search: " + projects_to_search.inspect
return true if projects_to_search.nil?
projects_to_search.any? do |x|
if x.is_a?(ActiveRecord::Relation)
x.first.id == project_id
else
x[:id] == project_id
end
end
end
def get_database_path(user_stem_lang)
File.join(
Setting.plugin_redmine_xapian['index_database'].rstrip,
user_stem_lang
)
end
def file_timestamp( filename, project_name, repo_identifier )
repositoryfile = File.join(Rails.root, "files", "repos", project_name, repo_identifier, filename )
Rails.logger.debug "DEBUG: file_timestamp for #{repositoryfile}"
begin
time_stamp=File.new(repositoryfile).mtime.in_time_zone
rescue
Rails.logger.info "Redmine_xapian: Error getting #{repositoryfile} timestamp."
time_stamp=time_stamp=Time.at(0)
end
Rails.logger.debug "DEBUG: File mtime: #{time_stamp.inspect}"
time_stamp
end
end
end
end