Merge pull request #66 from opf/feature/rails3_group_assigned_issues

pull/448/merge
Hagen Schink 11 years ago
commit fb55cc561f
  1. 17
      app/helpers/groups_helper.rb
  2. 19
      app/models/group.rb
  3. 4
      app/models/issue_category.rb
  4. 3
      app/models/mail_handler.rb
  5. 1
      app/models/principal.rb
  6. 26
      app/models/project.rb
  7. 39
      app/models/query.rb
  8. 17
      app/models/user.rb
  9. 10
      app/models/work_package.rb
  10. 4
      app/views/issue_categories/_form.html.erb
  11. 12
      app/views/my/blocks/_issuesassignedtome.html.erb
  12. 2
      app/views/settings/_issues.html.erb
  13. 3
      config/locales/de.yml
  14. 1
      config/locales/en.yml
  15. 2
      config/settings.yml
  16. 1
      doc/CHANGELOG.md
  17. 70
      spec/models/group_spec.rb
  18. 13
      spec/models/work_package/work_package_action_mailer_spec.rb
  19. 51
      spec/models/work_package_spec.rb
  20. 2
      spec/support/shared/become_member.rb
  21. 16
      test/functional/issues_controller_test.rb
  22. 1
      test/unit/group_test.rb
  23. 20
      test/unit/issue_category_test.rb
  24. 16
      test/unit/mail_handler_test.rb
  25. 21
      test/unit/query_test.rb

@ -28,19 +28,10 @@
#++
module GroupsHelper
# Options for the new membership projects combo-box
def options_for_membership_project_select(user, projects)
options = content_tag('option', "--- #{l(:actionview_instancetag_blank_option)} ---")
options << project_tree_options_for_select(projects) do |p|
{:disabled => (user.projects.include?(p))}
end
options
end
def group_settings_tabs
tabs = [{:name => 'general', :partial => 'groups/general', :label => :label_general},
{:name => 'users', :partial => 'groups/users', :label => :label_user_plural},
{:name => 'memberships', :partial => 'groups/memberships', :label => :label_project_plural}
]
[{:name => 'general', :partial => 'groups/general', :label => :label_general},
{:name => 'users', :partial => 'groups/users', :label => :label_user_plural},
{:name => 'memberships', :partial => 'groups/memberships', :label => :label_project_plural}
]
end
end

@ -39,10 +39,14 @@ class Group < Principal
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?
@ -85,4 +89,19 @@ class Group < Principal
def add_member!(users)
self.users << users
end
private
# Removes references that are not handled by associations
def remove_references_before_destroy
return if self.id.nil?
deleted_user = DeletedUser.first
WorkPackage.update_all({ :assigned_to_id => deleted_user.id },
{ :assigned_to_id => id })
Journal::WorkPackageJournal.update_all({ :assigned_to_id => deleted_user.id },
{ :assigned_to_id => id })
end
end

@ -30,7 +30,7 @@
class IssueCategory < ActiveRecord::Base
include Redmine::SafeAttributes
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 :work_packages, :foreign_key => 'category_id', :dependent => :nullify
attr_protected :project_id
@ -42,7 +42,7 @@ class IssueCategory < ActiveRecord::Base
# validates that assignee is member of the issue category's project
validates_each :assigned_to_id do |record, attr, value|
if value # allow nil
record.errors.add(attr, l(:error_must_be_project_member)) unless record.project.user_ids.include?(value.to_i)
record.errors.add(attr, l(:error_must_be_project_member)) unless record.project.principals.map(&:id).include? value
end
end

@ -426,8 +426,9 @@ class MailHandler < ActionMailer::Base
}
end
if assignee.nil?
assignee ||= assignable.detect {|a| a.name.downcase == keyword}
assignee ||= assignable.detect {|a| a.is_a?(Group) && a.name.downcase == keyword}
end
assignee
end
end

@ -35,6 +35,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
scope :active, :conditions => "#{Principal.table_name}.type='Group' OR (#{Principal.table_name}.type='User' AND #{Principal.table_name}.status = 1)"

@ -45,11 +45,8 @@ class Project < ActiveRecord::Base
has_many :members, :include => [:user, :roles], :conditions => "#{User.table_name}.type='User' AND #{User.table_name}.status=#{User::STATUSES[:active]}"
has_many :assignable_members,
:class_name => 'Member',
:include => [:user, :roles],
:conditions => ["#{User.table_name}.type=? AND #{User.table_name}.status=? AND roles.assignable = ?",
'User',
User::STATUSES[:active],
true]
:include => [:principal, :roles],
:conditions => Proc.new { self.class.assignable_members_condition }
has_many :memberships, :class_name => 'Member'
has_many :member_principals, :class_name => 'Member',
:include => :principal,
@ -596,9 +593,9 @@ class Project < ActiveRecord::Base
Member.delete_all(['project_id = ?', id])
end
# Users issues can be assigned to
# Users/groups a work_package can be assigned to
def assignable_users
assignable_members.map(&:user).sort
assignable_members.map(&:principal).compact.sort
end
# Returns the mail adresses of users that should be always notified on project events
@ -1109,4 +1106,19 @@ class Project < ActiveRecord::Base
end
update_attribute :status, STATUS_ARCHIVED
end
protected
def self.assignable_members_condition
condition = Setting.work_package_group_assignment? ?
["(#{Principal.table_name}.type=? OR #{Principal.table_name}.type=?)", 'User', 'Group'] :
["(#{Principal.table_name}.type=?)", 'User']
condition[0] += " AND #{User.table_name}.status=? AND roles.assignable = ?"
condition << User::STATUSES[:active]
condition << true
sanitize_sql_array condition
end
end

@ -144,15 +144,14 @@ class Query < ActiveRecord::Base
"estimated_hours" => { :type => :integer, :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 = []
@ -163,8 +162,24 @@ 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?
principals_by_class = principals.group_by(&:class)
user_values = principals_by_class[User].present? ?
principals_by_class[User].collect{ |s| [s.name, s.id.to_s] }.sort :
[]
group_values = Setting.work_package_group_assignment? && principals_by_class[Group].present? ?
principals_by_class[Group].collect{ |s| [s.name, s.id.to_s] }.sort :
[]
assigned_to_values = (user_values + group_values).sort
assigned_to_values = [["<< #{l(:label_me)} >>", "me"]] + assigned_to_values if User.current.logged?
@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 += user_values
@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, :name => I18n.t('query_fields.member_of_group') } unless group_values.empty?
@ -175,7 +190,8 @@ class Query < ActiveRecord::Base
if User.current.logged?
# populate the watcher list with the same user list as other user filters if the user has the :view_work_package_watchers permission in at least one project
# TODO: this could be differentiated more, e.g. all users could watch issues in public projects, but won't necessarily be shown here
watcher_values = User.current.allowed_to_globally?(:view_work_package_watchers, {}) ? user_values : [["<< #{l(:label_me)} >>", "me"]]
watcher_values = [["<< #{l(:label_me)} >>", "me"]]
user_values.each { |v| watcher_values << v } if User.current.allowed_to_globally?(:view_work_packages_watchers, {})
@available_filters["watcher_id"] = { :type => :list, :order => 15, :values => watcher_values }
end
@ -409,7 +425,14 @@ class Query < ActiveRecord::Base
# "me" value subsitution
if %w(assigned_to_id author_id watcher_id).include?(field)
v.push(User.current.logged? ? User.current.id.to_s : "0") if v.delete("me")
if v.delete("me")
if User.current.logged?
v.push(User.current.id.to_s)
v += User.current.group_ids.map(&:to_s) if field == 'assigned_to_id'
else
v.push("0")
end
end
end
sql = ''

@ -566,6 +566,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')
@ -657,7 +668,7 @@ class User < Principal
true
when 'selected'
# user receives notifications for created/assigned issues on unselected projects
if object.is_a?(WorkPackage) && (object.author == self || object.assigned_to == self)
if object.is_a?(WorkPackage) && (object.author == self || is_or_belongs_to?(object.assigned_to))
true
else
false
@ -665,13 +676,13 @@ class User < Principal
when 'none'
false
when 'only_my_events'
if object.is_a?(WorkPackage) && (object.author == self || object.assigned_to == self)
if object.is_a?(WorkPackage) && (object.author == self || is_or_belongs_to?(object.assigned_to))
true
else
false
end
when 'only_assigned'
if object.is_a?(WorkPackage) && object.assigned_to == self
if object.is_a?(WorkPackage) && is_or_belongs_to?(object.assigned_to)
true
else
false

@ -47,7 +47,7 @@ class WorkPackage < ActiveRecord::Base
belongs_to :type
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 :responsible, :class_name => "User", :foreign_key => "responsible_id"
belongs_to :fixed_version, :class_name => 'Version', :foreign_key => 'fixed_version_id'
belongs_to :priority, :class_name => 'IssuePriority', :foreign_key => 'priority_id'
@ -467,7 +467,13 @@ class WorkPackage < 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)}

@ -31,5 +31,7 @@ See doc/COPYRIGHT.rdoc for more details.
<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>

@ -33,7 +33,9 @@ See doc/COPYRIGHT.rdoc for more details.
:include => [ :status, :project, :type, :priority ],
:order => "#{IssuePriority.table_name}.position DESC, #{WorkPackage.table_name}.updated_at DESC") %>
<% assigned_count = WorkPackage.visible.open.count(:conditions => {:assigned_to_id => User.current.id}) %>
<% assigned_count = WorkPackage.visible.open.count(:conditions => {
:assigned_to_id => User.current.id
}) %>
<h3><%=l(:label_assigned_to_me_work_packages)%> (<%= assigned_count %>)</h3>
@ -41,10 +43,10 @@ See doc/COPYRIGHT.rdoc for more details.
<% if assigned.length > 0 %>
<p class="small"><%= link_to l(:label_work_package_view_all_assigned_to_me), controller: :work_packages,
action: :index,
set_filter: 1,
assigned_to_id: 'me',
sort: 'priority:desc,updated_at:desc' %></p>
action: :index,
set_filter: 1,
assigned_to_id: 'me',
sort: 'priority:desc,updated_at:desc' %></p>
<% end %>
<% content_for :header_tags do %>

@ -32,6 +32,8 @@ See doc/COPYRIGHT.rdoc for more details.
<div class="box tabular settings">
<p><%= setting_check_box :cross_project_work_package_relations %></p>
<p><%= setting_check_box :work_package_group_assignment %></p>
<p><%= setting_check_box :display_subprojects_work_packages %></p>
<p><%= setting_check_box :work_package_startdate_is_adddate %></p>

@ -1219,6 +1219,7 @@ de:
setting_users_deletable_by_self: "Nutzer können ihren Account löschen"
setting_welcome_text: "Willkommenstext"
setting_wiki_compression: "Wiki-Historie komprimieren"
setting_work_package_group_assignment: "Zuweisung zu Gruppen erlauben"
settings:
general: "Allgemein"
@ -1393,7 +1394,6 @@ de:
parent: "Zeige Unterprojekte von"
planning_element_filters: "Planungselemente filtern"
planning_element_responsible: "Planungselemente von diesem Planungsverantwortlichen anzeigen"
planning_element_types: "Typ anzeigen"
project_time_filter: "Projekte mit Planungselementen eines Typs in einem Zeitfenster"
project_time_filter_historical: "von %{startdate} bis %{enddate}"
@ -1521,7 +1521,6 @@ de:
version_status_closed: "abgeschlossen"
version_status_locked: "gesperrt"
version_status_open: "offen"
warning_attachments_not_saved: "%{count} Datei(en) konnten nicht gespeichert werden."
wiki_menu_item: "Menüpunkt"

@ -1195,6 +1195,7 @@ en:
setting_users_deletable_by_self: "Users allowed to delete their accounts"
setting_welcome_text: "Welcome text"
setting_wiki_compression: "Wiki history compression"
setting_work_package_group_assignment: "Allow assignment to groups"
settings:
general: "General"

@ -162,6 +162,8 @@ user_format:
format: symbol
cross_project_work_package_relations:
default: 0
work_package_group_assignment:
default: 0
notified_events:
serialized: true
default:

@ -29,6 +29,7 @@ See doc/COPYRIGHT.rdoc for more details.
# Changelog
* `#1715` Group assigned work packages
* `#1770` New Comment Section layout errors
* `#1790` Fix activity view bug coming up during the meeting adaptions to acts_as_journalized

@ -0,0 +1,70 @@
#-- copyright
# OpenProject is a project management system.
# Copyright (C) 2012-2013 the OpenProject Foundation (OPF)
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2010-2013 the ChiliProject Team
#
# 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.
#
# See doc/COPYRIGHT.rdoc for more details.
#++
require 'spec_helper'
require_relative '../support/shared/become_member'
describe Group do
include BecomeMember
let(:group) { FactoryGirl.build(:group) }
let(:user) { FactoryGirl.build(:user) }
let(:project) { FactoryGirl.create(:project_with_types) }
let(:issue_status) { FactoryGirl.create(:issue_status) }
let(:package) { FactoryGirl.build(:work_package, :type => project.types.first,
:author => user,
:project => project,
:status => issue_status) }
describe :destroy do
describe 'work packages assigned to the group' do
before do
become_member_with_permissions project, group, [:view_work_packages]
package.assigned_to = group
package.save!
end
it 'should reassign the work package to nobody' do
group.destroy
package.reload
package.assigned_to.should == DeletedUser.first
end
it 'should update all journals to have the deleted user as assigned' do
group.destroy
package.reload
package.journals.all?{ |j| j.data.assigned_to_id == DeletedUser.first.id }.should be_true
end
end
end
end

@ -76,5 +76,18 @@ describe WorkPackage do
it { should eq(0) }
end
context :group_assigned_work_package do
let(:group) { FactoryGirl.create(:group) }
before do
group.users << user_1
work_package.assigned_to = group
end
subject { work_package.recipients }
it { should include(user_1.mail) }
end
end
end

@ -95,6 +95,21 @@ describe WorkPackage do
it { should be_nil }
end
end
describe :assigned_to do
context :group_assignment do
let(:group) { FactoryGirl.create(:group) }
before do
Setting.stub(:work_package_group_assignment).and_return(true)
end
subject { FactoryGirl.create(:work_package,
assigned_to: group).assigned_to }
it { should eq(group) }
end
end
end
describe :type do
@ -165,6 +180,32 @@ describe WorkPackage do
end
end
context "with work_package_group_assignment" do
let(:group) { FactoryGirl.create(:group) }
let(:work_package) { FactoryGirl.create(:work_package) }
before do
Setting.stub(:work_package_group_assignment?).and_return(true)
work_package.project.add_member! group, FactoryGirl.create(:role)
end
subject { work_package.assignable_users }
it { should include(group) }
end
context "without work_package_group_assignment" do
let(:group) { FactoryGirl.create(:group) }
let(:work_package) { FactoryGirl.create(:work_package) }
before do
Setting.stub(:work_package_group_assignment?).and_return(false)
work_package.project.add_member! group, FactoryGirl.create(:role)
end
subject { work_package.assignable_users }
it { should_not include(group) }
end
context "multiple users" do
let(:user_2) { FactoryGirl.build_stubbed(:user) }
@ -302,7 +343,7 @@ describe WorkPackage do
end
shared_examples_for "save with open version" do
before do
before do
work_package.status = status_open
work_package.fixed_version = version_open
end
@ -315,7 +356,7 @@ describe WorkPackage do
context "in closed version" do
include_context "in closed version"
before do
before do
work_package.status = status_open
work_package.save
end
@ -373,13 +414,13 @@ describe WorkPackage do
end
context "time entry 1" do
subject { work_package.time_entries }
subject { work_package.time_entries }
it { should include(time_entry_1) }
end
context "time entry 2" do
subject { work_package.time_entries }
subject { work_package.time_entries }
it { should include(time_entry_2) }
end
@ -414,7 +455,7 @@ describe WorkPackage do
it { should eq(target_category.id) }
end
it_behaves_like "moved work package"
end

@ -38,7 +38,7 @@ module BecomeMember
role = FactoryGirl.create(:role, :permissions => permissions)
member = FactoryGirl.build(:member, :user => user, :project => project)
member = FactoryGirl.build(:member, :principal => user, :project => project)
member.roles = [role]
member.save!
end

@ -119,6 +119,22 @@ class IssuesControllerTest < ActionController::TestCase
assert_equal 0, ActionMailer::Base.deliveries.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], WorkPackage.find_all_by_id([1, 2]).collect {|i| i.assigned_to}
end
def test_bulk_update_on_different_projects
issue = WorkPackage.find(1)
issue.recreate_initial_journal!

@ -34,6 +34,7 @@ class GroupTest < ActiveSupport::TestCase
super
@group = FactoryGirl.create :group
@member = FactoryGirl.build :member
@work_package = FactoryGirl.create :work_package
@roles = FactoryGirl.create_list :role, 2
@member.force_attributes = { :principal => @group, :role_ids => @roles.map(&:id) }
@member.save!

@ -38,6 +38,26 @@ class IssueCategoryTest < ActiveSupport::TestCase
assert_equal @category.work_packages, [@issue]
end
def test_create
(new_cat = IssueCategory.new).force_attributes = {:project_id => @project.id, :name => 'New category'}
assert new_cat.valid?
assert new_cat.save
assert_equal 'New category', new_cat.name
end
def test_create_with_group_assignment
group = FactoryGirl.create :group
role = FactoryGirl.create :role
(Member.new.tap do |m|
m.force_attributes = { :principal => group, :project => @project, :role_ids => [role.id] }
end).save!
(new_cat = IssueCategory.new).force_attributes = {:project_id => @project.id, :name => 'Group assignment', :assigned_to_id => group.id}
assert new_cat.valid?
assert new_cat.save
assert_kind_of Group, new_cat.assigned_to
assert_equal group, new_cat.assigned_to
end
# Make sure the category was nullified on the issue
def test_destroy
@category.destroy

@ -103,6 +103,18 @@ class MailHandlerTest < ActiveSupport::TestCase
assert issue.description.include?('Lorem ipsum dolor sit amet, consectetuer adipiscing elit.')
end
def test_add_work_package_with_group_assignment
with_settings :work_package_group_assignment => '1' do
work_package = submit_email('ticket_on_given_project.eml') do |email|
email.gsub!('Assigned to: John Smith', 'Assigned to: B Team')
end
assert work_package.is_a?(WorkPackage)
assert !work_package.new_record?
work_package.reload
assert_equal Group.find(11), work_package.assigned_to
end
end
def test_add_issue_with_partial_attributes_override
issue = submit_email('ticket_with_attributes.eml', :issue => {:priority => 'High'}, :allow_override => ['type'])
assert issue.is_a?(WorkPackage)
@ -159,10 +171,10 @@ class MailHandlerTest < ActiveSupport::TestCase
end
def test_add_issue_should_match_assignee_on_display_name # added from redmine - not sure if it is ok here
user = User.generate!(:firstname => 'Foo Bar', :lastname => 'Foo Baz')
user = User.generate!(:firstname => 'Foo', :lastname => 'Bar')
User.add_to_project(user, Project.find(2), Role.generate!(:name => 'Superhero'))
issue = submit_email('ticket_on_given_project.eml') do |email|
email.sub!(/^Assigned to.*$/, 'Assigned to: Foo Bar Foo baz')
email.sub!(/^Assigned to.*$/, 'Assigned to: Foo Bar')
end
assert issue.is_a?(WorkPackage)
assert_equal user, issue.assigned_to

@ -209,6 +209,27 @@ class QueryTest < ActiveSupport::TestCase
find_issues_with_query(query)
end
def test_filter_assigned_to_me
user = User.find(2)
group = Group.find(10)
project = Project.find(1)
User.current = user
i1 = FactoryGirl.create(:work_package, :project => project, :type => project.types.first, :assigned_to => user)
i2 = FactoryGirl.create(:work_package, :project => project, :type => project.types.first, :assigned_to => group)
i3 = FactoryGirl.create(:work_package, :project => project, :type => project.types.first, :assigned_to => Group.find(11))
group.users << user
query = Query.new(:name => '_', :filters => { 'assigned_to_id' => {:operator => '=', :values => ['me']}})
result = query.results.work_packages
assert_equal WorkPackage.visible.all(:conditions => {:assigned_to_id => ([2] + user.reload.group_ids)}).sort_by(&:id), result.sort_by(&:id)
assert result.include?(i1)
assert result.include?(i2)
assert !result.include?(i3)
User.current = nil
end
def test_filter_watched_issues
User.current = User.find(1)
query = Query.new(:name => '_', :filters => { 'watcher_id' => {:operator => '=', :values => ['me']}})

Loading…
Cancel
Save