2008-09-11 21:03:26 +04:00
# Redmine - project management software
# Copyright (C) 2006-2008 Jean-Philippe Lang
2007-03-12 20:59:02 +03:00
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
class IssuesController < ApplicationController
2008-01-20 16:07:19 +03:00
menu_item :new_issue , :only = > :new
2009-10-21 21:07:18 +04:00
default_search_scope :issues
2008-01-20 16:07:19 +03:00
2010-02-24 20:21:41 +03:00
before_filter :find_issue , :only = > [ :show , :edit , :update , :reply ]
2008-02-10 16:17:41 +03:00
before_filter :find_issues , :only = > [ :bulk_edit , :move , :destroy ]
2008-12-05 18:41:32 +03:00
before_filter :find_project , :only = > [ :new , :update_form , :preview ]
2009-11-29 22:46:40 +03:00
before_filter :authorize , :except = > [ :index , :changes , :gantt , :calendar , :preview , :context_menu ]
2008-12-05 18:41:32 +03:00
before_filter :find_optional_project , :only = > [ :index , :changes , :gantt , :calendar ]
2009-05-17 12:35:57 +04:00
accept_key_auth :index , :show , :changes
2007-03-12 20:59:02 +03:00
2009-11-28 13:29:48 +03:00
rescue_from Query :: StatementInvalid , :with = > :query_statement_invalid
2008-02-02 13:50:31 +03:00
helper :journals
2007-06-13 03:07:00 +04:00
helper :projects
include ProjectsHelper
2007-03-12 20:59:02 +03:00
helper :custom_fields
include CustomFieldsHelper
2007-05-05 17:22:27 +04:00
helper :issue_relations
include IssueRelationsHelper
2007-05-13 23:43:35 +04:00
helper :watchers
include WatchersHelper
2007-05-26 19:42:37 +04:00
helper :attachments
2007-08-31 21:02:44 +04:00
include AttachmentsHelper
helper :queries
2010-01-18 21:00:27 +03:00
include QueriesHelper
2007-08-31 21:02:44 +04:00
helper :sort
include SortHelper
2007-11-05 21:38:42 +03:00
include IssuesHelper
2008-06-29 16:01:20 +04:00
helper :timelog
2009-01-04 15:03:39 +03:00
include Redmine :: Export :: PDF
2006-09-09 20:07:02 +04:00
2010-01-13 22:29:19 +03:00
verify :method = > [ :post , :delete ] ,
2009-10-25 16:38:48 +03:00
:only = > :destroy ,
:render = > { :nothing = > true , :status = > :method_not_allowed }
2010-03-01 21:29:18 +03:00
verify :method = > :put , :only = > :update , :render = > { :nothing = > true , :status = > :method_not_allowed }
2007-08-31 21:02:44 +04:00
def index
retrieve_query
2009-03-12 21:06:54 +03:00
sort_init ( @query . sort_criteria . empty? ? [ [ 'id' , 'desc' ] ] : @query . sort_criteria )
2009-04-04 14:00:22 +04:00
sort_update ( { 'id' = > " #{ Issue . table_name } .id " } . merge ( @query . available_columns . inject ( { } ) { | h , c | h [ c . name . to_s ] = c . sortable ; h } ) )
2008-12-24 13:03:13 +03:00
2007-08-31 21:02:44 +04:00
if @query . valid?
2010-02-04 22:58:42 +03:00
limit = case params [ :format ]
when 'csv' , 'pdf'
Setting . issues_export_limit . to_i
when 'atom'
Setting . feeds_limit . to_i
else
per_page_option
2008-03-05 11:25:22 +03:00
end
2009-11-28 13:08:29 +03:00
@issue_count = @query . issue_count
2007-11-05 21:38:42 +03:00
@issue_pages = Paginator . new self , @issue_count , limit , params [ 'page' ]
2009-11-28 13:08:29 +03:00
@issues = @query . issues ( :include = > [ :assigned_to , :tracker , :priority , :category , :fixed_version ] ,
:order = > sort_clause ,
:offset = > @issue_pages . current . offset ,
:limit = > limit )
@issue_count_by_group = @query . issue_count_by_group
2007-11-05 21:38:42 +03:00
respond_to do | format |
2009-11-28 13:08:29 +03:00
format . html { render :template = > 'issues/index.rhtml' , :layout = > ! request . xhr? }
2010-01-13 22:29:19 +03:00
format . xml { render :layout = > false }
2008-07-06 17:47:59 +04:00
format . atom { render_feed ( @issues , :title = > " #{ @project || Setting . app_title } : #{ l ( :label_issue_plural ) } " ) }
2009-11-04 16:22:26 +03:00
format . csv { send_data ( issues_to_csv ( @issues , @project ) , :type = > 'text/csv; header=present' , :filename = > 'export.csv' ) }
2009-04-26 17:09:14 +04:00
format . pdf { send_data ( issues_to_pdf ( @issues , @project , @query ) , :type = > 'application/pdf' , :filename = > 'export.pdf' ) }
2007-11-05 21:38:42 +03:00
end
else
# Send html if the query is not valid
render ( :template = > 'issues/index.rhtml' , :layout = > ! request . xhr? )
2007-08-31 21:02:44 +04:00
end
2008-03-30 16:29:07 +04:00
rescue ActiveRecord :: RecordNotFound
render_404
2007-11-05 21:38:42 +03:00
end
def changes
retrieve_query
2008-12-24 13:03:13 +03:00
sort_init 'id' , 'desc'
2009-04-04 14:01:31 +04:00
sort_update ( { 'id' = > " #{ Issue . table_name } .id " } . merge ( @query . available_columns . inject ( { } ) { | h , c | h [ c . name . to_s ] = c . sortable ; h } ) )
2008-12-24 13:03:13 +03:00
2007-11-05 21:38:42 +03:00
if @query . valid?
2009-11-28 13:08:29 +03:00
@journals = @query . journals ( :order = > " #{ Journal . table_name } .created_on DESC " ,
:limit = > 25 )
2007-09-01 00:22:36 +04:00
end
2007-11-05 21:38:42 +03:00
@title = ( @project ? @project . name : Setting . app_title ) + " : " + ( @query . new_record? ? l ( :label_changes_details ) : @query . name )
render :layout = > false , :content_type = > 'application/atom+xml'
2008-03-30 16:29:07 +04:00
rescue ActiveRecord :: RecordNotFound
render_404
2007-08-31 21:02:44 +04:00
end
2006-09-09 20:07:02 +04:00
def show
2007-08-14 13:02:40 +04:00
@journals = @issue . journals . find ( :all , :include = > [ :user , :details ] , :order = > " #{ Journal . table_name } .created_on ASC " )
2008-03-05 18:41:54 +03:00
@journals . each_with_index { | j , i | j . indice = i + 1 }
@journals . reverse! if User . current . wants_comments_in_reverse_order?
2010-01-31 19:25:06 +03:00
@changesets = @issue . changesets . visible . all
2009-02-22 18:16:18 +03:00
@changesets . reverse! if User . current . wants_comments_in_reverse_order?
2008-02-09 19:11:18 +03:00
@allowed_statuses = @issue . new_statuses_allowed_to ( User . current )
@edit_allowed = User . current . allowed_to? ( :edit_issues , @project )
2009-05-31 03:30:36 +04:00
@priorities = IssuePriority . all
2008-05-26 21:12:11 +04:00
@time_entry = TimeEntry . new
2007-11-05 21:38:42 +03:00
respond_to do | format |
format . html { render :template = > 'issues/show.rhtml' }
2010-01-13 22:29:19 +03:00
format . xml { render :layout = > false }
2008-03-05 11:25:22 +03:00
format . atom { render :action = > 'changes' , :layout = > false , :content_type = > 'application/atom+xml' }
2009-01-04 15:03:39 +03:00
format . pdf { send_data ( issue_to_pdf ( @issue ) , :type = > 'application/pdf' , :filename = > " #{ @project . identifier } - #{ @issue . id } .pdf " ) }
2007-10-06 03:17:49 +04:00
end
2006-09-09 20:07:02 +04:00
end
2006-06-28 22:11:03 +04:00
2008-01-20 14:30:57 +03:00
# Add a new issue
# The new issue will be created from an existing one if copy_from parameter is given
def new
2008-06-28 00:13:56 +04:00
@issue = Issue . new
@issue . copy_from ( params [ :copy_from ] ) if params [ :copy_from ]
2008-01-20 14:30:57 +03:00
@issue . project = @project
2008-06-30 21:57:53 +04:00
# Tracker must be set before custom field values
@issue . tracker || = @project . trackers . find ( ( params [ :issue ] && params [ :issue ] [ :tracker_id ] ) || params [ :tracker_id ] || :first )
2008-01-20 14:30:57 +03:00
if @issue . tracker . nil?
2009-08-21 23:43:33 +04:00
render_error l ( :error_no_tracker_in_project )
2008-01-20 14:30:57 +03:00
return
end
2008-12-22 22:21:02 +03:00
if params [ :issue ] . is_a? ( Hash )
2010-01-12 23:17:20 +03:00
@issue . safe_attributes = params [ :issue ]
2008-12-22 22:21:02 +03:00
@issue . watcher_user_ids = params [ :issue ] [ 'watcher_user_ids' ] if User . current . allowed_to? ( :add_issue_watchers , @project )
end
2008-06-28 00:13:56 +04:00
@issue . author = User . current
2008-01-20 14:30:57 +03:00
default_status = IssueStatus . default
unless default_status
2009-08-21 23:43:33 +04:00
render_error l ( :error_no_default_issue_status )
2008-01-20 14:30:57 +03:00
return
end
@issue . status = default_status
2009-05-10 14:54:31 +04:00
@allowed_statuses = ( [ default_status ] + default_status . find_new_statuses_allowed_to ( User . current . roles_for_project ( @project ) , @issue . tracker ) ) . uniq
2008-01-20 14:30:57 +03:00
if request . get? || request . xhr?
@issue . start_date || = Date . today
else
requested_status = IssueStatus . find_by_id ( params [ :issue ] [ :status_id ] )
# Check that the user is allowed to apply the requested status
@issue . status = ( @allowed_statuses . include? requested_status ) ? requested_status : default_status
2009-12-30 02:31:24 +03:00
call_hook ( :controller_issues_new_before_save , { :params = > params , :issue = > @issue } )
2008-01-20 14:30:57 +03:00
if @issue . save
attach_files ( @issue , params [ :attachments ] )
2010-02-04 22:57:45 +03:00
flash [ :notice ] = l ( :notice_successful_create )
2009-01-12 07:52:56 +03:00
call_hook ( :controller_issues_new_after_save , { :params = > params , :issue = > @issue } )
2010-01-13 22:29:19 +03:00
respond_to do | format |
format . html {
redirect_to ( params [ :continue ] ? { :action = > 'new' , :tracker_id = > @issue . tracker } :
{ :action = > 'show' , :id = > @issue } )
}
format . xml { render :action = > 'show' , :status = > :created , :location = > url_for ( :controller = > 'issues' , :action = > 'show' , :id = > @issue ) }
end
2008-01-20 14:30:57 +03:00
return
2010-01-13 22:29:19 +03:00
else
respond_to do | format |
format . html { }
format . xml { render ( :xml = > @issue . errors , :status = > :unprocessable_entity ) ; return }
end
end
2010-02-04 22:57:45 +03:00
end
2009-05-31 03:30:36 +04:00
@priorities = IssuePriority . all
2008-01-20 14:30:57 +03:00
render :layout = > ! request . xhr?
end
2008-02-09 19:11:18 +03:00
# Attributes that can be updated on workflow transition (without :edit permission)
# TODO: make it configurable (at least per role)
UPDATABLE_ATTRS_ON_TRANSITION = %w( status_id assigned_to_id fixed_version_id done_ratio ) unless const_defined? ( :UPDATABLE_ATTRS_ON_TRANSITION )
2007-03-12 20:59:02 +03:00
def edit
2010-02-25 20:01:10 +03:00
update_issue_from_params
2008-02-10 16:17:41 +03:00
2010-02-25 20:01:05 +03:00
respond_to do | format |
format . html { }
format . xml { }
end
end
def update
2010-02-25 20:01:10 +03:00
update_issue_from_params
2010-02-25 20:01:05 +03:00
2010-02-26 19:16:18 +03:00
if issue_update
respond_to do | format |
format . html { redirect_back_or_default ( { :action = > 'show' , :id = > @issue } ) }
format . xml { head :ok }
2007-03-12 20:59:02 +03:00
end
2010-02-26 19:16:18 +03:00
else
2010-01-13 22:29:19 +03:00
respond_to do | format |
2010-02-24 20:21:41 +03:00
format . html { render :action = > 'edit' }
2010-01-13 22:29:19 +03:00
format . xml { render :xml = > @issue . errors , :status = > :unprocessable_entity }
end
2008-01-06 20:06:14 +03:00
end
2010-02-26 19:16:18 +03:00
2008-01-06 20:06:14 +03:00
rescue ActiveRecord :: StaleObjectError
# Optimistic locking exception
flash . now [ :error ] = l ( :notice_locking_conflict )
2009-09-12 13:59:38 +04:00
# Remove the previously added attachments if issue was not updated
attachments . each ( & :destroy )
2006-09-09 20:07:02 +04:00
end
2008-05-30 21:42:25 +04:00
def reply
journal = Journal . find ( params [ :journal_id ] ) if params [ :journal_id ]
if journal
user = journal . user
text = journal . notes
else
user = @issue . author
text = @issue . description
end
2008-06-07 15:42:37 +04:00
content = " #{ ll ( Setting . default_language , :text_user_wrote , user ) } \\ n> "
content << text . to_s . strip . gsub ( %r{ <pre>((.| \ s)*?)</pre> }m , '[...]' ) . gsub ( '"' , '\"' ) . gsub ( / ( \ r? \ n| \ r \ n?) / , " \\ n> " ) + " \\ n \\ n "
2008-05-30 21:42:25 +04:00
render ( :update ) { | page |
2008-06-07 15:42:37 +04:00
page . << " $('notes').value = \" #{ content } \" ; "
2008-05-30 21:42:25 +04:00
page . show 'update'
page << " Form.Element.focus('notes'); "
page << " Element.scrollTo('update'); "
page << " $('notes').scrollTop = $('notes').scrollHeight - $('notes').clientHeight; "
}
end
2008-02-10 16:17:41 +03:00
# Bulk edit a set of issues
def bulk_edit
if request . post?
2010-02-24 00:26:29 +03:00
attributes = ( params [ :issue ] || { } ) . reject { | k , v | v . blank? }
attributes . keys . each { | k | attributes [ k ] = '' if attributes [ k ] == 'none' }
attributes [ :custom_field_values ] . reject! { | k , v | v . blank? } if attributes [ :custom_field_values ]
2008-02-10 16:17:41 +03:00
2010-02-24 00:26:29 +03:00
unsaved_issue_ids = [ ]
2008-02-10 16:17:41 +03:00
@issues . each do | issue |
2010-02-24 00:26:29 +03:00
journal = issue . init_journal ( User . current , params [ :notes ] )
issue . safe_attributes = attributes
call_hook ( :controller_issues_bulk_edit_before_save , { :params = > params , :issue = > issue } )
unless issue . save
2008-02-10 16:17:41 +03:00
# Keep unsaved issue ids to display them in flash error
unsaved_issue_ids << issue . id
end
end
if unsaved_issue_ids . empty?
flash [ :notice ] = l ( :notice_successful_update ) unless @issues . empty?
else
2009-02-21 14:04:50 +03:00
flash [ :error ] = l ( :notice_failed_to_save_issues , :count = > unsaved_issue_ids . size ,
:total = > @issues . size ,
:ids = > '#' + unsaved_issue_ids . join ( ', #' ) )
2008-02-10 16:17:41 +03:00
end
2010-01-15 02:24:55 +03:00
redirect_back_or_default ( { :controller = > 'issues' , :action = > 'index' , :project_id = > @project } )
2008-02-10 16:17:41 +03:00
return
end
2009-12-05 01:46:12 +03:00
@available_statuses = Workflow . available_statuses ( @project )
2010-01-03 14:18:09 +03:00
@custom_fields = @project . all_issue_custom_fields
2008-02-10 16:17:41 +03:00
end
def move
2009-12-05 01:46:12 +03:00
@copy = params [ :copy_options ] && params [ :copy_options ] [ :copy ]
2008-02-10 16:17:41 +03:00
@allowed_projects = [ ]
# find projects to which the user is allowed to move the issue
if User . current . admin?
# admin is allowed to move issues to any active (visible) project
2009-01-25 16:52:40 +03:00
@allowed_projects = Project . find ( :all , :conditions = > Project . visible_by ( User . current ) )
2008-02-10 16:17:41 +03:00
else
2009-05-13 19:58:54 +04:00
User . current . memberships . each { | m | @allowed_projects << m . project if m . roles . detect { | r | r . allowed_to? ( :move_issues ) } }
2008-02-10 16:17:41 +03:00
end
@target_project = @allowed_projects . detect { | p | p . id . to_s == params [ :new_project_id ] } if params [ :new_project_id ]
@target_project || = @project
@trackers = @target_project . trackers
2009-12-05 01:46:12 +03:00
@available_statuses = Workflow . available_statuses ( @project )
2008-02-10 16:17:41 +03:00
if request . post?
new_tracker = params [ :new_tracker_id ] . blank? ? nil : @target_project . trackers . find_by_id ( params [ :new_tracker_id ] )
unsaved_issue_ids = [ ]
2009-11-15 17:31:19 +03:00
moved_issues = [ ]
2008-02-10 16:17:41 +03:00
@issues . each do | issue |
2009-12-05 01:46:12 +03:00
changed_attributes = { }
[ :assigned_to_id , :status_id , :start_date , :due_date ] . each do | valid_attribute |
2009-12-09 19:04:45 +03:00
unless params [ valid_attribute ] . blank?
changed_attributes [ valid_attribute ] = ( params [ valid_attribute ] == 'none' ? nil : params [ valid_attribute ] )
end
2009-12-05 01:46:12 +03:00
end
2008-06-19 22:52:20 +04:00
issue . init_journal ( User . current )
2010-02-19 22:10:50 +03:00
call_hook ( :controller_issues_move_before_save , { :params = > params , :issue = > issue , :target_project = > @target_project , :copy = > ! ! @copy } )
2009-12-05 01:46:12 +03:00
if r = issue . move_to ( @target_project , new_tracker , { :copy = > @copy , :attributes = > changed_attributes } )
2009-11-15 17:31:19 +03:00
moved_issues << r
else
unsaved_issue_ids << issue . id
end
2008-02-10 16:17:41 +03:00
end
if unsaved_issue_ids . empty?
flash [ :notice ] = l ( :notice_successful_update ) unless @issues . empty?
else
2009-02-21 14:04:50 +03:00
flash [ :error ] = l ( :notice_failed_to_save_issues , :count = > unsaved_issue_ids . size ,
:total = > @issues . size ,
:ids = > '#' + unsaved_issue_ids . join ( ', #' ) )
2008-02-10 16:17:41 +03:00
end
2009-11-15 17:31:19 +03:00
if params [ :follow ]
if @issues . size == 1 && moved_issues . size == 1
redirect_to :controller = > 'issues' , :action = > 'show' , :id = > moved_issues . first
else
redirect_to :controller = > 'issues' , :action = > 'index' , :project_id = > ( @target_project || @project )
end
else
redirect_to :controller = > 'issues' , :action = > 'index' , :project_id = > @project
end
2008-02-10 16:17:41 +03:00
return
end
render :layout = > false if request . xhr?
end
2006-09-09 20:07:02 +04:00
def destroy
2008-03-01 01:54:07 +03:00
@hours = TimeEntry . sum ( :hours , :conditions = > [ 'issue_id IN (?)' , @issues ] ) . to_f
if @hours > 0
case params [ :todo ]
when 'destroy'
# nothing to do
when 'nullify'
TimeEntry . update_all ( 'issue_id = NULL' , [ 'issue_id IN (?)' , @issues ] )
when 'reassign'
reassign_to = @project . issues . find_by_id ( params [ :reassign_to_id ] )
if reassign_to . nil?
flash . now [ :error ] = l ( :error_issue_not_found_in_project )
return
else
TimeEntry . update_all ( " issue_id = #{ reassign_to . id } " , [ 'issue_id IN (?)' , @issues ] )
end
else
2010-01-13 22:29:19 +03:00
unless params [ :format ] == 'xml'
# display the destroy form if it's a user request
return
end
2008-03-01 01:54:07 +03:00
end
end
2008-02-10 16:17:41 +03:00
@issues . each ( & :destroy )
2010-01-13 22:29:19 +03:00
respond_to do | format |
format . html { redirect_to :action = > 'index' , :project_id = > @project }
format . xml { head :ok }
end
2007-03-12 20:59:02 +03:00
end
2007-10-28 13:55:59 +03:00
2008-09-10 22:26:13 +04:00
def gantt
@gantt = Redmine :: Helpers :: Gantt . new ( params )
retrieve_query
2010-02-06 21:07:25 +03:00
@query . group_by = nil
2008-09-10 22:26:13 +04:00
if @query . valid?
events = [ ]
# Issues that have start and due dates
2009-11-28 13:08:29 +03:00
events += @query . issues ( :include = > [ :tracker , :assigned_to , :priority ] ,
:order = > " start_date, due_date " ,
:conditions = > [ " (((start_date>=? and start_date<=?) or (due_date>=? and due_date<=?) or (start_date<? and due_date>?)) and start_date is not null and due_date is not null) " , @gantt . date_from , @gantt . date_to , @gantt . date_from , @gantt . date_to , @gantt . date_from , @gantt . date_to ]
)
2008-09-10 22:26:13 +04:00
# Issues that don't have a due date but that are assigned to a version with a date
2009-11-28 13:08:29 +03:00
events += @query . issues ( :include = > [ :tracker , :assigned_to , :priority , :fixed_version ] ,
:order = > " start_date, effective_date " ,
:conditions = > [ " (((start_date>=? and start_date<=?) or (effective_date>=? and effective_date<=?) or (start_date<? and effective_date>?)) and start_date is not null and due_date is null and effective_date is not null) " , @gantt . date_from , @gantt . date_to , @gantt . date_from , @gantt . date_to , @gantt . date_from , @gantt . date_to ]
)
2008-09-11 21:08:00 +04:00
# Versions
2009-11-28 13:08:29 +03:00
events += @query . versions ( :conditions = > [ " effective_date BETWEEN ? AND ? " , @gantt . date_from , @gantt . date_to ] )
2008-09-11 21:08:00 +04:00
2008-09-10 22:26:13 +04:00
@gantt . events = events
end
2009-04-25 13:05:31 +04:00
basename = ( @project ? " #{ @project . identifier } - " : '' ) + 'gantt'
2008-09-10 22:26:13 +04:00
respond_to do | format |
format . html { render :template = > " issues/gantt.rhtml " , :layout = > ! request . xhr? }
2009-04-25 13:05:31 +04:00
format . png { send_data ( @gantt . to_image , :disposition = > 'inline' , :type = > 'image/png' , :filename = > " #{ basename } .png " ) } if @gantt . respond_to? ( 'to_image' )
format . pdf { send_data ( gantt_to_pdf ( @gantt , @project ) , :type = > 'application/pdf' , :filename = > " #{ basename } .pdf " ) }
2008-09-10 22:26:13 +04:00
end
end
2008-09-11 21:03:26 +04:00
def calendar
if params [ :year ] and params [ :year ] . to_i > 1900
@year = params [ :year ] . to_i
if params [ :month ] and params [ :month ] . to_i > 0 and params [ :month ] . to_i < 13
@month = params [ :month ] . to_i
end
end
@year || = Date . today . year
@month || = Date . today . month
@calendar = Redmine :: Helpers :: Calendar . new ( Date . civil ( @year , @month , 1 ) , current_language , :month )
retrieve_query
2010-02-06 21:07:25 +03:00
@query . group_by = nil
2008-09-11 21:03:26 +04:00
if @query . valid?
events = [ ]
2009-11-28 13:08:29 +03:00
events += @query . issues ( :include = > [ :tracker , :assigned_to , :priority ] ,
:conditions = > [ " ((start_date BETWEEN ? AND ?) OR (due_date BETWEEN ? AND ?)) " , @calendar . startdt , @calendar . enddt , @calendar . startdt , @calendar . enddt ]
)
events += @query . versions ( :conditions = > [ " effective_date BETWEEN ? AND ? " , @calendar . startdt , @calendar . enddt ] )
2008-09-11 21:03:26 +04:00
@calendar . events = events
end
render :layout = > false if request . xhr?
end
2007-10-28 13:55:59 +03:00
def context_menu
2008-02-10 16:17:41 +03:00
@issues = Issue . find_all_by_id ( params [ :ids ] , :include = > :project )
if ( @issues . size == 1 )
@issue = @issues . first
@allowed_statuses = @issue . new_statuses_allowed_to ( User . current )
end
projects = @issues . collect ( & :project ) . compact . uniq
@project = projects . first if projects . size == 1
@can = { :edit = > ( @project && User . current . allowed_to? ( :edit_issues , @project ) ) ,
2008-07-16 23:22:09 +04:00
:log_time = > ( @project && User . current . allowed_to? ( :log_time , @project ) ) ,
2008-08-26 14:34:26 +04:00
:update = > ( @project && ( User . current . allowed_to? ( :edit_issues , @project ) || ( User . current . allowed_to? ( :change_status , @project ) && @allowed_statuses && ! @allowed_statuses . empty? ) ) ) ,
2008-02-10 16:17:41 +03:00
:move = > ( @project && User . current . allowed_to? ( :move_issues , @project ) ) ,
:copy = > ( @issue && @project . trackers . include? ( @issue . tracker ) && User . current . allowed_to? ( :add_issues , @project ) ) ,
:delete = > ( @project && User . current . allowed_to? ( :delete_issues , @project ) )
}
2008-08-26 14:34:26 +04:00
if @project
@assignables = @project . assignable_users
@assignables << @issue . assigned_to if @issue && @issue . assigned_to && ! @assignables . include? ( @issue . assigned_to )
2009-11-30 22:18:09 +03:00
@trackers = @project . trackers
2008-08-26 14:34:26 +04:00
end
2009-05-31 03:30:36 +04:00
@priorities = IssuePriority . all . reverse
2007-10-28 13:55:59 +03:00
@statuses = IssueStatus . find ( :all , :order = > 'position' )
2009-11-11 14:35:27 +03:00
@back = params [ :back_url ] || request . env [ 'HTTP_REFERER' ]
2008-02-10 16:17:41 +03:00
2007-10-28 13:55:59 +03:00
render :layout = > false
end
2007-03-12 20:59:02 +03:00
2008-01-20 14:30:57 +03:00
def update_form
2009-12-06 13:37:08 +03:00
if params [ :id ] . blank?
2009-11-29 22:46:40 +03:00
@issue = Issue . new
@issue . project = @project
2009-12-06 13:37:08 +03:00
else
@issue = @project . issues . visible . find ( params [ :id ] )
2009-11-29 22:46:40 +03:00
end
@issue . attributes = params [ :issue ]
@allowed_statuses = ( [ @issue . status ] + @issue . status . find_new_statuses_allowed_to ( User . current . roles_for_project ( @project ) , @issue . tracker ) ) . uniq
@priorities = IssuePriority . all
render :partial = > 'attributes'
2008-01-20 14:30:57 +03:00
end
2007-10-06 12:54:05 +04:00
def preview
2008-04-24 21:35:04 +04:00
@issue = @project . issues . find_by_id ( params [ :id ] ) unless params [ :id ] . blank?
2008-04-09 21:52:41 +04:00
@attachements = @issue . attachments if @issue
2008-02-09 19:11:18 +03:00
@text = params [ :notes ] || ( params [ :issue ] ? params [ :issue ] [ :description ] : nil )
2007-10-06 12:54:05 +04:00
render :partial = > 'common/preview'
end
2007-03-12 20:59:02 +03:00
private
2008-01-20 14:30:57 +03:00
def find_issue
2007-03-12 20:59:02 +03:00
@issue = Issue . find ( params [ :id ] , :include = > [ :project , :tracker , :status , :author , :priority , :category ] )
@project = @issue . project
rescue ActiveRecord :: RecordNotFound
render_404
2007-08-31 21:02:44 +04:00
end
2008-02-10 16:17:41 +03:00
# Filter for bulk operations
def find_issues
@issues = Issue . find_all_by_id ( params [ :id ] || params [ :ids ] )
raise ActiveRecord :: RecordNotFound if @issues . empty?
projects = @issues . collect ( & :project ) . compact . uniq
if projects . size == 1
@project = projects . first
else
# TODO: let users bulk edit/move/destroy issues from different projects
2009-12-18 17:22:18 +03:00
render_error 'Can not bulk edit/move/destroy issues from different projects'
return false
2008-02-10 16:17:41 +03:00
end
rescue ActiveRecord :: RecordNotFound
render_404
end
2008-01-20 14:30:57 +03:00
def find_project
2010-01-13 22:29:19 +03:00
project_id = ( params [ :issue ] && params [ :issue ] [ :project_id ] ) || params [ :project_id ]
@project = Project . find ( project_id )
2008-01-20 14:30:57 +03:00
rescue ActiveRecord :: RecordNotFound
render_404
end
2007-11-05 21:38:42 +03:00
def find_optional_project
2008-12-05 18:41:32 +03:00
@project = Project . find ( params [ :project_id ] ) unless params [ :project_id ] . blank?
allowed = User . current . allowed_to? ( { :controller = > params [ :controller ] , :action = > params [ :action ] } , @project , :global = > true )
allowed ? true : deny_access
2007-11-05 21:38:42 +03:00
rescue ActiveRecord :: RecordNotFound
render_404
end
2007-08-31 21:02:44 +04:00
# Retrieve query from session or build a new query
def retrieve_query
2008-02-02 13:54:31 +03:00
if ! params [ :query_id ] . blank?
2008-03-30 16:29:07 +04:00
cond = " project_id IS NULL "
cond << " OR project_id = #{ @project . id } " if @project
@query = Query . find ( params [ :query_id ] , :conditions = > cond )
@query . project = @project
2007-12-30 13:46:09 +03:00
session [ :query ] = { :id = > @query . id , :project_id = > @query . project_id }
2009-03-12 21:06:54 +03:00
sort_clear
2007-11-05 21:38:42 +03:00
else
2010-01-18 22:53:06 +03:00
if api_request? || params [ :set_filter ] || session [ :query ] . nil? || session [ :query ] [ :project_id ] != ( @project ? @project . id : nil )
2007-11-05 21:38:42 +03:00
# Give it a name, required to be valid
2007-11-20 18:40:16 +03:00
@query = Query . new ( :name = > " _ " )
2007-11-05 21:38:42 +03:00
@query . project = @project
if params [ :fields ] and params [ :fields ] . is_a? Array
params [ :fields ] . each do | field |
@query . add_filter ( field , params [ :operators ] [ field ] , params [ :values ] [ field ] )
end
else
@query . available_filters . keys . each do | field |
@query . add_short_filter ( field , params [ field ] ) if params [ field ]
end
2007-08-31 21:02:44 +04:00
end
2009-04-26 17:09:14 +04:00
@query . group_by = params [ :group_by ]
2009-11-28 14:34:12 +03:00
@query . column_names = params [ :query ] && params [ :query ] [ :column_names ]
session [ :query ] = { :project_id = > @query . project_id , :filters = > @query . filters , :group_by = > @query . group_by , :column_names = > @query . column_names }
2007-08-31 21:02:44 +04:00
else
2007-12-30 13:46:09 +03:00
@query = Query . find_by_id ( session [ :query ] [ :id ] ) if session [ :query ] [ :id ]
2009-11-28 14:34:12 +03:00
@query || = Query . new ( :name = > " _ " , :project = > @project , :filters = > session [ :query ] [ :filters ] , :group_by = > session [ :query ] [ :group_by ] , :column_names = > session [ :query ] [ :column_names ] )
2008-04-14 23:21:58 +04:00
@query . project = @project
2007-08-31 21:02:44 +04:00
end
end
end
2009-11-28 13:29:48 +03:00
# Rescues an invalid query statement. Just in case...
def query_statement_invalid ( exception )
logger . error " Query::StatementInvalid: #{ exception . message } " if logger
session . delete ( :query )
sort_clear
render_error " An error occurred while executing the query and has been logged. Please report this error to your Redmine administrator. "
end
2010-02-25 20:01:10 +03:00
# Used by #edit and #update to set some common instance variables
# from the params
# TODO: Refactor, not everything in here is needed by #edit
def update_issue_from_params
@allowed_statuses = @issue . new_statuses_allowed_to ( User . current )
@priorities = IssuePriority . all
@edit_allowed = User . current . allowed_to? ( :edit_issues , @project )
@time_entry = TimeEntry . new
@notes = params [ :notes ]
@journal = @issue . init_journal ( User . current , @notes )
# User can change issue attributes only if he has :edit permission or if a workflow transition is allowed
if ( @edit_allowed || ! @allowed_statuses . empty? ) && params [ :issue ]
attrs = params [ :issue ] . dup
attrs . delete_if { | k , v | ! UPDATABLE_ATTRS_ON_TRANSITION . include? ( k ) } unless @edit_allowed
attrs . delete ( :status_id ) unless @allowed_statuses . detect { | s | s . id . to_s == attrs [ :status_id ] . to_s }
@issue . safe_attributes = attrs
end
end
2010-02-26 19:16:18 +03:00
# TODO: Temporary utility method for #update. Should be split off
# and moved to the Issue model (accepts_nested_attributes_for maybe?)
# TODO: move attach_files to the model so this can be moved to the
# model also
def issue_update
2010-03-01 20:40:54 +03:00
if params [ :time_entry ] && params [ :time_entry ] [ :hours ] . present? && User . current . allowed_to? ( :log_time , @project )
@time_entry = TimeEntry . new ( :project = > @project , :issue = > @issue , :user = > User . current , :spent_on = > Date . today )
@time_entry . attributes = params [ :time_entry ]
@issue . time_entries << @time_entry
end
if @issue . valid?
2010-02-26 19:16:18 +03:00
attachments = attach_files ( @issue , params [ :attachments ] )
attachments . each { | a | @journal . details << JournalDetail . new ( :property = > 'attachment' , :prop_key = > a . id , :value = > a . filename ) }
call_hook ( :controller_issues_edit_before_save , { :params = > params , :issue = > @issue , :time_entry = > @time_entry , :journal = > @journal } )
if @issue . save
if ! @journal . new_record?
# Only send notification if something was actually changed
flash [ :notice ] = l ( :notice_successful_update )
end
call_hook ( :controller_issues_edit_after_save , { :params = > params , :issue = > @issue , :time_entry = > @time_entry , :journal = > @journal } )
return true
end
end
# failure, returns false
end
2006-06-28 22:11:03 +04:00
end