You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

issues_controller.rb 22KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622
  1. # frozen_string_literal: true
  2. # Redmine - project management software
  3. # Copyright (C) 2006-2019 Jean-Philippe Lang
  4. #
  5. # This program is free software; you can redistribute it and/or
  6. # modify it under the terms of the GNU General Public License
  7. # as published by the Free Software Foundation; either version 2
  8. # of the License, or (at your option) any later version.
  9. #
  10. # This program is distributed in the hope that it will be useful,
  11. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. # GNU General Public License for more details.
  14. #
  15. # You should have received a copy of the GNU General Public License
  16. # along with this program; if not, write to the Free Software
  17. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  18. class IssuesController < ApplicationController
  19. default_search_scope :issues
  20. before_action :find_issue, :only => [:show, :edit, :update, :issue_tab]
  21. before_action :find_issues, :only => [:bulk_edit, :bulk_update, :destroy]
  22. before_action :authorize, :except => [:index, :new, :create]
  23. before_action :find_optional_project, :only => [:index, :new, :create]
  24. before_action :build_new_issue_from_params, :only => [:new, :create]
  25. accept_rss_auth :index, :show
  26. accept_api_auth :index, :show, :create, :update, :destroy
  27. rescue_from Query::StatementInvalid, :with => :query_statement_invalid
  28. helper :journals
  29. helper :projects
  30. helper :custom_fields
  31. helper :issue_relations
  32. helper :watchers
  33. helper :attachments
  34. helper :queries
  35. include QueriesHelper
  36. helper :repositories
  37. helper :timelog
  38. def index
  39. use_session = !request.format.csv?
  40. retrieve_query(IssueQuery, use_session)
  41. if @query.valid?
  42. respond_to do |format|
  43. format.html {
  44. @issue_count = @query.issue_count
  45. @issue_pages = Paginator.new @issue_count, per_page_option, params['page']
  46. @issues = @query.issues(:offset => @issue_pages.offset, :limit => @issue_pages.per_page)
  47. render :layout => !request.xhr?
  48. }
  49. format.api {
  50. @offset, @limit = api_offset_and_limit
  51. @query.column_names = %w(author)
  52. @issue_count = @query.issue_count
  53. @issues = @query.issues(:offset => @offset, :limit => @limit)
  54. Issue.load_visible_relations(@issues) if include_in_api_response?('relations')
  55. }
  56. format.atom {
  57. @issues = @query.issues(:limit => Setting.feeds_limit.to_i)
  58. render_feed(@issues, :title => "#{@project || Setting.app_title}: #{l(:label_issue_plural)}")
  59. }
  60. format.csv {
  61. @issues = @query.issues(:limit => Setting.issues_export_limit.to_i)
  62. send_data(query_to_csv(@issues, @query, params[:csv]), :type => 'text/csv; header=present', :filename => 'issues.csv')
  63. }
  64. format.pdf {
  65. @issues = @query.issues(:limit => Setting.issues_export_limit.to_i)
  66. send_file_headers! :type => 'application/pdf', :filename => 'issues.pdf'
  67. }
  68. end
  69. else
  70. respond_to do |format|
  71. format.html { render :layout => !request.xhr? }
  72. format.any(:atom, :csv, :pdf) { head 422 }
  73. format.api { render_validation_errors(@query) }
  74. end
  75. end
  76. rescue ActiveRecord::RecordNotFound
  77. render_404
  78. end
  79. def show
  80. @journals = @issue.visible_journals_with_index
  81. @has_changesets = @issue.changesets.visible.preload(:repository, :user).exists?
  82. @relations = @issue.relations.select {|r| r.other_issue(@issue) && r.other_issue(@issue).visible? }
  83. @journals.reverse! if User.current.wants_comments_in_reverse_order?
  84. if User.current.allowed_to?(:view_time_entries, @project)
  85. Issue.load_visible_spent_hours([@issue])
  86. Issue.load_visible_total_spent_hours([@issue])
  87. end
  88. respond_to do |format|
  89. format.html {
  90. @allowed_statuses = @issue.new_statuses_allowed_to(User.current)
  91. @priorities = IssuePriority.active
  92. @time_entry = TimeEntry.new(:issue => @issue, :project => @issue.project)
  93. @time_entries = @issue.time_entries.visible.preload(:activity, :user)
  94. @relation = IssueRelation.new
  95. retrieve_previous_and_next_issue_ids
  96. render :template => 'issues/show'
  97. }
  98. format.api {
  99. @changesets = @issue.changesets.visible.preload(:repository, :user).to_a
  100. @changesets.reverse! if User.current.wants_comments_in_reverse_order?
  101. }
  102. format.atom { render :template => 'journals/index', :layout => false, :content_type => 'application/atom+xml' }
  103. format.pdf {
  104. send_file_headers! :type => 'application/pdf', :filename => "#{@project.identifier}-#{@issue.id}.pdf"
  105. }
  106. end
  107. end
  108. def new
  109. respond_to do |format|
  110. format.html { render :action => 'new', :layout => !request.xhr? }
  111. format.js
  112. end
  113. end
  114. def create
  115. unless User.current.allowed_to?(:add_issues, @issue.project, :global => true)
  116. raise ::Unauthorized
  117. end
  118. call_hook(:controller_issues_new_before_save, { :params => params, :issue => @issue })
  119. @issue.save_attachments(params[:attachments] || (params[:issue] && params[:issue][:uploads]))
  120. if @issue.save
  121. call_hook(:controller_issues_new_after_save, { :params => params, :issue => @issue})
  122. respond_to do |format|
  123. format.html {
  124. render_attachment_warning_if_needed(@issue)
  125. flash[:notice] = l(:notice_issue_successful_create, :id => view_context.link_to("##{@issue.id}", issue_path(@issue), :title => @issue.subject))
  126. redirect_after_create
  127. }
  128. format.api { render :action => 'show', :status => :created, :location => issue_url(@issue) }
  129. end
  130. return
  131. else
  132. respond_to do |format|
  133. format.html {
  134. if @issue.project.nil?
  135. render_error :status => 422
  136. else
  137. render :action => 'new'
  138. end
  139. }
  140. format.api { render_validation_errors(@issue) }
  141. end
  142. end
  143. end
  144. def edit
  145. return unless update_issue_from_params
  146. respond_to do |format|
  147. format.html { }
  148. format.js
  149. end
  150. end
  151. def update
  152. return unless update_issue_from_params
  153. @issue.save_attachments(params[:attachments] || (params[:issue] && params[:issue][:uploads]))
  154. saved = false
  155. begin
  156. saved = save_issue_with_child_records
  157. rescue ActiveRecord::StaleObjectError
  158. @conflict = true
  159. if params[:last_journal_id]
  160. @conflict_journals = @issue.journals_after(params[:last_journal_id]).to_a
  161. @conflict_journals.reject!(&:private_notes?) unless User.current.allowed_to?(:view_private_notes, @issue.project)
  162. end
  163. end
  164. if saved
  165. render_attachment_warning_if_needed(@issue)
  166. flash[:notice] = l(:notice_successful_update) unless @issue.current_journal.new_record? || params[:no_flash]
  167. respond_to do |format|
  168. format.html { redirect_back_or_default issue_path(@issue, previous_and_next_issue_ids_params) }
  169. format.api { render_api_ok }
  170. end
  171. else
  172. respond_to do |format|
  173. format.html { render :action => 'edit' }
  174. format.api { render_validation_errors(@issue) }
  175. end
  176. end
  177. end
  178. def issue_tab
  179. return render_error :status => 422 unless request.xhr?
  180. tab = params[:name]
  181. case tab
  182. when 'time_entries'
  183. @time_entries = @issue.time_entries.visible.preload(:activity, :user).to_a
  184. render :partial => 'issues/tabs/time_entries', :locals => {:time_entries => @time_entries}
  185. when 'changesets'
  186. @changesets = @issue.changesets.visible.preload(:repository, :user).to_a
  187. changesets.reverse! if User.current.wants_comments_in_reverse_order?
  188. render :partial => 'issues/tabs/changesets', :locals => {:changesets => @changesets}
  189. end
  190. end
  191. # Bulk edit/copy a set of issues
  192. def bulk_edit
  193. @issues.sort!
  194. @copy = params[:copy].present?
  195. @notes = params[:notes]
  196. if @copy
  197. unless User.current.allowed_to?(:copy_issues, @projects)
  198. raise ::Unauthorized
  199. end
  200. else
  201. unless @issues.all?(&:attributes_editable?)
  202. raise ::Unauthorized
  203. end
  204. end
  205. edited_issues = Issue.where(:id => @issues.map(&:id)).to_a
  206. @values_by_custom_field = {}
  207. edited_issues.each do |issue|
  208. issue.custom_field_values.each do |c|
  209. if c.value_present?
  210. @values_by_custom_field[c.custom_field] ||= []
  211. @values_by_custom_field[c.custom_field] << issue.id
  212. end
  213. end
  214. end
  215. @allowed_projects = Issue.allowed_target_projects
  216. if params[:issue]
  217. @target_project = @allowed_projects.detect {|p| p.id.to_s == params[:issue][:project_id].to_s}
  218. if @target_project
  219. target_projects = [@target_project]
  220. edited_issues.each {|issue| issue.project = @target_project}
  221. end
  222. end
  223. target_projects ||= @projects
  224. @trackers = target_projects.map {|p| Issue.allowed_target_trackers(p) }.reduce(:&)
  225. if params[:issue]
  226. @target_tracker = @trackers.detect {|t| t.id.to_s == params[:issue][:tracker_id].to_s}
  227. if @target_tracker
  228. edited_issues.each {|issue| issue.tracker = @target_tracker}
  229. end
  230. end
  231. if @copy
  232. # Copied issues will get their default statuses
  233. @available_statuses = []
  234. else
  235. @available_statuses = edited_issues.map(&:new_statuses_allowed_to).reduce(:&)
  236. end
  237. if params[:issue]
  238. @target_status = @available_statuses.detect {|t| t.id.to_s == params[:issue][:status_id].to_s}
  239. if @target_status
  240. edited_issues.each {|issue| issue.status = @target_status}
  241. end
  242. end
  243. edited_issues.each do |issue|
  244. issue.custom_field_values.each do |c|
  245. if c.value_present? && @values_by_custom_field[c.custom_field]
  246. @values_by_custom_field[c.custom_field].delete(issue.id)
  247. end
  248. end
  249. end
  250. @values_by_custom_field.delete_if {|k,v| v.blank?}
  251. @custom_fields = edited_issues.map{|i|i.editable_custom_fields}.reduce(:&).select {|field| field.format.bulk_edit_supported}
  252. @assignables = target_projects.map(&:assignable_users).reduce(:&)
  253. @versions = target_projects.map {|p| p.shared_versions.open}.reduce(:&)
  254. @categories = target_projects.map {|p| p.issue_categories}.reduce(:&)
  255. if @copy
  256. @attachments_present = @issues.detect {|i| i.attachments.any?}.present?
  257. @subtasks_present = @issues.detect {|i| !i.leaf?}.present?
  258. @watchers_present = User.current.allowed_to?(:add_issue_watchers, @projects) && Watcher.where(:watchable_type => 'Issue', :watchable_id => @issues.map(&:id)).exists?
  259. end
  260. @safe_attributes = edited_issues.map(&:safe_attribute_names).reduce(:&)
  261. @issue_params = params[:issue] || {}
  262. @issue_params[:custom_field_values] ||= {}
  263. end
  264. def bulk_update
  265. @issues.sort!
  266. @copy = params[:copy].present?
  267. attributes = parse_params_for_bulk_update(params[:issue])
  268. copy_subtasks = (params[:copy_subtasks] == '1')
  269. copy_attachments = (params[:copy_attachments] == '1')
  270. copy_watchers = (params[:copy_watchers] == '1')
  271. if @copy
  272. unless User.current.allowed_to?(:copy_issues, @projects)
  273. raise ::Unauthorized
  274. end
  275. target_projects = @projects
  276. if attributes['project_id'].present?
  277. target_projects = Project.where(:id => attributes['project_id']).to_a
  278. end
  279. unless User.current.allowed_to?(:add_issues, target_projects)
  280. raise ::Unauthorized
  281. end
  282. unless User.current.allowed_to?(:add_issue_watchers, @projects)
  283. copy_watchers = false
  284. end
  285. else
  286. unless @issues.all?(&:attributes_editable?)
  287. raise ::Unauthorized
  288. end
  289. end
  290. unsaved_issues = []
  291. saved_issues = []
  292. if @copy && copy_subtasks
  293. # Descendant issues will be copied with the parent task
  294. # Don't copy them twice
  295. @issues.reject! {|issue| @issues.detect {|other| issue.is_descendant_of?(other)}}
  296. end
  297. @issues.each do |orig_issue|
  298. orig_issue.reload
  299. if @copy
  300. issue = orig_issue.copy({},
  301. :attachments => copy_attachments,
  302. :subtasks => copy_subtasks,
  303. :watchers => copy_watchers,
  304. :link => link_copy?(params[:link_copy])
  305. )
  306. else
  307. issue = orig_issue
  308. end
  309. journal = issue.init_journal(User.current, params[:notes])
  310. issue.safe_attributes = attributes
  311. call_hook(:controller_issues_bulk_edit_before_save, { :params => params, :issue => issue })
  312. if issue.save
  313. saved_issues << issue
  314. else
  315. unsaved_issues << orig_issue
  316. end
  317. end
  318. if unsaved_issues.empty?
  319. flash[:notice] = l(:notice_successful_update) unless saved_issues.empty?
  320. if params[:follow]
  321. if @issues.size == 1 && saved_issues.size == 1
  322. redirect_to issue_path(saved_issues.first)
  323. elsif saved_issues.map(&:project).uniq.size == 1
  324. redirect_to project_issues_path(saved_issues.map(&:project).first)
  325. end
  326. else
  327. redirect_back_or_default _project_issues_path(@project)
  328. end
  329. else
  330. @saved_issues = @issues
  331. @unsaved_issues = unsaved_issues
  332. @issues = Issue.visible.where(:id => @unsaved_issues.map(&:id)).to_a
  333. bulk_edit
  334. render :action => 'bulk_edit'
  335. end
  336. end
  337. def destroy
  338. raise Unauthorized unless @issues.all?(&:deletable?)
  339. # all issues and their descendants are about to be deleted
  340. issues_and_descendants_ids = Issue.self_and_descendants(@issues).pluck(:id)
  341. time_entries = TimeEntry.where(:issue_id => issues_and_descendants_ids)
  342. @hours = time_entries.sum(:hours).to_f
  343. if @hours > 0
  344. case params[:todo]
  345. when 'destroy'
  346. # nothing to do
  347. when 'nullify'
  348. if Setting.timelog_required_fields.include?('issue_id')
  349. flash.now[:error] = l(:field_issue) + " " + ::I18n.t('activerecord.errors.messages.blank')
  350. return
  351. else
  352. time_entries.update_all(:issue_id => nil)
  353. end
  354. when 'reassign'
  355. reassign_to = @project && @project.issues.find_by_id(params[:reassign_to_id])
  356. if reassign_to.nil?
  357. flash.now[:error] = l(:error_issue_not_found_in_project)
  358. return
  359. elsif issues_and_descendants_ids.include?(reassign_to.id)
  360. flash.now[:error] = l(:error_cannot_reassign_time_entries_to_an_issue_about_to_be_deleted)
  361. return
  362. else
  363. time_entries.update_all(:issue_id => reassign_to.id, :project_id => reassign_to.project_id)
  364. end
  365. else
  366. # display the destroy form if it's a user request
  367. return unless api_request?
  368. end
  369. end
  370. @issues.each do |issue|
  371. begin
  372. issue.reload.destroy
  373. rescue ::ActiveRecord::RecordNotFound # raised by #reload if issue no longer exists
  374. # nothing to do, issue was already deleted (eg. by a parent)
  375. end
  376. end
  377. respond_to do |format|
  378. format.html { redirect_back_or_default _project_issues_path(@project) }
  379. format.api { render_api_ok }
  380. end
  381. end
  382. # Overrides Redmine::MenuManager::MenuController::ClassMethods for
  383. # when the "New issue" tab is enabled
  384. def current_menu_item
  385. if Setting.new_item_menu_tab == '1' && [:new, :create].include?(action_name.to_sym)
  386. :new_issue
  387. else
  388. super
  389. end
  390. end
  391. private
  392. def retrieve_previous_and_next_issue_ids
  393. if params[:prev_issue_id].present? || params[:next_issue_id].present?
  394. @prev_issue_id = params[:prev_issue_id].presence.try(:to_i)
  395. @next_issue_id = params[:next_issue_id].presence.try(:to_i)
  396. @issue_position = params[:issue_position].presence.try(:to_i)
  397. @issue_count = params[:issue_count].presence.try(:to_i)
  398. else
  399. retrieve_query_from_session
  400. if @query
  401. @per_page = per_page_option
  402. limit = 500
  403. issue_ids = @query.issue_ids(:limit => (limit + 1))
  404. if (idx = issue_ids.index(@issue.id)) && idx < limit
  405. if issue_ids.size < 500
  406. @issue_position = idx + 1
  407. @issue_count = issue_ids.size
  408. end
  409. @prev_issue_id = issue_ids[idx - 1] if idx > 0
  410. @next_issue_id = issue_ids[idx + 1] if idx < (issue_ids.size - 1)
  411. end
  412. query_params = @query.as_params
  413. if @issue_position
  414. query_params = query_params.merge(:page => (@issue_position / per_page_option) + 1, :per_page => per_page_option)
  415. end
  416. @query_path = _project_issues_path(@query.project, query_params)
  417. end
  418. end
  419. end
  420. def previous_and_next_issue_ids_params
  421. {
  422. :prev_issue_id => params[:prev_issue_id],
  423. :next_issue_id => params[:next_issue_id],
  424. :issue_position => params[:issue_position],
  425. :issue_count => params[:issue_count]
  426. }.reject {|k,v| k.blank?}
  427. end
  428. # Used by #edit and #update to set some common instance variables
  429. # from the params
  430. def update_issue_from_params
  431. @time_entry = TimeEntry.new(:issue => @issue, :project => @issue.project)
  432. if params[:time_entry]
  433. @time_entry.safe_attributes = params[:time_entry]
  434. end
  435. @issue.init_journal(User.current)
  436. issue_attributes = params[:issue]
  437. issue_attributes[:assigned_to_id] = User.current.id if issue_attributes && issue_attributes[:assigned_to_id] == 'me'
  438. if issue_attributes && params[:conflict_resolution]
  439. case params[:conflict_resolution]
  440. when 'overwrite'
  441. issue_attributes = issue_attributes.dup
  442. issue_attributes.delete(:lock_version)
  443. when 'add_notes'
  444. issue_attributes = issue_attributes.slice(:notes, :private_notes)
  445. when 'cancel'
  446. redirect_to issue_path(@issue)
  447. return false
  448. end
  449. end
  450. @issue.safe_attributes = issue_attributes
  451. @priorities = IssuePriority.active
  452. @allowed_statuses = @issue.new_statuses_allowed_to(User.current)
  453. true
  454. end
  455. # Used by #new and #create to build a new issue from the params
  456. # The new issue will be copied from an existing one if copy_from parameter is given
  457. def build_new_issue_from_params
  458. @issue = Issue.new
  459. if params[:copy_from]
  460. begin
  461. @issue.init_journal(User.current)
  462. @copy_from = Issue.visible.find(params[:copy_from])
  463. unless User.current.allowed_to?(:copy_issues, @copy_from.project)
  464. raise ::Unauthorized
  465. end
  466. @link_copy = link_copy?(params[:link_copy]) || request.get?
  467. @copy_attachments = params[:copy_attachments].present? || request.get?
  468. @copy_subtasks = params[:copy_subtasks].present? || request.get?
  469. @copy_watchers = User.current.allowed_to?(:add_issue_watchers, @project)
  470. @issue.copy_from(@copy_from, :attachments => @copy_attachments, :subtasks => @copy_subtasks, :watchers => @copy_watchers, :link => @link_copy)
  471. @issue.parent_issue_id = @copy_from.parent_id
  472. rescue ActiveRecord::RecordNotFound
  473. render_404
  474. return
  475. end
  476. end
  477. @issue.project = @project
  478. if request.get?
  479. @issue.project ||= @issue.allowed_target_projects.first
  480. end
  481. @issue.author ||= User.current
  482. @issue.start_date ||= User.current.today if Setting.default_issue_start_date_to_creation_date?
  483. attrs = (params[:issue] || {}).deep_dup
  484. if action_name == 'new' && params[:was_default_status] == attrs[:status_id]
  485. attrs.delete(:status_id)
  486. end
  487. if action_name == 'new' && params[:form_update_triggered_by] == 'issue_project_id'
  488. # Discard submitted version when changing the project on the issue form
  489. # so we can use the default version for the new project
  490. attrs.delete(:fixed_version_id)
  491. end
  492. attrs[:assigned_to_id] = User.current.id if attrs[:assigned_to_id] == 'me'
  493. @issue.safe_attributes = attrs
  494. if @issue.project
  495. @issue.tracker ||= @issue.allowed_target_trackers.first
  496. if @issue.tracker.nil?
  497. if @issue.project.trackers.any?
  498. # None of the project trackers is allowed to the user
  499. render_error :message => l(:error_no_tracker_allowed_for_new_issue_in_project), :status => 403
  500. else
  501. # Project has no trackers
  502. render_error l(:error_no_tracker_in_project)
  503. end
  504. return false
  505. end
  506. if @issue.status.nil?
  507. render_error l(:error_no_default_issue_status)
  508. return false
  509. end
  510. elsif request.get?
  511. render_error :message => l(:error_no_projects_with_tracker_allowed_for_new_issue), :status => 403
  512. return false
  513. end
  514. @priorities = IssuePriority.active
  515. @allowed_statuses = @issue.new_statuses_allowed_to(User.current)
  516. end
  517. # Saves @issue and a time_entry from the parameters
  518. def save_issue_with_child_records
  519. Issue.transaction do
  520. if params[:time_entry] && (params[:time_entry][:hours].present? || params[:time_entry][:comments].present?) && User.current.allowed_to?(:log_time, @issue.project)
  521. time_entry = @time_entry || TimeEntry.new
  522. time_entry.project = @issue.project
  523. time_entry.issue = @issue
  524. time_entry.user = User.current
  525. time_entry.spent_on = User.current.today
  526. time_entry.safe_attributes = params[:time_entry]
  527. @issue.time_entries << time_entry
  528. end
  529. call_hook(:controller_issues_edit_before_save, { :params => params, :issue => @issue, :time_entry => time_entry, :journal => @issue.current_journal})
  530. if @issue.save
  531. call_hook(:controller_issues_edit_after_save, { :params => params, :issue => @issue, :time_entry => time_entry, :journal => @issue.current_journal})
  532. else
  533. raise ActiveRecord::Rollback
  534. end
  535. end
  536. end
  537. # Returns true if the issue copy should be linked
  538. # to the original issue
  539. def link_copy?(param)
  540. case Setting.link_copied_issue
  541. when 'yes'
  542. true
  543. when 'no'
  544. false
  545. when 'ask'
  546. param == '1'
  547. end
  548. end
  549. # Redirects user after a successful issue creation
  550. def redirect_after_create
  551. if params[:continue]
  552. url_params = {}
  553. url_params[:issue] = {:tracker_id => @issue.tracker, :parent_issue_id => @issue.parent_issue_id}.reject {|k,v| v.nil?}
  554. url_params[:back_url] = params[:back_url].presence
  555. if params[:project_id]
  556. redirect_to new_project_issue_path(@issue.project, url_params)
  557. else
  558. url_params[:issue].merge! :project_id => @issue.project_id
  559. redirect_to new_issue_path(url_params)
  560. end
  561. else
  562. redirect_back_or_default issue_path(@issue)
  563. end
  564. end
  565. end