From 5f889932b6ce810707867e3c55cf9da438fe3518 Mon Sep 17 00:00:00 2001 From: Jean-Philippe Lang Date: Tue, 15 Mar 2011 15:39:59 +0000 Subject: [PATCH] Changed the way the visibility SQL statement is built. git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@5140 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- app/models/project.rb | 28 +++++++++++++++++----------- app/models/user.rb | 20 +++++++++++++++++++- test/unit/user_test.rb | 17 +++++++++++++++++ 3 files changed, 53 insertions(+), 12 deletions(-) diff --git a/app/models/project.rb b/app/models/project.rb index 8315a48a5..b20a218ba 100644 --- a/app/models/project.rb +++ b/app/models/project.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 @@ -135,7 +135,6 @@ class Project < ActiveRecord::Base end def self.allowed_to_condition(user, permission, options={}) - statements = [] base_statement = "#{Project.table_name}.status=#{Project::STATUS_ACTIVE}" if perm = Redmine::AccessControl.permission(permission) unless perm.project_module.nil? @@ -148,24 +147,31 @@ class Project < ActiveRecord::Base project_statement << " OR (#{Project.table_name}.lft > #{options[:project].lft} AND #{Project.table_name}.rgt < #{options[:project].rgt})" if options[:with_subprojects] base_statement = "(#{project_statement}) AND (#{base_statement})" end + if user.admin? - # no restriction + base_statement else - statements << "1=0" + statement_by_role = {} if user.logged? if Role.non_member.allowed_to?(permission) && !options[:member] - statements << "#{Project.table_name}.is_public = #{connection.quoted_true}" + statement_by_role[Role.non_member] = "#{Project.table_name}.is_public = #{connection.quoted_true}" + end + user.projects_by_role.each do |role, projects| + if role.allowed_to?(permission) + statement_by_role[role] = "#{Project.table_name}.id IN (#{projects.collect(&:id).join(',')})" + end end - allowed_project_ids = user.memberships.select {|m| m.roles.detect {|role| role.allowed_to?(permission)}}.collect {|m| m.project_id} - statements << "#{Project.table_name}.id IN (#{allowed_project_ids.join(',')})" if allowed_project_ids.any? else if Role.anonymous.allowed_to?(permission) && !options[:member] - # anonymous user allowed on public project - statements << "#{Project.table_name}.is_public = #{connection.quoted_true}" + statement_by_role[Role.anonymous] = "#{Project.table_name}.is_public = #{connection.quoted_true}" end end + if statement_by_role.empty? + "1=0" + else + "((#{base_statement}) AND (#{statement_by_role.values.join(' OR ')}))" + end end - statements.empty? ? base_statement : "((#{base_statement}) AND (#{statements.join(' OR ')}))" end # Returns the Systemwide and project specific activities diff --git a/app/models/user.rb b/app/models/user.rb index 025976831..62e832489 100644 --- a/app/models/user.rb +++ b/app/models/user.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 @@ -90,6 +90,7 @@ class User < Principal def reload(*args) @name = nil + @projects_by_role = nil super end @@ -361,6 +362,23 @@ class User < Principal !roles_for_project(project).detect {|role| role.member?}.nil? end + # Returns a hash of user's projects grouped by roles + def projects_by_role + return @projects_by_role if @projects_by_role + + @projects_by_role = Hash.new {|h,k| h[k]=[]} + memberships.each do |membership| + membership.roles.each do |role| + @projects_by_role[role] << membership.project if membership.project + end + end + @projects_by_role.each do |role, projects| + projects.uniq! + end + + @projects_by_role + 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') diff --git a/test/unit/user_test.rb b/test/unit/user_test.rb index 3f324ddc4..3848eab0f 100644 --- a/test/unit/user_test.rb +++ b/test/unit/user_test.rb @@ -522,6 +522,23 @@ class UserTest < ActiveSupport::TestCase assert_nil @dlopper.roles_for_project(Project.find(2)).detect {|role| role.member?} end + def test_projects_by_role_for_user_with_role + user = User.find(2) + assert_kind_of Hash, user.projects_by_role + assert_equal 2, user.projects_by_role.size + assert_equal [1,5], user.projects_by_role[Role.find(1)].collect(&:id).sort + assert_equal [2], user.projects_by_role[Role.find(2)].collect(&:id).sort + end + + def test_projects_by_role_for_user_with_no_role + user = User.generate! + assert_equal({}, user.projects_by_role) + end + + def test_projects_by_role_for_anonymous + assert_equal({}, User.anonymous.projects_by_role) + end + def test_valid_notification_options # without memberships assert_equal 5, User.find(7).valid_notification_options.size -- 2.39.5