Commit a105101c4566479baa00ef98b6bf58f8a5516b12

Authored by Dmitriy Zaporozhets
2 parents 70a6af93 0fdce4a5

Merge branch 'improve-projects-collecting' into 'master'

Improve projects collecting

Refactor code that cause unexpected AR behaviour.

For example this works fine:

    @projects = Project.personal(@user).accessible_to(current_user)
    @groups = @user.groups.accessible_to(current_user) # OK

But

    @projects = Project.all
    @groups = @user.groups.accessible_to(current_user) # PG:Error
app/controllers/users_controller.rb
@@ -4,15 +4,24 @@ class UsersController < ApplicationController @@ -4,15 +4,24 @@ class UsersController < ApplicationController
4 4
5 def show 5 def show
6 @user = User.find_by_username!(params[:username]) 6 @user = User.find_by_username!(params[:username])
7 - @projects = Project.personal(@user).accessible_to(current_user)  
8 7
9 unless current_user || @user.public_profile? 8 unless current_user || @user.public_profile?
10 return authenticate_user! 9 return authenticate_user!
11 end 10 end
12 11
13 - @groups = @user.groups.accessible_to(current_user)  
14 - accessible_projects = @user.authorized_projects.accessible_to(current_user)  
15 - @events = @user.recent_events.where(project_id: accessible_projects.pluck(:id)).limit(20) 12 + # Projects user can view
  13 + authorized_projects_ids = ProjectsFinder.new.execute(current_user).pluck(:id)
  14 +
  15 + @projects = @user.personal_projects.
  16 + where(id: authorized_projects_ids)
  17 +
  18 + # Collect only groups common for both users
  19 + @groups = @user.groups & GroupsFinder.new.execute(current_user)
  20 +
  21 + # Get user activity feed for projects common for both users
  22 + @events = @user.recent_events.
  23 + where(project_id: authorized_projects_ids).limit(20)
  24 +
16 @title = @user.name 25 @title = @user.name
17 end 26 end
18 27
app/finders/base_finder.rb
@@ -49,7 +49,7 @@ class BaseFinder @@ -49,7 +49,7 @@ class BaseFinder
49 elsif current_user && params[:authorized_only].presence 49 elsif current_user && params[:authorized_only].presence
50 klass.of_projects(current_user.authorized_projects).references(:project) 50 klass.of_projects(current_user.authorized_projects).references(:project)
51 else 51 else
52 - klass.of_projects(Project.accessible_to(current_user)).references(:project) 52 + klass.of_projects(ProjectsFinder.new.execute(current_user)).references(:project)
53 end 53 end
54 end 54 end
55 55
app/finders/groups_finder.rb 0 → 100644
@@ -0,0 +1,38 @@ @@ -0,0 +1,38 @@
  1 +class GroupsFinder
  2 + def execute(current_user, options = {})
  3 + all_groups(current_user)
  4 + end
  5 +
  6 + private
  7 +
  8 + def all_groups(current_user)
  9 + if current_user
  10 + if current_user.authorized_groups.any?
  11 + # User has access to groups
  12 + #
  13 + # Return only:
  14 + # groups with public projects
  15 + # groups with internal projects
  16 + # groups with joined projects
  17 + #
  18 + group_ids = Project.public_and_internal_only.pluck(:namespace_id) +
  19 + current_user.authorized_groups.pluck(:id)
  20 + Group.where(id: group_ids)
  21 + else
  22 + # User has no group membership
  23 + #
  24 + # Return only:
  25 + # groups with public projects
  26 + # groups with internal projects
  27 + #
  28 + Group.where(id: Project.public_and_internal_only.pluck(:namespace_id))
  29 + end
  30 + else
  31 + # Not authenticated
  32 + #
  33 + # Return only:
  34 + # groups with public projects
  35 + Group.where(id: Project.public_only.pluck(:namespace_id))
  36 + end
  37 + end
  38 +end
app/finders/projects_finder.rb
1 class ProjectsFinder 1 class ProjectsFinder
2 - def execute(current_user, options) 2 + def execute(current_user, options = {})
3 group = options[:group] 3 group = options[:group]
4 4
5 if group 5 if group
@@ -56,8 +56,36 @@ class ProjectsFinder @@ -56,8 +56,36 @@ class ProjectsFinder
56 end 56 end
57 end 57 end
58 58
59 - def all_projects  
60 - # TODO: implement  
61 - raise 'Not implemented yet' 59 + def all_projects(current_user)
  60 + if current_user
  61 + if current_user.authorized_projects.any?
  62 + # User has access to private projects
  63 + #
  64 + # Return only:
  65 + # public projects
  66 + # internal projects
  67 + # joined projects
  68 + #
  69 + Project.where(
  70 + "projects.id IN (?) OR projects.visibility_level IN (?)",
  71 + current_user.authorized_projects.pluck(:id),
  72 + Project.public_and_internal_levels
  73 + )
  74 + else
  75 + # User has no access to private projects
  76 + #
  77 + # Return only:
  78 + # public projects
  79 + # internal projects
  80 + #
  81 + Project.public_and_internal_only
  82 + end
  83 + else
  84 + # Not authenticated
  85 + #
  86 + # Return only:
  87 + # public projects
  88 + Project.public_only
  89 + end
62 end 90 end
63 end 91 end
app/helpers/search_helper.rb
@@ -81,7 +81,7 @@ module SearchHelper @@ -81,7 +81,7 @@ module SearchHelper
81 81
82 # Autocomplete results for the current user's projects 82 # Autocomplete results for the current user's projects
83 def projects_autocomplete(term, limit = 5) 83 def projects_autocomplete(term, limit = 5)
84 - Project.accessible_to(current_user).search_by_title(term).non_archived.limit(limit).map do |p| 84 + ProjectsFinder.new.execute(current_user).search_by_title(term).non_archived.limit(limit).map do |p|
85 { 85 {
86 label: "project: #{search_result_sanitize(p.name_with_namespace)}", 86 label: "project: #{search_result_sanitize(p.name_with_namespace)}",
87 url: project_path(p) 87 url: project_path(p)
app/helpers/submodule_helper.rb 100755 → 100644
app/models/ability.rb
@@ -51,7 +51,7 @@ class Ability @@ -51,7 +51,7 @@ class Ability
51 nil 51 nil
52 end 52 end
53 53
54 - if group && group.has_projects_accessible_to?(nil) 54 + if group && group.public_profile?
55 [:read_group] 55 [:read_group]
56 else 56 else
57 [] 57 []
app/models/group.rb
@@ -27,12 +27,6 @@ class Group < Namespace @@ -27,12 +27,6 @@ class Group < Namespace
27 27
28 mount_uploader :avatar, AttachmentUploader 28 mount_uploader :avatar, AttachmentUploader
29 29
30 - def self.accessible_to(user)  
31 - accessible_ids = Project.accessible_to(user).pluck(:namespace_id)  
32 - accessible_ids += user.groups.pluck(:id) if user  
33 - where(id: accessible_ids)  
34 - end  
35 -  
36 def human_name 30 def human_name
37 name 31 name
38 end 32 end
@@ -77,4 +71,8 @@ class Group < Namespace @@ -77,4 +71,8 @@ class Group < Namespace
77 self.errors.add :avatar, "only images allowed" 71 self.errors.add :avatar, "only images allowed"
78 end 72 end
79 end 73 end
  74 +
  75 + def public_profile?
  76 + projects.public_only.any?
  77 + end
80 end 78 end
app/models/namespace.rb
@@ -47,14 +47,6 @@ class Namespace < ActiveRecord::Base @@ -47,14 +47,6 @@ class Namespace < ActiveRecord::Base
47 def self.global_id 47 def self.global_id
48 'GLN' 48 'GLN'
49 end 49 end
50 -  
51 - def projects_accessible_to(user)  
52 - projects.accessible_to(user)  
53 - end  
54 -  
55 - def has_projects_accessible_to?(user)  
56 - projects_accessible_to(user).present?  
57 - end  
58 50
59 def to_param 51 def to_param
60 path 52 path
app/models/project.rb
@@ -164,12 +164,6 @@ class Project < ActiveRecord::Base @@ -164,12 +164,6 @@ class Project < ActiveRecord::Base
164 where(visibility_level: visibility_levels) 164 where(visibility_level: visibility_levels)
165 end 165 end
166 166
167 - def accessible_to(user)  
168 - accessible_ids = publicish(user).pluck(:id)  
169 - accessible_ids += user.authorized_projects.pluck(:id) if user  
170 - where(id: accessible_ids)  
171 - end  
172 -  
173 def with_push 167 def with_push
174 includes(:events).where('events.action = ?', Event::PUSHED) 168 includes(:events).where('events.action = ?', Event::PUSHED)
175 end 169 end
app/services/search/global_service.rb
@@ -12,7 +12,7 @@ module Search @@ -12,7 +12,7 @@ module Search
12 return result unless query.present? 12 return result unless query.present?
13 13
14 group = Group.find_by(id: params[:group_id]) if params[:group_id].present? 14 group = Group.find_by(id: params[:group_id]) if params[:group_id].present?
15 - projects = Project.accessible_to(current_user) 15 + projects = ProjectsFinder.new.execute(current_user)
16 projects = projects.where(namespace_id: group.id) if group 16 projects = projects.where(namespace_id: group.id) if group
17 project_ids = projects.pluck(:id) 17 project_ids = projects.pluck(:id)
18 18