diff app/models/issue.rb @ 909:cbb26bc654de redmine-1.3

Update to Redmine 1.3-stable branch (Redmine SVN rev 8964)
author Chris Cannam
date Fri, 24 Feb 2012 19:09:32 +0000
parents 0c939c159af4
children 5e80956cc792 433d4f72a19b
line wrap: on
line diff
--- a/app/models/issue.rb	Fri Feb 24 18:36:29 2012 +0000
+++ b/app/models/issue.rb	Fri Feb 24 19:09:32 2012 +0000
@@ -22,7 +22,7 @@
   belongs_to :tracker
   belongs_to :status, :class_name => 'IssueStatus', :foreign_key => 'status_id'
   belongs_to :author, :class_name => 'User', :foreign_key => 'author_id'
-  belongs_to :assigned_to, :class_name => 'User', :foreign_key => 'assigned_to_id'
+  belongs_to :assigned_to, :class_name => 'Principal', :foreign_key => 'assigned_to_id'
   belongs_to :fixed_version, :class_name => 'Version', :foreign_key => 'fixed_version_id'
   belongs_to :priority, :class_name => 'IssuePriority', :foreign_key => 'priority_id'
   belongs_to :category, :class_name => 'IssueCategory', :foreign_key => 'category_id'
@@ -35,7 +35,7 @@
   has_many :relations_to, :class_name => 'IssueRelation', :foreign_key => 'issue_to_id', :dependent => :delete_all
 
   acts_as_nested_set :scope => 'root_id', :dependent => :destroy
-  acts_as_attachable :after_remove => :attachment_removed
+  acts_as_attachable :after_add => :attachment_added, :after_remove => :attachment_removed
   acts_as_customizable
   acts_as_watchable
   acts_as_searchable :columns => ['subject', "#{table_name}.description", "#{Journal.table_name}.notes"],
@@ -58,6 +58,7 @@
   validates_length_of :subject, :maximum => 255
   validates_inclusion_of :done_ratio, :in => 0..100
   validates_numericality_of :estimated_hours, :allow_nil => true
+  validate :validate_issue
 
   named_scope :visible, lambda {|*args| { :include => :project,
                                           :conditions => Issue.visible_condition(args.shift || User.current, *args) } }
@@ -93,9 +94,11 @@
       when 'all'
         nil
       when 'default'
-        "(#{table_name}.is_private = #{connection.quoted_false} OR #{table_name}.author_id = #{user.id} OR #{table_name}.assigned_to_id = #{user.id})"
+        user_ids = [user.id] + user.groups.map(&:id)
+        "(#{table_name}.is_private = #{connection.quoted_false} OR #{table_name}.author_id = #{user.id} OR #{table_name}.assigned_to_id IN (#{user_ids.join(',')}))"
       when 'own'
-        "(#{table_name}.author_id = #{user.id} OR #{table_name}.assigned_to_id = #{user.id})"
+        user_ids = [user.id] + user.groups.map(&:id)
+        "(#{table_name}.author_id = #{user.id} OR #{table_name}.assigned_to_id IN (#{user_ids.join(',')}))"
       else
         '1=0'
       end
@@ -109,9 +112,9 @@
       when 'all'
         true
       when 'default'
-        !self.is_private? || self.author == user || self.assigned_to == user
+        !self.is_private? || self.author == user || user.is_or_belongs_to?(assigned_to)
       when 'own'
-        self.author == user || self.assigned_to == user
+        self.author == user || user.is_or_belongs_to?(assigned_to)
       else
         false
       end
@@ -227,7 +230,7 @@
     @custom_field_values = nil
     result
   end
-  
+
   def description=(arg)
     if arg.is_a?(String)
       arg = arg.gsub(/(\r\n|\n|\r)/, "\r\n")
@@ -335,7 +338,7 @@
     Setting.issue_done_ratio == 'issue_field'
   end
 
-  def validate
+  def validate_issue
     if self.due_date.nil? && @attributes['due_date'] && !@attributes['due_date'].empty?
       errors.add :due_date, :not_a_date
     end
@@ -352,7 +355,7 @@
       if !assignable_versions.include?(fixed_version)
         errors.add :fixed_version_id, :inclusion
       elsif reopened? && fixed_version.closed?
-        errors.add_to_base I18n.t(:error_can_not_reopen_issue_on_closed_version)
+        errors.add :base, I18n.t(:error_can_not_reopen_issue_on_closed_version)
       end
     end
 
@@ -449,6 +452,7 @@
   def assignable_users
     users = project.assignable_users
     users << author if author
+    users << assigned_to if assigned_to
     users.uniq.sort
   end
 
@@ -482,7 +486,13 @@
     # Author and assignee are always notified unless they have been
     # locked or don't want to be notified
     notified << author if author && author.active? && author.notify_about?(self)
-    notified << assigned_to if assigned_to && assigned_to.active? && assigned_to.notify_about?(self)
+    if assigned_to
+      if assigned_to.is_a?(Group)
+        notified += assigned_to.users.select {|u| u.active? && u.notify_about?(self)}
+      else
+        notified << assigned_to if assigned_to.active? && assigned_to.notify_about?(self)
+      end
+    end
     notified.uniq!
     # Remove users that can not view the issue
     notified.reject! {|user| !visible?(user)}
@@ -499,7 +509,22 @@
   end
 
   def relations
-    (relations_from + relations_to).sort
+    @relations ||= (relations_from + relations_to).sort
+  end
+
+  # Preloads relations for a collection of issues
+  def self.load_relations(issues)
+    if issues.any?
+      relations = IssueRelation.all(:conditions => ["issue_from_id IN (:ids) OR issue_to_id IN (:ids)", {:ids => issues.map(&:id)}])
+      issues.each do |issue|
+        issue.instance_variable_set "@relations", relations.select {|r| r.issue_from_id == issue.id || r.issue_to_id == issue.id}
+      end
+    end
+  end
+
+  # Finds an issue relation given its id.
+  def find_relation(relation_id)
+    IssueRelation.find(relation_id, :conditions => ["issue_to_id = ? OR issue_from_id = ?", id, id])
   end
 
   def all_dependent_issues(except=[])
@@ -591,15 +616,13 @@
         @time_entry.project = project
         @time_entry.issue = self
         @time_entry.user = User.current
-        @time_entry.spent_on = Date.today
+        @time_entry.spent_on = User.current.today
         @time_entry.attributes = params[:time_entry]
         self.time_entries << @time_entry
       end
 
       if valid?
         attachments = Attachment.attach_files(self, params[:attachments])
-
-        attachments[:files].each {|a| @current_journal.details << JournalDetail.new(:property => 'attachment', :prop_key => a.id, :value => a.filename)}
         # TODO: Rename hook
         Redmine::Hook.call_hook(:controller_issues_edit_before_save, { :params => params, :issue => self, :time_entry => @time_entry, :journal => @current_journal})
         begin
@@ -611,7 +634,7 @@
           end
         rescue ActiveRecord::StaleObjectError
           attachments[:files].each(&:destroy)
-          errors.add_to_base l(:notice_locking_conflict)
+          errors.add :base, l(:notice_locking_conflict)
           raise ActiveRecord::Rollback
         end
       end
@@ -830,6 +853,13 @@
   end
 
   # Callback on attachment deletion
+  def attachment_added(obj)
+    if @current_journal && !obj.new_record?
+      @current_journal.details << JournalDetail.new(:property => 'attachment', :prop_key => obj.id, :value => obj.filename)
+    end
+  end
+
+  # Callback on attachment deletion
   def attachment_removed(obj)
     journal = init_journal(User.current)
     journal.details << JournalDetail.new(:property => 'attachment',