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 23KB

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