diff app/models/user.rb @ 37:94944d00e43c

* Update to SVN trunk rev 4411
author Chris Cannam <chris.cannam@soundsoftware.ac.uk>
date Fri, 19 Nov 2010 13:24:41 +0000
parents 40f7cfd4df19
children bbb139d5ca95 af80e5618e9b 8661b858af72
line wrap: on
line diff
--- a/app/models/user.rb	Fri Sep 24 14:06:04 2010 +0100
+++ b/app/models/user.rb	Fri Nov 19 13:24:41 2010 +0000
@@ -33,6 +33,15 @@
     :username => '#{login}'
   }
 
+  MAIL_NOTIFICATION_OPTIONS = [
+                               [:all, :label_user_mail_option_all],
+                               [:selected, :label_user_mail_option_selected],
+                               [:none, :label_user_mail_option_none],
+                               [:only_my_events, :label_user_mail_option_only_my_events],
+                               [:only_assigned, :label_user_mail_option_only_assigned],
+                               [:only_owner, :label_user_mail_option_only_owner]
+                              ]
+
   has_and_belongs_to_many :groups, :after_add => Proc.new {|user, group| group.user_added(user)},
                                    :after_remove => Proc.new {|user, group| group.user_removed(user)}
   has_many :issue_categories, :foreign_key => 'assigned_to_id', :dependent => :nullify
@@ -65,7 +74,7 @@
   validates_confirmation_of :password, :allow_nil => true
 
   def before_create
-    self.mail_notification = false
+    self.mail_notification = Setting.default_notification_option if self.mail_notification.blank?
     true
   end
   
@@ -250,6 +259,17 @@
     notified_projects_ids
   end
 
+  # Only users that belong to more than 1 project can select projects for which they are notified
+  def valid_notification_options
+    # Note that @user.membership.size would fail since AR ignores
+    # :include association option when doing a count
+    if memberships.length < 1
+      MAIL_NOTIFICATION_OPTIONS.delete_if {|option| option.first == :selected}
+    else
+      MAIL_NOTIFICATION_OPTIONS
+    end
+  end
+
   # Find a user account by matching the exact login and then a case-insensitive
   # version.  Exact matches will be given priority.
   def self.find_by_login(login)
@@ -324,23 +344,35 @@
     !roles_for_project(project).detect {|role| role.member?}.nil?
   end
   
-  # Return true if the user is allowed to do the specified action on project
-  # action can be:
+  # Return true if the user is allowed to do the specified action on a specific context
+  # Action can be:
   # * a parameter-like Hash (eg. :controller => 'projects', :action => 'edit')
   # * a permission Symbol (eg. :edit_project)
-  def allowed_to?(action, project, options={})
-    if project
+  # Context can be:
+  # * a project : returns true if user is allowed to do the specified action on this project
+  # * a group of projects : returns true if user is allowed on every project
+  # * nil with options[:global] set : check if user has at least one role allowed for this action, 
+  #   or falls back to Non Member / Anonymous permissions depending if the user is logged
+  def allowed_to?(action, context, options={})
+    if context && context.is_a?(Project)
       # No action allowed on archived projects
-      return false unless project.active?
+      return false unless context.active?
       # No action allowed on disabled modules
-      return false unless project.allows_to?(action)
+      return false unless context.allows_to?(action)
       # Admin users are authorized for anything else
       return true if admin?
       
-      roles = roles_for_project(project)
+      roles = roles_for_project(context)
       return false unless roles
-      roles.detect {|role| (project.is_public? || role.member?) && role.allowed_to?(action)}
+      roles.detect {|role| (context.is_public? || role.member?) && role.allowed_to?(action)}
       
+    elsif context && context.is_a?(Array)
+      # Authorize if user is authorized on every element of the array
+      context.map do |project|
+        allowed_to?(action,project,options)
+      end.inject do |memo,allowed|
+        memo && allowed
+      end
     elsif options[:global]
       # Admin users are always authorized
       return true if admin?
@@ -359,6 +391,41 @@
     allowed_to?(action, nil, options.reverse_merge(:global => true))
   end
   
+  # Utility method to help check if a user should be notified about an
+  # event.
+  #
+  # TODO: only supports Issue events currently
+  def notify_about?(object)
+    case mail_notification.to_sym
+    when :all
+      true
+    when :selected
+      # Handled by the Project
+    when :none
+      false
+    when :only_my_events
+      if object.is_a?(Issue) && (object.author == self || object.assigned_to == self)
+        true
+      else
+        false
+      end
+    when :only_assigned
+      if object.is_a?(Issue) && object.assigned_to == self
+        true
+      else
+        false
+      end
+    when :only_owner
+      if object.is_a?(Issue) && object.author == self
+        true
+      else
+        false
+      end
+    else
+      false
+    end
+  end
+  
   def self.current=(user)
     @current_user = user
   end