Browse Source

Speeds up Project.allowed_to_condition for users who belong to hundreds of projects.

git-svn-id: http://svn.redmine.org/redmine/trunk@16124 e93f8b46-1217-0410-a6f0-8f06a7374b81
tags/3.4.0
Jean-Philippe Lang 7 years ago
parent
commit
98f8a17851
2 changed files with 40 additions and 21 deletions
  1. 3
    3
      app/models/project.rb
  2. 37
    18
      app/models/user.rb

+ 3
- 3
app/models/project.rb View File

@@ -204,9 +204,9 @@ class Project < ActiveRecord::Base
statement_by_role[role] = s
end
end
user.projects_by_role.each do |role, projects|
if role.allowed_to?(permission) && projects.any?
statement_by_role[role] = "#{Project.table_name}.id IN (#{projects.collect(&:id).join(',')})"
user.project_ids_by_role.each do |role, project_ids|
if role.allowed_to?(permission) && project_ids.any?
statement_by_role[role] = "#{Project.table_name}.id IN (#{project_ids.join(',')})"
end
end
if statement_by_role.empty?

+ 37
- 18
app/models/user.rb View File

@@ -163,6 +163,7 @@ class User < Principal
def reload(*args)
@name = nil
@projects_by_role = nil
@project_ids_by_role = nil
@membership_by_project_id = nil
@notified_projects_ids = nil
@notified_projects_ids_changed = false
@@ -564,33 +565,51 @@ class User < Principal
end

# Returns a hash of user's projects grouped by roles
# TODO: No longer used, should be deprecated
def projects_by_role
return @projects_by_role if @projects_by_role

hash = Hash.new([])
result = Hash.new([])
project_ids_by_role.each do |role, ids|
result[role] = Project.where(:id => ids).to_a
end
@projects_by_role = result
end

# Returns a hash of project ids grouped by roles.
# Includes the projects that the user is a member of and the projects
# that grant custom permissions to the builtin groups.
def project_ids_by_role
return @project_ids_by_role if @project_ids_by_role

group_class = anonymous? ? GroupAnonymous : GroupNonMember
members = Member.joins(:project, :principal).
group_id = group_class.pluck(:id).first

members = Member.joins(:project, :member_roles).
where("#{Project.table_name}.status <> 9").
where("#{Member.table_name}.user_id = ? OR (#{Project.table_name}.is_public = ? AND #{Principal.table_name}.type = ?)", self.id, true, group_class.name).
preload(:project, :roles).
to_a

members.reject! {|member| member.user_id != id && project_ids.include?(member.project_id)}
members.each do |member|
if member.project
member.roles.each do |role|
hash[role] = [] unless hash.key?(role)
hash[role] << member.project
end
end
end
where("#{Member.table_name}.user_id = ? OR (#{Project.table_name}.is_public = ? AND #{Member.table_name}.user_id = ?)", self.id, true, group_id).
pluck(:user_id, :role_id, :project_id)

hash = {}
members.each do |user_id, role_id, project_id|
# Ignore the roles of the builtin group if the user is a member of the project
next if user_id != id && project_ids.include?(project_id)

hash.each do |role, projects|
projects.uniq!
hash[role_id] ||= []
hash[role_id] << project_id
end

@projects_by_role = hash
result = Hash.new([])
if hash.present?
roles = Role.where(:id => hash.keys).to_a
hash.each do |role_id, proj_ids|
role = roles.detect {|r| r.id == role_id}
if role
result[role] = proj_ids.uniq
end
end
end
@project_ids_by_role = result
end

# Returns the ids of visible projects

Loading…
Cancel
Save