1 class QuickEditIssuesController < ApplicationController
2 include ApplicationHelper
3 before_filter :find_issues
4 before_filter :check_first_issue
5 before_filter :check_target_specifier
6 before_filter :check_replace_args, :only => [:replace, :replace_preview]
9 custom_field = @dialog_params[:custom_field]
11 @dialog_params[:description] = nil
13 @dialog_params[:description] = custom_field.description.presence if custom_field.attributes().has_key?('description')
15 @dialog_params[:description] = nil if (@dialog_params[:description] == "")
16 @dialog_params[:issue_ids] = params[:ids]
17 @dialog_params[:back_url] = params[:back_url]
18 @dialog_params[:default_value] = params[:default_value] unless (params[:default_value].nil?)
22 @replaced_issues = @issues.map do |issue|
23 eval_replace(issue, @attribute_name, @find_regexp, @replace)
28 emulate_bulk_update = Setting.plugin_quick_edit['emulate_bulk_update']
31 @issues.each do |issue|
32 replace_result = eval_replace(issue, @attribute_name, @find_regexp, @replace)
33 if replace_result[:before] != replace_result[:after]
34 issue.init_journal(User.current, params[:notes])
35 issue.safe_attributes = {@attribute_name => replace_result[:after]}
36 issue.safe_attributes = {'private_notes' => (params.has_key?(:private_notes) ? '1' : '0')}
38 if emulate_bulk_update == 'on'
39 emulate_params = { @target_specifier.to_sym => replace_result[after],
40 'ids[]'.to_sym => issue.id,
41 :back_url => params[:back_url] }
42 call_hook(:controller_issues_bulk_edit_before_save, { :params => emulate_params, :issue => issue })
50 redirect_to params[:back_url]
57 logger.warn "### quick edit ### issues not found."
65 def check_target_specifier
66 @target_specifier = params[:target_specifier]
67 if @target_specifier.nil?
68 logger.warn "### quick edit ### missing target specifier."
69 render_error :status => 400
73 parsed = parse_target_specifier(@target_specifier)
74 if parsed.nil? || parsed.empty?
75 logger.warn "### quick edit ### invalid target specifier. target_specifier=" + @target_specifier
76 render_error :status => 400
80 @attribute_name = parsed[0]
82 custom_field_id = parsed[1]
83 custom_field = @issue.available_custom_fields.detect {|f| f.id.to_s == custom_field_id}
85 logger.warn "### quick edit ### no available custom field. target_specifier=" + @target_specifier
86 head 409, {"X-Quick-Edit-Error" => l(:text_can_not_edit)}
91 unless @attribute_name == :notes
92 unless @issue.safe_attribute_names.include?(@attribute_name)
93 logger.warn "### quick edit ### no safe attribute. target_specifier=" + @target_specifier
94 head 409, {"X-Quick-Edit-Error" => l(:text_can_not_edit)}
100 @dialog_params = get_input_dialog_params_for_core_fields(@issue, @target_specifier)
102 @dialog_params = get_input_dialog_params_for_custom_fields(@issue, @target_specifier, custom_field)
107 def check_replace_args
108 unless @dialog_params[:replacable]
109 logger.warn "### quick edit ### no support. target_specifier=" + @target_specifier
110 render_error :status => 400
115 match_case = params[:match_case].to_s # nil to ""
116 unless match_case.empty?
117 options = Regexp::IGNORECASE
120 @find = params[:find].to_s # nil to ""
122 logger.warn "### quick edit ### missing params[find]."
123 render_error :status => 400
127 if @find.length > 127
128 logger.warn "### quick edit ### length over params[find]."
129 render_error :status => 400
132 @find_regexp = Regexp.new(Regexp.escape(@find), options)
134 @replace = params[:replace].to_s # nil to ""
135 if @replace.length > 127
136 logger.warn "### quick edit ### length over params[replace]."
137 render_error :status => 400
140 @replace = @replace.gsub(/\\/, '\\\\\\\\')
143 def get_input_dialog_params_for_core_fields(issue, target_specifier)
144 attribute_name = parse_target_specifier(target_specifier)[0]
146 caption = get_attribute_caption(attribute_name)
147 field_type = get_attribute_type(attribute_name)
148 default_value = issue[attribute_name]
149 default_value = "" if default_value.nil?
150 validation_pattern = get_field_validation_pattern(field_type)
151 help_message = get_field_help_message(field_type)
152 clear_pseudo_value = nil
153 clear_pseudo_value = 'none' if %w(parent_issue_id start_date due_date estimated_hours).include?(attribute_name)
154 replacable = %w(subject).include?(attribute_name)
157 { :attribute_name => attribute_name.to_sym,
159 :target_specifier => target_specifier,
160 :field_type => field_type,
161 :default_value => default_value,
162 :validation_pattern => validation_pattern,
163 :help_message => help_message,
164 :clear_pseudo_value => clear_pseudo_value,
165 :replacable => replacable,
170 def get_input_dialog_params_for_custom_fields(issue, target_specifier, custom_field)
171 attribute_name = parse_target_specifier(target_specifier)[0]
173 caption = custom_field.name
174 field_type = custom_field.field_format.to_sym
175 default_value = issue.editable_custom_field_values.detect {|v| v.custom_field_id == custom_field.id}
176 default_value = "" if default_value.nil?
177 validation_pattern = get_field_validation_pattern(field_type)
178 help_message = get_field_help_message(field_type)
182 { :attribute_name => attribute_name.to_sym,
184 :target_specifier => target_specifier,
185 :field_type => field_type,
186 :default_value => default_value,
187 :validation_pattern => validation_pattern,
188 :help_message => help_message,
189 :clear_pseudo_value => '__none__',
190 :replacable => replacable,
191 :custom_field => custom_field
195 def get_field_validation_pattern(field_type)
196 case field_type.to_sym
204 pattern = '^[+-]?(\d+|\d*\.\d+|\d+\.\d+)($|[eE][+-]?\d+$)'
206 pattern = '\d{4}-\d{2}-\d{2}'
210 def get_field_help_message(field_type)
211 help_message= l(:text_edit_confirm)
212 help_message += " (yyyy-mm-dd)" if field_type == :date
216 def eval_replace(issue, attribute_name, find_regexp, replace)
217 before = issue[attribute_name].to_s # nil to ""
218 after = before.gsub(find_regexp, replace)