Index: app/controllers/issues_controller.rb =================================================================== --- app/controllers/issues_controller.rb (revision 2034) +++ app/controllers/issues_controller.rb (working copy) @@ -5,19 +5,19 @@ # 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 menu_item :new_issue, :only => :new - + before_filter :find_issue, :only => [:show, :edit, :reply, :destroy_attachment] before_filter :find_issues, :only => [:bulk_edit, :move, :destroy] before_filter :find_project, :only => [:new, :update_form, :preview, :gantt, :calendar] @@ -27,7 +27,7 @@ helper :journals helper :projects - include ProjectsHelper + include ProjectsHelper helper :custom_fields include CustomFieldsHelper helper :ifpdf @@ -76,7 +76,7 @@ rescue ActiveRecord::RecordNotFound render_404 end - + def changes sort_init "#{Issue.table_name}.id", "desc" sort_update @@ -92,7 +92,7 @@ rescue ActiveRecord::RecordNotFound render_404 end - + def show @journals = @issue.journals.find(:all, :include => [:user, :details], :order => "#{Journal.table_name}.created_on ASC") @journals.each_with_index {|j,i| j.indice = i+1} @@ -123,16 +123,16 @@ end @issue.attributes = params[:issue] @issue.author = User.current - + default_status = IssueStatus.default unless default_status flash.now[:error] = 'No default issue status is defined. Please check your configuration (Go to "Administration -> Issue statuses").' render :nothing => true, :layout => true return - end + end @issue.status = default_status @allowed_statuses = ([default_status] + default_status.find_new_statuses_allowed_to(User.current.role_for_project(@project), @issue.tracker)).uniq - + if request.get? || request.xhr? @issue.start_date ||= Date.today else @@ -145,22 +145,22 @@ Mailer.deliver_issue_add(@issue) if Setting.notified_events.include?('issue_added') redirect_to :controller => 'issues', :action => 'show', :id => @issue return - end - end + end + end @priorities = Enumeration::get_values('IPRI') render :layout => !request.xhr? end - + # 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) - + def edit @allowed_statuses = @issue.new_statuses_allowed_to(User.current) @priorities = Enumeration::get_values('IPRI') @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 @@ -174,12 +174,15 @@ if request.post? @time_entry = TimeEntry.new(:project => @project, :issue => @issue, :user => User.current, :spent_on => Date.today) @time_entry.attributes = params[:time_entry] + @time_entry.comments = @time_entry.comments.strip unless @time_entry.comments.nil? attachments = attach_files(@issue, params[:attachments]) attachments.each {|a| journal.details << JournalDetail.new(:property => 'attachment', :prop_key => a.id, :value => a.filename)} if (@time_entry.hours.nil? || @time_entry.valid?) && @issue.save # Log spend time if current_role.allowed_to?(:log_time) - @time_entry.save + not_save = (@time_entry.hours.nil? or @time_entry.hours.zero?) + not_save = (not_save and (@time_entry.comments.nil? or @time_entry.comments.empty?)) + @time_entry.save unless not_save end if !journal.new_record? # Only send notification if something was actually changed @@ -213,7 +216,7 @@ page << "$('notes').scrollTop = $('notes').scrollHeight - $('notes').clientHeight;" } end - + # Bulk edit a set of issues def bulk_edit if request.post? @@ -222,8 +225,8 @@ assigned_to = (params[:assigned_to_id].blank? || params[:assigned_to_id] == 'none') ? nil : User.find_by_id(params[:assigned_to_id]) category = (params[:category_id].blank? || params[:category_id] == 'none') ? nil : @project.issue_categories.find_by_id(params[:category_id]) fixed_version = (params[:fixed_version_id].blank? || params[:fixed_version_id] == 'none') ? nil : @project.versions.find_by_id(params[:fixed_version_id]) - - unsaved_issue_ids = [] + + unsaved_issue_ids = [] @issues.each do |issue| journal = issue.init_journal(User.current, params[:notes]) issue.priority = priority if priority @@ -266,7 +269,7 @@ User.current.memberships.each {|m| @allowed_projects << m.project if m.role.allowed_to?(:move_issues)} end @target_project = @allowed_projects.detect {|p| p.id.to_s == params[:new_project_id]} if params[:new_project_id] - @target_project ||= @project + @target_project ||= @project @trackers = @target_project.trackers if request.post? new_tracker = params[:new_tracker_id].blank? ? nil : @target_project.trackers.find_by_id(params[:new_tracker_id]) @@ -285,7 +288,7 @@ end render :layout => false if request.xhr? end - + def destroy @hours = TimeEntry.sum(:hours, :conditions => ['issue_id IN (?)', @issues]).to_f if @hours > 0 @@ -321,65 +324,65 @@ journal.save redirect_to :action => 'show', :id => @issue end - + def gantt @gantt = Redmine::Helpers::Gantt.new(params) retrieve_query if @query.valid? events = [] # Issues that have start and due dates - events += Issue.find(:all, + events += Issue.find(:all, :order => "start_date, due_date", - :include => [:tracker, :status, :assigned_to, :priority, :project], + :include => [:tracker, :status, :assigned_to, :priority, :project], :conditions => ["(#{@query.statement}) AND (((start_date>=? and start_date<=?) or (due_date>=? and due_date<=?) or (start_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] ) # Issues that don't have a due date but that are assigned to a version with a date - events += Issue.find(:all, + events += Issue.find(:all, :order => "start_date, effective_date", - :include => [:tracker, :status, :assigned_to, :priority, :project, :fixed_version], + :include => [:tracker, :status, :assigned_to, :priority, :project, :fixed_version], :conditions => ["(#{@query.statement}) AND (((start_date>=? and start_date<=?) or (effective_date>=? and effective_date<=?) or (start_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] ) # Versions events += Version.find(:all, :include => :project, :conditions => ["(#{@query.project_statement}) AND effective_date BETWEEN ? AND ?", @gantt.date_from, @gantt.date_to]) - + @gantt.events = events end - + respond_to do |format| format.html { render :template => "issues/gantt.rhtml", :layout => !request.xhr? } format.png { send_data(@gantt.to_image, :disposition => 'inline', :type => 'image/png', :filename => "#{@project.identifier}-gantt.png") } if @gantt.respond_to?('to_image') format.pdf { send_data(render(:template => "issues/gantt.rfpdf", :layout => false), :type => 'application/pdf', :filename => "#{@project.identifier}-gantt.pdf") } end end - + 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 end @year ||= Date.today.year @month ||= Date.today.month - + @calendar = Redmine::Helpers::Calendar.new(Date.civil(@year, @month, 1), current_language, :month) retrieve_query if @query.valid? events = [] - events += Issue.find(:all, - :include => [:tracker, :status, :assigned_to, :priority, :project], + events += Issue.find(:all, + :include => [:tracker, :status, :assigned_to, :priority, :project], :conditions => ["(#{@query.statement}) AND ((start_date BETWEEN ? AND ?) OR (due_date BETWEEN ? AND ?))", @calendar.startdt, @calendar.enddt, @calendar.startdt, @calendar.enddt] ) events += Version.find(:all, :include => :project, :conditions => ["(#{@query.project_statement}) AND effective_date BETWEEN ? AND ?", @calendar.startdt, @calendar.enddt]) - + @calendar.events = events end - + render :layout => false if request.xhr? end - + def context_menu @issues = Issue.find_all_by_id(params[:ids], :include => :project) if (@issues.size == 1) @@ -400,11 +403,11 @@ @assignables = @project.assignable_users @assignables << @issue.assigned_to if @issue && @issue.assigned_to && !@assignables.include?(@issue.assigned_to) end - + @priorities = Enumeration.get_values('IPRI').reverse @statuses = IssueStatus.find(:all, :order => 'position') @back = request.env['HTTP_REFERER'] - + render :layout => false end @@ -412,14 +415,14 @@ @issue = Issue.new(params[:issue]) render :action => :new, :layout => false end - + def preview @issue = @project.issues.find_by_id(params[:id]) unless params[:id].blank? @attachements = @issue.attachments if @issue @text = params[:notes] || (params[:issue] ? params[:issue][:description] : nil) render :partial => 'common/preview' end - + private def find_issue @issue = Issue.find(params[:id], :include => [:project, :tracker, :status, :author, :priority, :category]) @@ -427,7 +430,7 @@ rescue ActiveRecord::RecordNotFound render_404 end - + # Filter for bulk operations def find_issues @issues = Issue.find_all_by_id(params[:id] || params[:ids]) @@ -442,13 +445,13 @@ rescue ActiveRecord::RecordNotFound render_404 end - + def find_project @project = Project.find(params[:project_id]) rescue ActiveRecord::RecordNotFound render_404 end - + def find_optional_project return true unless params[:project_id] @project = Project.find(params[:project_id]) @@ -456,7 +459,7 @@ rescue ActiveRecord::RecordNotFound render_404 end - + # Retrieve query from session or build a new query def retrieve_query if !params[:query_id].blank?