diff options
61 files changed, 249 insertions, 41 deletions
diff --git a/app/controllers/reports_controller.rb b/app/controllers/reports_controller.rb index 0d4715078..1b5d2ccbc 100644 --- a/app/controllers/reports_controller.rb +++ b/app/controllers/reports_controller.rb @@ -1,5 +1,5 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang +# Redmine - project management software +# Copyright (C) 2006-2011 Jean-Philippe Lang # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License @@ -24,8 +24,8 @@ class ReportsController < ApplicationController @versions = @project.shared_versions.sort @priorities = IssuePriority.all @categories = @project.issue_categories - @assignees = @project.members.collect { |m| m.user }.sort - @authors = @project.members.collect { |m| m.user }.sort + @assignees = (Setting.issue_group_assignment? ? @project.principals : @project.users).sort + @authors = @project.users.sort @subprojects = @project.descendants.visible @issues_by_tracker = Issue.by_tracker(@project) @@ -63,12 +63,12 @@ class ReportsController < ApplicationController @report_title = l(:field_category) when "assigned_to" @field = "assigned_to_id" - @rows = @project.members.collect { |m| m.user }.sort + @rows = (Setting.issue_group_assignment? ? @project.principals : @project.users).sort @data = Issue.by_assigned_to(@project) @report_title = l(:field_assigned_to) when "author" @field = "author_id" - @rows = @project.members.collect { |m| m.user }.sort + @rows = @project.users.sort @data = Issue.by_author(@project) @report_title = l(:field_author) when "subproject" diff --git a/app/models/group.rb b/app/models/group.rb index 1b55c2566..f3721f7fd 100644 --- a/app/models/group.rb +++ b/app/models/group.rb @@ -1,5 +1,5 @@ # Redmine - project management software -# Copyright (C) 2006-2009 Jean-Philippe Lang +# Copyright (C) 2006-2011 Jean-Philippe Lang # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License @@ -24,11 +24,15 @@ class Group < Principal validates_presence_of :lastname validates_uniqueness_of :lastname, :case_sensitive => false validates_length_of :lastname, :maximum => 30 - + + before_destroy :remove_references_before_destroy + def to_s lastname.to_s end + alias :name :to_s + def user_added(user) members.each do |member| next if member.project.nil? @@ -46,4 +50,13 @@ class Group < Principal :conditions => ["#{Member.table_name}.user_id = ? AND #{MemberRole.table_name}.inherited_from IN (?)", user.id, member.member_role_ids]).each(&:destroy) end end + + private + + # Removes references that are not handled by associations + def remove_references_before_destroy + return if self.id.nil? + + Issue.update_all 'assigned_to_id = NULL', ['assigned_to_id = ?', id] + end end diff --git a/app/models/issue.rb b/app/models/issue.rb index 5ac166270..d7a3e6ecb 100644 --- a/app/models/issue.rb +++ b/app/models/issue.rb @@ -22,7 +22,7 @@ class Issue < ActiveRecord::Base 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' @@ -93,9 +93,11 @@ class Issue < ActiveRecord::Base 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}))" 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}))" else '1=0' end @@ -109,9 +111,9 @@ class Issue < ActiveRecord::Base 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 @@ -482,7 +484,13 @@ class Issue < ActiveRecord::Base # 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)} diff --git a/app/models/issue_category.rb b/app/models/issue_category.rb index 96b8eeee1..19b2d906b 100644 --- a/app/models/issue_category.rb +++ b/app/models/issue_category.rb @@ -17,7 +17,7 @@ class IssueCategory < ActiveRecord::Base belongs_to :project - belongs_to :assigned_to, :class_name => 'User', :foreign_key => 'assigned_to_id' + belongs_to :assigned_to, :class_name => 'Principal', :foreign_key => 'assigned_to_id' has_many :issues, :foreign_key => 'category_id', :dependent => :nullify validates_presence_of :name diff --git a/app/models/mail_handler.rb b/app/models/mail_handler.rb index dbbd4f5f3..0ba8d3fd2 100644 --- a/app/models/mail_handler.rb +++ b/app/models/mail_handler.rb @@ -261,8 +261,7 @@ class MailHandler < ActionMailer::Base # Returns a Hash of issue attributes extracted from keywords in the email body def issue_attributes_from_keywords(issue) - assigned_to = (k = get_keyword(:assigned_to, :override => true)) && find_user_from_keyword(k) - assigned_to = nil if assigned_to && !issue.assignable_users.include?(assigned_to) + assigned_to = (k = get_keyword(:assigned_to, :override => true)) && find_assignee_from_keyword(k, issue) attrs = { 'tracker_id' => (k = get_keyword(:tracker)) && issue.project.trackers.named(k).first.try(:id), @@ -353,14 +352,19 @@ class MailHandler < ActionMailer::Base end body.strip end - - def find_user_from_keyword(keyword) - user ||= User.find_by_mail(keyword) - user ||= User.find_by_login(keyword) - if user.nil? && keyword.match(/ /) + + def find_assignee_from_keyword(keyword, issue) + keyword = keyword.to_s.downcase + assignable = issue.assignable_users + assignee = nil + assignee ||= assignable.detect {|a| a.mail.to_s.downcase == keyword || a.login.to_s.downcase == keyword} + if assignee.nil? && keyword.match(/ /) firstname, lastname = *(keyword.split) # "First Last Throwaway" - user ||= User.find_by_firstname_and_lastname(firstname, lastname) + assignee ||= assignable.detect {|a| a.is_a?(User) && a.firstname.to_s.downcase == firstname && a.lastname.to_s.downcase == lastname} + end + if assignee.nil? + assignee ||= assignable.detect {|a| a.is_a?(Group) && a.name.downcase == keyword} end - user + assignee end end diff --git a/app/models/principal.rb b/app/models/principal.rb index b3e07dda5..a157cd22f 100644 --- a/app/models/principal.rb +++ b/app/models/principal.rb @@ -1,5 +1,5 @@ # Redmine - project management software -# Copyright (C) 2006-2009 Jean-Philippe Lang +# Copyright (C) 2006-2011 Jean-Philippe Lang # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License @@ -21,6 +21,7 @@ class Principal < ActiveRecord::Base has_many :members, :foreign_key => 'user_id', :dependent => :destroy has_many :memberships, :class_name => 'Member', :foreign_key => 'user_id', :include => [ :project, :roles ], :conditions => "#{Project.table_name}.status=#{Project::STATUS_ACTIVE}", :order => "#{Project.table_name}.name" has_many :projects, :through => :memberships + has_many :issue_categories, :foreign_key => 'assigned_to_id', :dependent => :nullify # Groups and active users named_scope :active, :conditions => "#{Principal.table_name}.type='Group' OR (#{Principal.table_name}.type='User' AND #{Principal.table_name}.status = 1)" diff --git a/app/models/project.rb b/app/models/project.rb index c3b553083..b4872a3b4 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -426,9 +426,10 @@ class Project < ActiveRecord::Base Member.delete_all(['project_id = ?', id]) end - # Users issues can be assigned to + # Users/groups issues can be assigned to def assignable_users - members.select {|m| m.roles.detect {|role| role.assignable?}}.collect {|m| m.user}.sort + assignable = Setting.issue_group_assignment? ? member_principals : members + assignable.select {|m| m.roles.detect {|role| role.assignable?}}.collect {|m| m.principal}.sort end # Returns the mail adresses of users that should be always notified on project events diff --git a/app/models/query.rb b/app/models/query.rb index 3cb4c4507..28e1a6d18 100644 --- a/app/models/query.rb +++ b/app/models/query.rb @@ -223,15 +223,14 @@ class Query < ActiveRecord::Base "estimated_hours" => { :type => :float, :order => 13 }, "done_ratio" => { :type => :integer, :order => 14 }} - user_values = [] - user_values << ["<< #{l(:label_me)} >>", "me"] if User.current.logged? + principals = [] if project - user_values += project.users.sort.collect{|s| [s.name, s.id.to_s] } + principals += project.principals.sort else all_projects = Project.visible.all if all_projects.any? # members of visible projects - user_values += User.active.find(:all, :conditions => ["#{User.table_name}.id IN (SELECT DISTINCT user_id FROM members WHERE project_id IN (?))", all_projects.collect(&:id)]).sort.collect{|s| [s.name, s.id.to_s] } + principals += Principal.active.find(:all, :conditions => ["#{User.table_name}.id IN (SELECT DISTINCT user_id FROM members WHERE project_id IN (?))", all_projects.collect(&:id)]).sort # project filter project_values = [] @@ -242,8 +241,17 @@ class Query < ActiveRecord::Base @available_filters["project_id"] = { :type => :list, :order => 1, :values => project_values} unless project_values.empty? end end - @available_filters["assigned_to_id"] = { :type => :list_optional, :order => 4, :values => user_values } unless user_values.empty? - @available_filters["author_id"] = { :type => :list, :order => 5, :values => user_values } unless user_values.empty? + users = principals.select {|p| p.is_a?(User)} + + assigned_to_values = [] + assigned_to_values << ["<< #{l(:label_me)} >>", "me"] if User.current.logged? + assigned_to_values += (Setting.issue_group_assignment? ? principals : users).collect{|s| [s.name, s.id.to_s] } + @available_filters["assigned_to_id"] = { :type => :list_optional, :order => 4, :values => assigned_to_values } unless assigned_to_values.empty? + + author_values = [] + author_values << ["<< #{l(:label_me)} >>", "me"] if User.current.logged? + author_values += users.collect{|s| [s.name, s.id.to_s] } + @available_filters["author_id"] = { :type => :list, :order => 5, :values => author_values } unless author_values.empty? group_values = Group.all.collect {|g| [g.name, g.id.to_s] } @available_filters["member_of_group"] = { :type => :list_optional, :order => 6, :values => group_values } unless group_values.empty? diff --git a/app/models/user.rb b/app/models/user.rb index 1b7680182..656110f73 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -45,7 +45,6 @@ class User < Principal 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 has_many :changesets, :dependent => :nullify has_one :preference, :dependent => :destroy, :class_name => 'UserPreference' has_one :rss_token, :class_name => 'Token', :conditions => "action='feeds'" @@ -388,6 +387,17 @@ class User < Principal @projects_by_role end + # Returns true if user is arg or belongs to arg + def is_or_belongs_to?(arg) + if arg.is_a?(User) + self == arg + elsif arg.is_a?(Group) + arg.users.include?(self) + else + false + end + end + # 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') @@ -469,7 +479,7 @@ class User < Principal true when 'selected' # user receives notifications for created/assigned issues on unselected projects - if object.is_a?(Issue) && (object.author == self || object.assigned_to == self) + if object.is_a?(Issue) && (object.author == self || is_or_belongs_to?(object.assigned_to)) true else false @@ -477,13 +487,13 @@ class User < Principal when 'none' false when 'only_my_events' - if object.is_a?(Issue) && (object.author == self || object.assigned_to == self) + if object.is_a?(Issue) && (object.author == self || is_or_belongs_to?(object.assigned_to)) true else false end when 'only_assigned' - if object.is_a?(Issue) && object.assigned_to == self + if object.is_a?(Issue) && is_or_belongs_to?(object.assigned_to) true else false diff --git a/app/views/issue_categories/_form.rhtml b/app/views/issue_categories/_form.rhtml index 232808800..fc5f158d3 100644 --- a/app/views/issue_categories/_form.rhtml +++ b/app/views/issue_categories/_form.rhtml @@ -2,5 +2,5 @@ <div class="box"> <p><%= f.text_field :name, :size => 30, :required => true %></p> -<p><%= f.select :assigned_to_id, @project.users.sort.collect{|u| [u.name, u.id]}, :include_blank => true %></p> +<p><%= f.select :assigned_to_id, @project.assignable_users.sort.collect{|u| [u.name, u.id]}, :include_blank => true %></p> </div> diff --git a/app/views/settings/_issues.rhtml b/app/views/settings/_issues.rhtml index 273d4b581..cfe843e0c 100644 --- a/app/views/settings/_issues.rhtml +++ b/app/views/settings/_issues.rhtml @@ -3,6 +3,8 @@ <div class="box tabular settings"> <p><%= setting_check_box :cross_project_issue_relations %></p> +<p><%= setting_check_box :issue_group_assignment %></p> + <p><%= setting_check_box :display_subprojects_issues %></p> <p><%= setting_select :issue_done_ratio, Issue::DONE_RATIO_OPTIONS.collect {|i| [l("setting_issue_done_ratio_#{i}"), i]} %></p> diff --git a/config/locales/bg.yml b/config/locales/bg.yml index aa91c96c5..1ed6ce6df 100644 --- a/config/locales/bg.yml +++ b/config/locales/bg.yml @@ -977,3 +977,4 @@ bg: enumeration_doc_categories: Категории документи enumeration_activities: Дейности (time tracking) enumeration_system_activity: Системна активност + setting_issue_group_assignment: Allow issue assignment to groups diff --git a/config/locales/bs.yml b/config/locales/bs.yml index 962e08d58..8f635418f 100644 --- a/config/locales/bs.yml +++ b/config/locales/bs.yml @@ -992,3 +992,4 @@ bs: text_scm_command_not_available: Scm command is not available. Please check settings on the administration panel. notice_issue_successful_create: Issue %{id} created. label_between: between + setting_issue_group_assignment: Allow issue assignment to groups diff --git a/config/locales/ca.yml b/config/locales/ca.yml index 41ea899ee..62b3acfbe 100644 --- a/config/locales/ca.yml +++ b/config/locales/ca.yml @@ -981,3 +981,4 @@ ca: text_scm_command_not_available: Scm command is not available. Please check settings on the administration panel. notice_issue_successful_create: Issue %{id} created. label_between: between + setting_issue_group_assignment: Allow issue assignment to groups diff --git a/config/locales/cs.yml b/config/locales/cs.yml index 3dfc14964..88c0af57a 100644 --- a/config/locales/cs.yml +++ b/config/locales/cs.yml @@ -982,3 +982,4 @@ cs: text_scm_command_not_available: Scm command is not available. Please check settings on the administration panel. notice_issue_successful_create: Issue %{id} created. label_between: between + setting_issue_group_assignment: Allow issue assignment to groups diff --git a/config/locales/da.yml b/config/locales/da.yml index 88849ed66..e0c69c64f 100644 --- a/config/locales/da.yml +++ b/config/locales/da.yml @@ -995,3 +995,4 @@ da: text_scm_command_not_available: Scm command is not available. Please check settings on the administration panel. notice_issue_successful_create: Issue %{id} created. label_between: between + setting_issue_group_assignment: Allow issue assignment to groups diff --git a/config/locales/de.yml b/config/locales/de.yml index 535e3aec1..68b3cba3d 100644 --- a/config/locales/de.yml +++ b/config/locales/de.yml @@ -997,3 +997,4 @@ de: notice_issue_successful_create: Issue %{id} created. label_between: between + setting_issue_group_assignment: Allow issue assignment to groups diff --git a/config/locales/el.yml b/config/locales/el.yml index c5566fadd..9fcceeebc 100644 --- a/config/locales/el.yml +++ b/config/locales/el.yml @@ -978,3 +978,4 @@ el: text_scm_command_not_available: Scm command is not available. Please check settings on the administration panel. notice_issue_successful_create: Issue %{id} created. label_between: between + setting_issue_group_assignment: Allow issue assignment to groups diff --git a/config/locales/en-GB.yml b/config/locales/en-GB.yml index 0a3d793f8..8efa96d14 100644 --- a/config/locales/en-GB.yml +++ b/config/locales/en-GB.yml @@ -981,3 +981,4 @@ en-GB: text_scm_command_not_available: Scm command is not available. Please check settings on the administration panel. notice_issue_successful_create: Issue %{id} created. label_between: between + setting_issue_group_assignment: Allow issue assignment to groups diff --git a/config/locales/en.yml b/config/locales/en.yml index 66792632b..8dd3c8f7c 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -374,6 +374,7 @@ en: setting_commit_logtime_enabled: Enable time logging setting_commit_logtime_activity_id: Activity for logged time setting_gantt_items_limit: Maximum number of items displayed on the gantt chart + setting_issue_group_assignment: Allow issue assignment to groups permission_add_project: Create project permission_add_subprojects: Create subprojects diff --git a/config/locales/es.yml b/config/locales/es.yml index b2f4a5bd9..7cd8d0d07 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -1015,3 +1015,4 @@ es: text_scm_command_not_available: La orden para el Scm no está disponible. Por favor, compruebe la configuración en el panel de administración. notice_issue_successful_create: Issue %{id} created. label_between: between + setting_issue_group_assignment: Allow issue assignment to groups diff --git a/config/locales/eu.yml b/config/locales/eu.yml index fb0269332..5fb1ec11c 100644 --- a/config/locales/eu.yml +++ b/config/locales/eu.yml @@ -982,3 +982,4 @@ eu: text_scm_command_not_available: Scm command is not available. Please check settings on the administration panel. notice_issue_successful_create: Issue %{id} created. label_between: between + setting_issue_group_assignment: Allow issue assignment to groups diff --git a/config/locales/fa.yml b/config/locales/fa.yml index 81fef9187..98291cc57 100644 --- a/config/locales/fa.yml +++ b/config/locales/fa.yml @@ -981,3 +981,4 @@ fa: text_scm_command_not_available: Scm command is not available. Please check settings on the administration panel. notice_issue_successful_create: Issue %{id} created. label_between: between + setting_issue_group_assignment: Allow issue assignment to groups diff --git a/config/locales/fi.yml b/config/locales/fi.yml index 134823e59..22005c2c0 100644 --- a/config/locales/fi.yml +++ b/config/locales/fi.yml @@ -999,3 +999,4 @@ fi: text_scm_command_not_available: Scm command is not available. Please check settings on the administration panel. notice_issue_successful_create: Issue %{id} created. label_between: between + setting_issue_group_assignment: Allow issue assignment to groups diff --git a/config/locales/fr.yml b/config/locales/fr.yml index cf23259bd..b6a85d5f0 100644 --- a/config/locales/fr.yml +++ b/config/locales/fr.yml @@ -371,6 +371,7 @@ fr: setting_commit_logtime_enabled: Permettre la saisie de temps setting_commit_logtime_activity_id: Activité pour le temps saisi setting_gantt_items_limit: Nombre maximum d'éléments affichés sur le gantt + setting_issue_group_assignment: Permettre l'assignement des demandes aux groupes permission_add_project: Créer un projet permission_add_subprojects: Créer des sous-projets diff --git a/config/locales/gl.yml b/config/locales/gl.yml index 7f40a42da..d814a78fe 100644 --- a/config/locales/gl.yml +++ b/config/locales/gl.yml @@ -990,3 +990,4 @@ gl: text_scm_command_not_available: Scm command is not available. Please check settings on the administration panel. notice_issue_successful_create: Issue %{id} created. label_between: between + setting_issue_group_assignment: Allow issue assignment to groups diff --git a/config/locales/he.yml b/config/locales/he.yml index ee37dba39..dc9495edb 100644 --- a/config/locales/he.yml +++ b/config/locales/he.yml @@ -983,3 +983,4 @@ he: text_scm_command_not_available: Scm command is not available. Please check settings on the administration panel. notice_issue_successful_create: Issue %{id} created. label_between: between + setting_issue_group_assignment: Allow issue assignment to groups diff --git a/config/locales/hr.yml b/config/locales/hr.yml index 9d0215d32..ec9f2abf8 100644 --- a/config/locales/hr.yml +++ b/config/locales/hr.yml @@ -985,3 +985,4 @@ hr: text_scm_command_not_available: Scm command is not available. Please check settings on the administration panel. notice_issue_successful_create: Issue %{id} created. label_between: between + setting_issue_group_assignment: Allow issue assignment to groups diff --git a/config/locales/hu.yml b/config/locales/hu.yml index 1262ebab0..475b7ac0d 100644 --- a/config/locales/hu.yml +++ b/config/locales/hu.yml @@ -997,3 +997,4 @@ text_scm_command_not_available: Scm command is not available. Please check settings on the administration panel. notice_issue_successful_create: Issue %{id} created. label_between: between + setting_issue_group_assignment: Allow issue assignment to groups diff --git a/config/locales/id.yml b/config/locales/id.yml index 95b48db66..824f07810 100644 --- a/config/locales/id.yml +++ b/config/locales/id.yml @@ -986,3 +986,4 @@ id: text_scm_command_not_available: Scm command is not available. Please check settings on the administration panel. notice_issue_successful_create: Issue %{id} created. label_between: between + setting_issue_group_assignment: Allow issue assignment to groups diff --git a/config/locales/it.yml b/config/locales/it.yml index da1f00d48..44d8974a7 100644 --- a/config/locales/it.yml +++ b/config/locales/it.yml @@ -979,3 +979,4 @@ it: text_scm_command_not_available: Scm command is not available. Please check settings on the administration panel. notice_issue_successful_create: Issue %{id} created. label_between: between + setting_issue_group_assignment: Allow issue assignment to groups diff --git a/config/locales/ja.yml b/config/locales/ja.yml index d026a7505..c095a40b6 100644 --- a/config/locales/ja.yml +++ b/config/locales/ja.yml @@ -1008,3 +1008,4 @@ ja: text_issues_destroy_descendants_confirmation: %{count}個の子チケットも削除されます。 notice_issue_successful_create: Issue %{id} created. label_between: between + setting_issue_group_assignment: Allow issue assignment to groups diff --git a/config/locales/ko.yml b/config/locales/ko.yml index 9cc8bade3..2741f420e 100644 --- a/config/locales/ko.yml +++ b/config/locales/ko.yml @@ -1030,3 +1030,4 @@ ko: text_scm_command_not_available: Scm command is not available. Please check settings on the administration panel. notice_issue_successful_create: Issue %{id} created. label_between: between + setting_issue_group_assignment: Allow issue assignment to groups diff --git a/config/locales/lt.yml b/config/locales/lt.yml index 7ee5dc017..f33521bae 100644 --- a/config/locales/lt.yml +++ b/config/locales/lt.yml @@ -1038,3 +1038,4 @@ lt: text_scm_command_not_available: Scm command is not available. Please check settings on the administration panel. notice_issue_successful_create: Issue %{id} created. label_between: between + setting_issue_group_assignment: Allow issue assignment to groups diff --git a/config/locales/lv.yml b/config/locales/lv.yml index d436788f1..423693254 100644 --- a/config/locales/lv.yml +++ b/config/locales/lv.yml @@ -973,3 +973,4 @@ lv: text_scm_command_not_available: Scm command is not available. Please check settings on the administration panel. notice_issue_successful_create: Issue %{id} created. label_between: between + setting_issue_group_assignment: Allow issue assignment to groups diff --git a/config/locales/mk.yml b/config/locales/mk.yml index 4832d6ac4..b3444ce77 100644 --- a/config/locales/mk.yml +++ b/config/locales/mk.yml @@ -978,3 +978,4 @@ mk: text_scm_command_not_available: Scm command is not available. Please check settings on the administration panel. notice_issue_successful_create: Issue %{id} created. label_between: between + setting_issue_group_assignment: Allow issue assignment to groups diff --git a/config/locales/mn.yml b/config/locales/mn.yml index b14a2a296..f6357b4ee 100644 --- a/config/locales/mn.yml +++ b/config/locales/mn.yml @@ -979,3 +979,4 @@ mn: text_scm_command_not_available: Scm command is not available. Please check settings on the administration panel. notice_issue_successful_create: Issue %{id} created. label_between: between + setting_issue_group_assignment: Allow issue assignment to groups diff --git a/config/locales/nl.yml b/config/locales/nl.yml index 9e20dd2f2..e2a1b91a7 100644 --- a/config/locales/nl.yml +++ b/config/locales/nl.yml @@ -960,3 +960,4 @@ nl: text_scm_command_not_available: Scm command is not available. Please check settings on the administration panel. notice_issue_successful_create: Issue %{id} created. label_between: between + setting_issue_group_assignment: Allow issue assignment to groups diff --git a/config/locales/no.yml b/config/locales/no.yml index 2e560cb65..795179eb9 100644 --- a/config/locales/no.yml +++ b/config/locales/no.yml @@ -965,3 +965,4 @@ text_scm_command_not_available: Scm command is not available. Please check settings on the administration panel. notice_issue_successful_create: Issue %{id} created. label_between: between + setting_issue_group_assignment: Allow issue assignment to groups diff --git a/config/locales/pl.yml b/config/locales/pl.yml index 1af6d26ff..16db7446b 100644 --- a/config/locales/pl.yml +++ b/config/locales/pl.yml @@ -995,3 +995,4 @@ pl: text_scm_command_not_available: Scm command is not available. Please check settings on the administration panel. notice_issue_successful_create: Issue %{id} created. label_between: between + setting_issue_group_assignment: Allow issue assignment to groups diff --git a/config/locales/pt-BR.yml b/config/locales/pt-BR.yml index edf33a751..8e8d0f6a6 100644 --- a/config/locales/pt-BR.yml +++ b/config/locales/pt-BR.yml @@ -999,3 +999,4 @@ pt-BR: text_scm_command_not_available: Comando de versionamento não disponível. Por favor verifique as configurações no painel de administração. notice_issue_successful_create: Issue %{id} created. label_between: between + setting_issue_group_assignment: Allow issue assignment to groups diff --git a/config/locales/pt.yml b/config/locales/pt.yml index 36b36586b..a972090a0 100644 --- a/config/locales/pt.yml +++ b/config/locales/pt.yml @@ -983,3 +983,4 @@ pt: text_scm_command_not_available: Scm command is not available. Please check settings on the administration panel. notice_issue_successful_create: Issue %{id} created. label_between: between + setting_issue_group_assignment: Allow issue assignment to groups diff --git a/config/locales/ro.yml b/config/locales/ro.yml index c850c9008..a2206a703 100644 --- a/config/locales/ro.yml +++ b/config/locales/ro.yml @@ -971,3 +971,4 @@ ro: text_scm_command_not_available: Scm command is not available. Please check settings on the administration panel. notice_issue_successful_create: Issue %{id} created. label_between: between + setting_issue_group_assignment: Allow issue assignment to groups diff --git a/config/locales/ru.yml b/config/locales/ru.yml index b67d0ad72..af2b98d16 100644 --- a/config/locales/ru.yml +++ b/config/locales/ru.yml @@ -1091,3 +1091,4 @@ ru: text_scm_command_not_available: Scm command is not available. Please check settings on the administration panel. notice_issue_successful_create: Issue %{id} created. label_between: between + setting_issue_group_assignment: Allow issue assignment to groups diff --git a/config/locales/sk.yml b/config/locales/sk.yml index 3fbe62d45..c0bf3f781 100644 --- a/config/locales/sk.yml +++ b/config/locales/sk.yml @@ -973,3 +973,4 @@ sk: text_scm_command_not_available: Scm command is not available. Please check settings on the administration panel. notice_issue_successful_create: Issue %{id} created. label_between: between + setting_issue_group_assignment: Allow issue assignment to groups diff --git a/config/locales/sl.yml b/config/locales/sl.yml index afb023b1a..6cf8e6722 100644 --- a/config/locales/sl.yml +++ b/config/locales/sl.yml @@ -974,3 +974,4 @@ sl: text_scm_command_not_available: Scm command is not available. Please check settings on the administration panel. notice_issue_successful_create: Issue %{id} created. label_between: between + setting_issue_group_assignment: Allow issue assignment to groups diff --git a/config/locales/sr-YU.yml b/config/locales/sr-YU.yml index a4c396bd2..c26b3ced2 100644 --- a/config/locales/sr-YU.yml +++ b/config/locales/sr-YU.yml @@ -978,3 +978,4 @@ sr-YU: text_scm_command_not_available: Scm command is not available. Please check settings on the administration panel. notice_issue_successful_create: Issue %{id} created. label_between: between + setting_issue_group_assignment: Allow issue assignment to groups diff --git a/config/locales/sr.yml b/config/locales/sr.yml index c908f944d..dbb1c9514 100644 --- a/config/locales/sr.yml +++ b/config/locales/sr.yml @@ -979,3 +979,4 @@ sr: text_scm_command_not_available: Scm command is not available. Please check settings on the administration panel. notice_issue_successful_create: Issue %{id} created. label_between: between + setting_issue_group_assignment: Allow issue assignment to groups diff --git a/config/locales/sv.yml b/config/locales/sv.yml index 8bdf04cb2..712f7bf6f 100644 --- a/config/locales/sv.yml +++ b/config/locales/sv.yml @@ -1019,3 +1019,4 @@ sv: enumeration_system_activity: Systemaktivitet notice_issue_successful_create: Issue %{id} created. label_between: between + setting_issue_group_assignment: Allow issue assignment to groups diff --git a/config/locales/th.yml b/config/locales/th.yml index bf701f2a5..1edeaac85 100644 --- a/config/locales/th.yml +++ b/config/locales/th.yml @@ -975,3 +975,4 @@ th: text_scm_command_not_available: Scm command is not available. Please check settings on the administration panel. notice_issue_successful_create: Issue %{id} created. label_between: between + setting_issue_group_assignment: Allow issue assignment to groups diff --git a/config/locales/tr.yml b/config/locales/tr.yml index 3b2f32927..84ff00f0e 100644 --- a/config/locales/tr.yml +++ b/config/locales/tr.yml @@ -997,3 +997,4 @@ tr: text_scm_command_not_available: Scm command is not available. Please check settings on the administration panel. notice_issue_successful_create: Issue %{id} created. label_between: between + setting_issue_group_assignment: Allow issue assignment to groups diff --git a/config/locales/uk.yml b/config/locales/uk.yml index ad23b9ce3..c09574ac6 100644 --- a/config/locales/uk.yml +++ b/config/locales/uk.yml @@ -974,3 +974,4 @@ uk: text_scm_command_not_available: Scm command is not available. Please check settings on the administration panel. notice_issue_successful_create: Issue %{id} created. label_between: between + setting_issue_group_assignment: Allow issue assignment to groups diff --git a/config/locales/vi.yml b/config/locales/vi.yml index e4ffc6093..d144f89fc 100644 --- a/config/locales/vi.yml +++ b/config/locales/vi.yml @@ -1029,3 +1029,4 @@ vi: text_scm_command_not_available: Scm command is not available. Please check settings on the administration panel. notice_issue_successful_create: Issue %{id} created. label_between: between + setting_issue_group_assignment: Allow issue assignment to groups diff --git a/config/locales/zh-TW.yml b/config/locales/zh-TW.yml index bd9f48eda..52e368b75 100644 --- a/config/locales/zh-TW.yml +++ b/config/locales/zh-TW.yml @@ -1058,3 +1058,4 @@ enumeration_doc_categories: 文件分類 enumeration_activities: 活動 (時間追蹤) enumeration_system_activity: 系統活動 + setting_issue_group_assignment: Allow issue assignment to groups diff --git a/config/locales/zh.yml b/config/locales/zh.yml index a9dbf29ca..281d75330 100644 --- a/config/locales/zh.yml +++ b/config/locales/zh.yml @@ -981,3 +981,4 @@ zh: text_scm_command_not_available: Scm command is not available. Please check settings on the administration panel. notice_issue_successful_create: Issue %{id} created. label_between: between + setting_issue_group_assignment: Allow issue assignment to groups diff --git a/config/settings.yml b/config/settings.yml index 6a9676a90..c81ddc853 100644 --- a/config/settings.yml +++ b/config/settings.yml @@ -121,6 +121,8 @@ user_format: format: symbol cross_project_issue_relations: default: 0 +issue_group_assignment: + default: 0 notified_events: serialized: true default: diff --git a/test/functional/issues_controller_test.rb b/test/functional/issues_controller_test.rb index 53afe2a25..3f539faa1 100644 --- a/test/functional/issues_controller_test.rb +++ b/test/functional/issues_controller_test.rb @@ -535,6 +535,28 @@ class IssuesControllerTest < ActionController::TestCase assert_not_nil v assert_equal 'Value for field 2', v.value end + + def test_post_new_with_group_assignment + group = Group.find(11) + project = Project.find(1) + project.members << Member.new(:principal => group, :roles => [Role.first]) + + with_settings :issue_group_assignment => '1' do + @request.session[:user_id] = 2 + assert_difference 'Issue.count' do + post :create, :project_id => project.id, + :issue => {:tracker_id => 3, + :status_id => 1, + :subject => 'This is the test_new_with_group_assignment issue', + :assigned_to_id => group.id} + end + end + assert_redirected_to :controller => 'issues', :action => 'show', :id => Issue.last.id + + issue = Issue.find_by_subject('This is the test_new_with_group_assignment issue') + assert_not_nil issue + assert_equal group, issue.assigned_to + end def test_post_create_without_start_date @request.session[:user_id] = 2 @@ -1309,6 +1331,22 @@ class IssuesControllerTest < ActionController::TestCase assert_equal 1, journal.details.size end + def test_bulk_update_with_group_assignee + group = Group.find(11) + project = Project.find(1) + project.members << Member.new(:principal => group, :roles => [Role.first]) + + @request.session[:user_id] = 2 + # update issues assignee + post :bulk_update, :ids => [1, 2], :notes => 'Bulk editing', + :issue => {:priority_id => '', + :assigned_to_id => group.id, + :custom_field_values => {'2' => ''}} + + assert_response 302 + assert_equal [group, group], Issue.find_all_by_id([1, 2]).collect {|i| i.assigned_to} + end + def test_bulk_update_on_different_projects @request.session[:user_id] = 2 # update issues priority diff --git a/test/unit/group_test.rb b/test/unit/group_test.rb index a7670aab0..b86dbb0a8 100644 --- a/test/unit/group_test.rb +++ b/test/unit/group_test.rb @@ -1,5 +1,5 @@ # Redmine - project management software -# Copyright (C) 2006-2009 Jean-Philippe Lang +# Copyright (C) 2006-2011 Jean-Philippe Lang # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License @@ -74,4 +74,14 @@ class GroupTest < ActiveSupport::TestCase User.find(8).groups.clear assert !User.find(8).member_of?(Project.find(5)) end + + def test_destroy_should_unassign_issues + group = Group.first + Issue.update_all(["assigned_to_id = ?", group.id], 'id = 1') + + assert group.destroy + assert group.destroyed? + + assert_equal nil, Issue.find(1).assigned_to_id + end end diff --git a/test/unit/issue_category_test.rb b/test/unit/issue_category_test.rb index 947f15f0d..74c6539db 100644 --- a/test/unit/issue_category_test.rb +++ b/test/unit/issue_category_test.rb @@ -1,5 +1,5 @@ -# redMine - project management software -# Copyright (C) 2006-2007 Jean-Philippe Lang +# Redmine - project management software +# Copyright (C) 2006-2011 Jean-Philippe Lang # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License @@ -24,6 +24,19 @@ class IssueCategoryTest < ActiveSupport::TestCase @category = IssueCategory.find(1) end + def test_create + assert IssueCategory.new(:project_id => 2, :name => 'New category').save + category = IssueCategory.first(:order => 'id DESC') + assert_equal 'New category', category.name + end + + def test_create_with_group_assignment + assert IssueCategory.new(:project_id => 2, :name => 'Group assignment', :assigned_to_id => 11).save + category = IssueCategory.first(:order => 'id DESC') + assert_kind_of Group, category.assigned_to + assert_equal Group.find(11), category.assigned_to + end + def test_destroy issue = @category.issues.first @category.destroy diff --git a/test/unit/issue_test.rb b/test/unit/issue_test.rb index cf759b43d..f36bf9049 100644 --- a/test/unit/issue_test.rb +++ b/test/unit/issue_test.rb @@ -64,6 +64,15 @@ class IssueTest < ActiveSupport::TestCase issue.reload assert_equal 'PostgreSQL', issue.custom_value_for(field).value end + + def test_create_with_group_assignment + with_settings :issue_group_assignment => '1' do + assert Issue.new(:project_id => 2, :tracker_id => 1, :author_id => 1, :subject => 'Group assignment', :assigned_to_id => 11).save + issue = Issue.first(:order => 'id DESC') + assert_kind_of Group, issue.assigned_to + assert_equal Group.find(11), issue.assigned_to + end + end def assert_visibility_match(user, issues) assert_equal issues.collect(&:id).sort, Issue.all.select {|issue| issue.visible?(user)}.collect(&:id).sort @@ -579,6 +588,16 @@ class IssueTest < ActiveSupport::TestCase # author is not a member of project anymore assert !copy.recipients.include?(copy.author.mail) end + + def test_recipients_should_include_the_assigned_group_members + group_member = User.generate_with_protected! + group = Group.generate! + group.users << group_member + + issue = Issue.find(12) + issue.assigned_to = group + assert issue.recipients.include?(group_member.mail) + end def test_watcher_recipients_should_not_include_users_that_cannot_view_the_issue user = User.find(3) @@ -682,6 +701,28 @@ class IssueTest < ActiveSupport::TestCase assert_equal 1, assignable_user_ids.select {|i| i == user_id}.length, "User #{user_id} appears more or less than once" end end + + context "with issue_group_assignment" do + should "include groups" do + issue = Issue.new(:project => Project.find(2)) + + with_settings :issue_group_assignment => '1' do + assert_equal %w(Group User), issue.assignable_users.map {|a| a.class.name}.uniq.sort + assert issue.assignable_users.include?(Group.find(11)) + end + end + end + + context "without issue_group_assignment" do + should "not include groups" do + issue = Issue.new(:project => Project.find(2)) + + with_settings :issue_group_assignment => '0' do + assert_equal %w(User), issue.assignable_users.map {|a| a.class.name}.uniq.sort + assert !issue.assignable_users.include?(Group.find(11)) + end + end + end end def test_create_should_send_email_notification diff --git a/test/unit/mail_handler_test.rb b/test/unit/mail_handler_test.rb index 2ead03935..d272e6090 100644 --- a/test/unit/mail_handler_test.rb +++ b/test/unit/mail_handler_test.rb @@ -109,6 +109,18 @@ class MailHandlerTest < ActiveSupport::TestCase assert_equal 'Urgent', issue.priority.to_s assert issue.description.include?('Lorem ipsum dolor sit amet, consectetuer adipiscing elit.') end + + def test_add_issue_with_group_assignment + with_settings :issue_group_assignment => '1' do + issue = submit_email('ticket_on_given_project.eml') do |email| + email.gsub!('Assigned to: John Smith', 'Assigned to: B Team') + end + assert issue.is_a?(Issue) + assert !issue.new_record? + issue.reload + assert_equal Group.find(11), issue.assigned_to + end + end def test_add_issue_with_partial_attributes_override issue = submit_email('ticket_with_attributes.eml', :issue => {:priority => 'High'}, :allow_override => ['tracker']) @@ -446,6 +458,7 @@ class MailHandlerTest < ActiveSupport::TestCase def submit_email(filename, options={}) raw = IO.read(File.join(FIXTURES_PATH, filename)) + yield raw if block_given? MailHandler.receive(raw, options) end |