Project

General

Profile

Feature #647 » wiki_extensions_ref_issue.rb

r153 https://bitbucket.org/kusu/redmine_wiki_extensions-ref_issues - Tomohisa Kusukawa, 01/11/2011 12:38 AM

 
require 'redmine'

module WikiExtensionsRefIssue
Redmine::WikiFormatting::Macros.register do
desc "Displays a list of referer issues."
macro :ref_issues do |obj, args|
flgSameProject = false;
searchWords = [];
flgSearchSubject = nil;
flgSearchDescription = nil;

# 引数をパース
columns = [];
args.each do |arg|
arg.strip!;
if arg=~/^\-([^\=]*)(\=.*)?$/ then # オプション表記発見
options = $1;
options.each_byte do |c|
case c.chr
when 'S'
flgSearchSubject = false;
when 's'
flgSearchSubject = true;
when 'D'
flgSearchDescription = false;
when 'd'
flgSearchDescription = true;
when 'p'
flgSameProject = true;
when 'w'
if arg=~/^[^\=]+\=(.*)$/ then
searchWords.push($1);
else
raise "no search word:#{arg}<br>"+
"ex. -w=SEARCH_WORD";
end
when 'q'
if arg=~/^[^\=]+\=(.*)$/ then
@customQuery = $1;
if flgSearchSubject == nil then
flgSearchSubject = false;
end
if flgSearchDescription==nil then
flgSearchDescription = false;
end
else
raise "no search word:#{arg}<br>"+
"ex. -w=SEARCH_WORD";
end
else
raise "unknown option:#{arg}<br>"+
"[optins]<br>"+
"-S : not search word in subject<br>"+
"-s : search word in subject<br>"+
"-D : not search word in description<br>"+
"-d : search word in description<br>"+
"-p : restrict project<br>"+
"-w=[search word]: specify search word<br>"+
"-q=[custom query name]: specify custom query";
end
end
else
case arg
when 'project'
columns.push(:project);
when 'tracker'
columns.push(:tracker);
when 'parent'
columns.push(:parent);
when 'status'
columns.push(:status);
when 'priority'
columns.push(:priority);
when 'subject'
columns.push(:subject);
when 'author'
columns.push(:author);
when 'assigned_to', 'assigned'
columns.push(:assigned_to);
when 'updated_on', 'updated'
columns.push(:updated_on);
when 'category'
columns.push(:category);
when 'fixed_version'
columns.push(:fixed_version);
when 'start_date'
columns.push(:start_date);
when 'due_date'
columns.push(:due_date);
when 'estimated_hours'
columns.push(:estimated_hours);
when 'done_ratio'
columns.push(:done_ratio);
when 'created_on', 'created'
columns.push(:created_on);
else
raise "unknown column:#{arg}<br>";
end
end
end

if flgSearchSubject==nil then
flgSearchSubject = true;
end
if flgSearchDescription==nil then
flgSearchDescription = true;
end

# オプション指定がなければ検索ワードを抽出
if searchWords.empty? then # 検索ワードの指定が無かったら
# 検索するキーワードを取得する
if obj.class == WikiContent then # Wikiの場合はページ名および別名を検索ワードにする
searchWords.push(obj.page.title); #ページ名
redirects = WikiRedirect.find(:all, :conditions=>["redirects_to=:s", {:s=>obj.page.title}]); #別名query
redirects.each do |redirect|
searchWords.push(redirect.title); #別名
end
elsif obj.class == Issue then # チケットの場合はチケット番号表記を検索ワードにする
searchWords.push('#'+obj.id.to_s);
elsif obj.class == Journal && obj.journalized_type == "Issue" then
# チケットコメントの場合もチケット番号表記を検索ワードにする
searchWords.push('#'+obj.journalized_id.to_s);
else
# チケットでもWikiでもない場合はどうしていいかわからないので帰る。
return;
end
end

extend SortHelper
extend QueriesHelper
extend IssuesHelper

if defined?(@customQuery) then
cond = "project_id IS NULL"
cond << " OR project_id = #{@project.id}" if @project
cond = "(#{cond}) AND name = '#{@customQuery}'";
@query = Query.find(:first, :conditions=>cond);
else
@query = Query.new(:name => "_", :filters => {});
end
WikiExtensionsRefIssue.overwrite_sql_for_field(@query);
WikiExtensionsRefIssue.overwrite_statement(@query);

if flgSameProject then
@query.project = @project;
end

sort_init(@query.sort_criteria.empty? ? [['id', 'desc']] : @query.sort_criteria);
sort_update(@query.sortable_columns);

if flgSearchSubject then
@query.add_filter("subject", "~", searchWords);
end

if flgSearchDescription then
@query.available_filters["description"] = { :type => :text, :order => 8 };
@query.add_filter("description", "~", searchWords);
end

if !columns.empty? then
@query.column_names = columns;
end

@issues = @query.issues(:order => sort_clause);
disp = context_menu(issues_context_menu_path);
disp << render(:partial => 'issues/list', :locals => {:issues => @issues, :query => @query});

return disp;
end
end

def WikiExtensionsRefIssue.overwrite_sql_for_field(query)
def query.sql_for_field(field, operator, value, db_table, db_field, is_custom_filter=false);
sql = '';
case operator
when "="
sql = "#{db_table}.#{db_field} IN (" + value.collect{|val| "'#{connection.quote_string(val)}'"}.join(",") + ")"
when "!"
sql = "(#{db_table}.#{db_field} IS NULL OR #{db_table}.#{db_field} NOT IN (" + value.collect{|val| "'#{connection.quote_string(val)}'"}.join(",") + "))"
when "!*"
sql = "#{db_table}.#{db_field} IS NULL"
sql << " OR #{db_table}.#{db_field} = ''" if is_custom_filter
when "*"
sql = "#{db_table}.#{db_field} IS NOT NULL"
sql << " AND #{db_table}.#{db_field} <> ''" if is_custom_filter
when ">="
sql = "#{db_table}.#{db_field} >= #{value.first.to_i}"
when "<="
sql = "#{db_table}.#{db_field} <= #{value.first.to_i}"
when "o"
sql = "#{IssueStatus.table_name}.is_closed=#{connection.quoted_false}" if field == "status_id"
when "c"
sql = "#{IssueStatus.table_name}.is_closed=#{connection.quoted_true}" if field == "status_id"
when ">t-"
sql = date_range_clause(db_table, db_field, - value.first.to_i, 0)
when "<t-"
sql = date_range_clause(db_table, db_field, nil, - value.first.to_i)
when "t-"
sql = date_range_clause(db_table, db_field, - value.first.to_i, - value.first.to_i)
when ">t+"
sql = date_range_clause(db_table, db_field, value.first.to_i, nil)
when "<t+"
sql = date_range_clause(db_table, db_field, 0, value.first.to_i)
when "t+"
sql = date_range_clause(db_table, db_field, value.first.to_i, value.first.to_i)
when "t"
sql = date_range_clause(db_table, db_field, 0, 0)
when "w"
from = l(:general_first_day_of_week) == '7' ?
# week starts on sunday
((Date.today.cwday == 7) ? Time.now.at_beginning_of_day : Time.now.at_beginning_of_week - 1.day) :
# week starts on monday (Rails default)
Time.now.at_beginning_of_week
sql = "#{db_table}.#{db_field} BETWEEN '%s' AND '%s'" % [connection.quoted_date(from), connection.quoted_date(from + 7.days)]
when "~"
sql = "(";
value.each do |v|
sql << " OR " if sql != "(";
sql << "LOWER(#{db_table}.#{db_field}) LIKE '%#{connection.quote_string(v.to_s.downcase)}%'";
end
sql << ")";
when "!~"
sql = "LOWER(#{db_table}.#{db_field}) NOT LIKE '%#{connection.quote_string(value.first.to_s.downcase)}%'"
end
return sql
end
end

def WikiExtensionsRefIssue.overwrite_statement(query)
def query.statement
# filters clauses
filters_clauses = []
filters_key_words = []
filters.each_key do |field|
next if field == "subproject_id"
v = values_for(field).clone
next unless v and !v.empty?
operator = operator_for(field)

# "me" value subsitution
if %w(assigned_to_id author_id watcher_id).include?(field)
v.push(User.current.logged? ? User.current.id.to_s : "0") if v.delete("me")
end

sql = ''
if field =~ /^cf_(\d+)$/
# custom field
db_table = CustomValue.table_name
db_field = 'value'
is_custom_filter = true
sql << "#{Issue.table_name}.id IN (SELECT #{Issue.table_name}.id FROM #{Issue.table_name} LEFT OUTER JOIN #{db_table} ON #{db_table}.customized_type='Issue' AND #{db_table}.customized_id=#{Issue.table_name}.id AND #{db_table}.custom_field_id=#{$1} WHERE "
sql << sql_for_field(field, operator, v, db_table, db_field, true) + ')'
elsif field == 'watcher_id'
db_table = Watcher.table_name
db_field = 'user_id'
sql << "#{Issue.table_name}.id #{ operator == '=' ? 'IN' : 'NOT IN' } (SELECT #{db_table}.watchable_id FROM #{db_table} WHERE #{db_table}.watchable_type='Issue' AND "
sql << sql_for_field(field, '=', v, db_table, db_field) + ')'
else
# regular field
db_table = Issue.table_name
db_field = field
sql << '(' + sql_for_field(field, operator, v, db_table, db_field) + ')'
end
if field == 'subject' || field == 'description' then
filters_key_words << sql;
else
filters_clauses << sql
end

end if filters and valid?
if !filters_key_words.empty? then
filters_clauses << '(' + filters_key_words.join(' OR ') + ')';
end
return (filters_clauses << project_statement).join(' AND ')
end
end
end
(3-3/3)