OSDN Git Service

If you do not change the value before and after the replacement operation, it was...
[quickedit/quick_edit.git] / app / controllers / quick_edit_issues_controller.rb
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]
7
8   def edit
9     custom_field = @dialog_params[:custom_field]
10     if custom_field.nil?
11       @dialog_params[:description] = nil
12     else
13       @dialog_params[:description] = custom_field.description.presence if custom_field.attributes().has_key?('description')
14     end
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?)
19   end
20
21   def replace_preview
22     @replaced_issues = @issues.map do |issue|
23       eval_replace(issue, @attribute_name, @find_regexp, @replace)
24     end
25   end
26
27   def replace
28     emulate_bulk_update = Setting.plugin_quick_edit['emulate_bulk_update']
29
30     Issue.transaction do
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')}
37
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 })
43           end
44
45           issue.save!
46         end
47       end
48     end
49
50     redirect_to params[:back_url]
51   end
52
53 private
54   # rails filter
55   def check_first_issue
56     if @issues.empty?
57       logger.warn "### quick edit ### issues not found."
58       render_404
59     end
60
61     @issue = @issues[0]
62   end
63
64   # rails filter
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
70       return
71     end
72
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
77       return
78     end
79
80     @attribute_name = parsed[0]
81     if parsed.size == 2
82       custom_field_id = parsed[1]
83       custom_field = @issue.available_custom_fields.detect {|f| f.id.to_s == custom_field_id}
84       if custom_field.nil?
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)}
87         return false
88       end
89     end
90
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)}
95         return false
96       end
97     end
98
99     if custom_field.nil?
100       @dialog_params = get_input_dialog_params_for_core_fields(@issue, @target_specifier)
101     else
102       @dialog_params = get_input_dialog_params_for_custom_fields(@issue, @target_specifier, custom_field)
103     end
104   end
105
106   # rails filter
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
111       return
112     end
113
114     options = 0
115     match_case = params[:match_case].to_s # nil to ""
116     unless match_case.empty?
117       options = Regexp::IGNORECASE
118     end
119
120     @find = params[:find].to_s # nil to ""
121     if @find.empty?
122       logger.warn "### quick edit ### missing params[find]."
123       render_error :status => 400
124       return
125     end
126
127     if @find.length > 127
128       logger.warn "### quick edit ### length over params[find]."
129       render_error :status => 400
130       return
131     end
132     @find_regexp = Regexp.new(Regexp.escape(@find), options)
133
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
138       return
139     end
140     @replace = @replace.gsub(/\\/, '\\\\\\\\')
141   end
142
143   def get_input_dialog_params_for_core_fields(issue, target_specifier)
144     attribute_name = parse_target_specifier(target_specifier)[0]
145
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)
155
156     ret =
157       { :attribute_name => attribute_name.to_sym,
158         :caption => caption,
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,
166         :custom_field => nil
167       }
168   end
169
170   def get_input_dialog_params_for_custom_fields(issue, target_specifier, custom_field)
171     attribute_name = parse_target_specifier(target_specifier)[0]
172
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)
179     replacable = false
180
181     ret =
182       { :attribute_name => attribute_name.to_sym,
183         :caption => caption,
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
192       }
193   end
194
195   def get_field_validation_pattern(field_type)
196      case field_type.to_sym
197      when :string
198         pattern = ''
199      when :text
200         pattern = ''
201      when :int
202         pattern = '\d+'
203      when :float
204         pattern = '^[+-]?(\d+|\d*\.\d+|\d+\.\d+)($|[eE][+-]?\d+$)'
205      when :date
206         pattern = '\d{4}-\d{2}-\d{2}'
207      end
208   end
209
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
213     help_message
214   end
215
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)
219
220       { :id  => issue.id,
221         :before => before,
222         :after =>  after}
223   end
224 end