summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--app/controllers/admin/projects_controller.rb1
-rw-r--r--app/controllers/concerns/filter_projects.rb17
-rw-r--r--app/controllers/concerns/params_backward_compatibility.rb7
-rw-r--r--app/controllers/dashboard/projects_controller.rb27
-rw-r--r--app/controllers/explore/projects_controller.rb34
-rw-r--r--app/controllers/groups/application_controller.rb2
-rw-r--r--app/controllers/groups_controller.rb11
-rw-r--r--app/controllers/projects/forks_controller.rb2
-rw-r--r--app/controllers/users_controller.rb2
-rw-r--r--app/finders/group_projects_finder.rb59
-rw-r--r--app/finders/issuable_finder.rb8
-rw-r--r--app/finders/labels_finder.rb2
-rw-r--r--app/finders/projects_finder.rb88
-rw-r--r--app/finders/todos_finder.rb2
-rw-r--r--app/helpers/sorting_helper.rb20
-rw-r--r--app/models/project.rb7
-rw-r--r--app/policies/group_policy.rb4
-rw-r--r--app/services/search/global_service.rb2
-rw-r--r--app/views/dashboard/projects/_zero_authorized_projects.html.haml2
-rw-r--r--app/views/shared/projects/_dropdown.html.haml2
-rw-r--r--changelogs/unreleased/28810-projectfinder-should-handle-more-options.yml4
-rw-r--r--lib/api/groups.rb2
-rw-r--r--lib/api/projects.rb2
-rw-r--r--lib/api/users.rb2
-rw-r--r--lib/api/v3/groups.rb2
-rw-r--r--lib/api/v3/projects.rb2
-rw-r--r--lib/api/v3/users.rb2
-rw-r--r--spec/finders/group_projects_finder_spec.rb70
-rw-r--r--spec/finders/projects_finder_spec.rb128
29 files changed, 370 insertions, 143 deletions
diff --git a/app/controllers/admin/projects_controller.rb b/app/controllers/admin/projects_controller.rb
index daecfc832bf..a1975c0e341 100644
--- a/app/controllers/admin/projects_controller.rb
+++ b/app/controllers/admin/projects_controller.rb
@@ -3,6 +3,7 @@ class Admin::ProjectsController < Admin::ApplicationController
before_action :group, only: [:show, :transfer]
def index
+ params[:sort] ||= 'latest_activity_desc'
@projects = Project.with_statistics
@projects = @projects.in_namespace(params[:namespace_id]) if params[:namespace_id].present?
@projects = @projects.where(visibility_level: params[:visibility_level]) if params[:visibility_level].present?
diff --git a/app/controllers/concerns/filter_projects.rb b/app/controllers/concerns/filter_projects.rb
deleted file mode 100644
index 6014112256a..00000000000
--- a/app/controllers/concerns/filter_projects.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-# == FilterProjects
-#
-# Controller concern to handle projects filtering
-# * by name
-# * by archived state
-#
-module FilterProjects
- extend ActiveSupport::Concern
-
- def filter_projects(projects)
- projects = projects.search(params[:name]) if params[:name].present?
- projects = projects.non_archived if params[:archived].blank?
- projects = projects.personal(current_user) if params[:personal].present? && current_user
-
- projects
- end
-end
diff --git a/app/controllers/concerns/params_backward_compatibility.rb b/app/controllers/concerns/params_backward_compatibility.rb
new file mode 100644
index 00000000000..b0e3d9c7b34
--- /dev/null
+++ b/app/controllers/concerns/params_backward_compatibility.rb
@@ -0,0 +1,7 @@
+module ParamsBackwardCompatibility
+ private
+
+ def set_non_archived_param
+ params[:non_archived] = params[:archived].blank?
+ end
+end
diff --git a/app/controllers/dashboard/projects_controller.rb b/app/controllers/dashboard/projects_controller.rb
index be00d765f73..5a1efcab1a3 100644
--- a/app/controllers/dashboard/projects_controller.rb
+++ b/app/controllers/dashboard/projects_controller.rb
@@ -1,10 +1,11 @@
class Dashboard::ProjectsController < Dashboard::ApplicationController
- include FilterProjects
+ include ParamsBackwardCompatibility
+
+ before_action :set_non_archived_param
+ before_action :default_sorting
def index
- @projects = load_projects(current_user.authorized_projects)
- @projects = @projects.sort(@sort = params[:sort])
- @projects = @projects.page(params[:page])
+ @projects = load_projects(params.merge(non_public: true)).page(params[:page])
respond_to do |format|
format.html { @last_push = current_user.recent_push }
@@ -21,10 +22,8 @@ class Dashboard::ProjectsController < Dashboard::ApplicationController
end
def starred
- @projects = load_projects(current_user.viewable_starred_projects)
- @projects = @projects.includes(:forked_from_project, :tags)
- @projects = @projects.sort(@sort = params[:sort])
- @projects = @projects.page(params[:page])
+ @projects = load_projects(params.merge(starred: true)).
+ includes(:forked_from_project, :tags).page(params[:page])
@last_push = current_user.recent_push
@groups = []
@@ -41,14 +40,18 @@ class Dashboard::ProjectsController < Dashboard::ApplicationController
private
- def load_projects(base_scope)
- projects = base_scope.sorted_by_activity.includes(:route, namespace: :route)
+ def default_sorting
+ params[:sort] ||= 'latest_activity_desc'
+ @sort = params[:sort]
+ end
- filter_projects(projects)
+ def load_projects(finder_params)
+ ProjectsFinder.new(params: finder_params, current_user: current_user).
+ execute.includes(:route, namespace: :route)
end
def load_events
- @events = Event.in_projects(load_projects(current_user.authorized_projects))
+ @events = Event.in_projects(load_projects(params.merge(non_public: true)))
@events = event_filter.apply_filter(@events).with_associations
@events = @events.limit(20).offset(params[:offset] || 0)
end
diff --git a/app/controllers/explore/projects_controller.rb b/app/controllers/explore/projects_controller.rb
index 6167f9bd335..8f1870759e4 100644
--- a/app/controllers/explore/projects_controller.rb
+++ b/app/controllers/explore/projects_controller.rb
@@ -1,14 +1,12 @@
class Explore::ProjectsController < Explore::ApplicationController
- include FilterProjects
+ include ParamsBackwardCompatibility
+
+ before_action :set_non_archived_param
def index
- @projects = load_projects
- @tags = @projects.tags_on(:tags)
- @projects = @projects.tagged_with(params[:tag]) if params[:tag].present?
- @projects = @projects.where(visibility_level: params[:visibility_level]) if params[:visibility_level].present?
- @projects = filter_projects(@projects)
- @projects = @projects.sort(@sort = params[:sort])
- @projects = @projects.includes(:namespace).page(params[:page])
+ params[:sort] ||= 'latest_activity_desc'
+ @sort = params[:sort]
+ @projects = load_projects.page(params[:page])
respond_to do |format|
format.html
@@ -21,10 +19,9 @@ class Explore::ProjectsController < Explore::ApplicationController
end
def trending
- @projects = load_projects(Project.trending)
- @projects = filter_projects(@projects)
- @projects = @projects.sort(@sort = params[:sort])
- @projects = @projects.page(params[:page])
+ params[:trending] = true
+ @sort = params[:sort]
+ @projects = load_projects.page(params[:page])
respond_to do |format|
format.html
@@ -37,10 +34,7 @@ class Explore::ProjectsController < Explore::ApplicationController
end
def starred
- @projects = load_projects
- @projects = filter_projects(@projects)
- @projects = @projects.reorder('star_count DESC')
- @projects = @projects.page(params[:page])
+ @projects = load_projects.reorder('star_count DESC').page(params[:page])
respond_to do |format|
format.html
@@ -52,10 +46,10 @@ class Explore::ProjectsController < Explore::ApplicationController
end
end
- protected
+ private
- def load_projects(base_scope = nil)
- base_scope ||= ProjectsFinder.new.execute(current_user)
- base_scope.includes(:route, namespace: :route)
+ def load_projects
+ ProjectsFinder.new(current_user: current_user, params: params).
+ execute.includes(:route, namespace: :route)
end
end
diff --git a/app/controllers/groups/application_controller.rb b/app/controllers/groups/application_controller.rb
index 8b69c18d689..29ffaeb19c1 100644
--- a/app/controllers/groups/application_controller.rb
+++ b/app/controllers/groups/application_controller.rb
@@ -27,7 +27,7 @@ class Groups::ApplicationController < ApplicationController
end
def group_projects
- @projects ||= GroupProjectsFinder.new(group).execute(current_user)
+ @projects ||= GroupProjectsFinder.new(group: group, current_user: current_user).execute
end
def authorize_admin_group!
diff --git a/app/controllers/groups_controller.rb b/app/controllers/groups_controller.rb
index 05f9ee1ee90..78c9f1f7004 100644
--- a/app/controllers/groups_controller.rb
+++ b/app/controllers/groups_controller.rb
@@ -1,7 +1,7 @@
class GroupsController < Groups::ApplicationController
- include FilterProjects
include IssuesAction
include MergeRequestsAction
+ include ParamsBackwardCompatibility
respond_to :html
@@ -105,15 +105,16 @@ class GroupsController < Groups::ApplicationController
protected
def setup_projects
+ set_non_archived_param
+ params[:sort] ||= 'latest_activity_desc'
+ @sort = params[:sort]
+
options = {}
options[:only_owned] = true if params[:shared] == '0'
options[:only_shared] = true if params[:shared] == '1'
- @projects = GroupProjectsFinder.new(group, options).execute(current_user)
+ @projects = GroupProjectsFinder.new(params: params, group: group, options: options, current_user: current_user).execute
@projects = @projects.includes(:namespace)
- @projects = @projects.sorted_by_activity
- @projects = filter_projects(@projects)
- @projects = @projects.sort(@sort = params[:sort])
@projects = @projects.page(params[:page]) if params[:name].blank?
end
diff --git a/app/controllers/projects/forks_controller.rb b/app/controllers/projects/forks_controller.rb
index ba46e2528e6..1eb3800e49d 100644
--- a/app/controllers/projects/forks_controller.rb
+++ b/app/controllers/projects/forks_controller.rb
@@ -9,7 +9,7 @@ class Projects::ForksController < Projects::ApplicationController
def index
base_query = project.forks.includes(:creator)
- @forks = base_query.merge(ProjectsFinder.new.execute(current_user))
+ @forks = base_query.merge(ProjectsFinder.new(current_user: current_user).execute)
@total_forks_count = base_query.size
@private_forks_count = @total_forks_count - @forks.size
@public_forks_count = @total_forks_count - @private_forks_count
diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb
index 2683614d2e8..a452bbba422 100644
--- a/app/controllers/users_controller.rb
+++ b/app/controllers/users_controller.rb
@@ -140,6 +140,6 @@ class UsersController < ApplicationController
end
def projects_for_current_user
- ProjectsFinder.new.execute(current_user)
+ ProjectsFinder.new(current_user: current_user).execute
end
end
diff --git a/app/finders/group_projects_finder.rb b/app/finders/group_projects_finder.rb
index 3b9a421b118..f043c38c6f9 100644
--- a/app/finders/group_projects_finder.rb
+++ b/app/finders/group_projects_finder.rb
@@ -1,42 +1,63 @@
-class GroupProjectsFinder < UnionFinder
- def initialize(group, options = {})
+# GroupProjectsFinder
+#
+# Used to filter Projects by set of params
+#
+# Arguments:
+# current_user - which user use
+# project_ids_relation: int[] - project ids to use
+# group
+# options:
+# only_owned: boolean
+# only_shared: boolean
+# params:
+# sort: string
+# visibility_level: int
+# tags: string[]
+# personal: boolean
+# search: string
+# non_archived: boolean
+#
+class GroupProjectsFinder < ProjectsFinder
+ attr_reader :group, :options
+
+ def initialize(group:, params: {}, options: {}, current_user: nil, project_ids_relation: nil)
+ super(params: params, current_user: current_user, project_ids_relation: project_ids_relation)
@group = group
@options = options
end
- def execute(current_user = nil)
- segments = group_projects(current_user)
- find_union(segments, Project)
- end
-
private
- def group_projects(current_user)
- only_owned = @options.fetch(:only_owned, false)
- only_shared = @options.fetch(:only_shared, false)
+ def init_collection
+ only_owned = options.fetch(:only_owned, false)
+ only_shared = options.fetch(:only_shared, false)
projects = []
if current_user
- if @group.users.include?(current_user)
- projects << @group.projects unless only_shared
- projects << @group.shared_projects unless only_owned
+ if group.users.include?(current_user)
+ projects << group.projects unless only_shared
+ projects << group.shared_projects unless only_owned
else
unless only_shared
- projects << @group.projects.visible_to_user(current_user)
- projects << @group.projects.public_to_user(current_user)
+ projects << group.projects.visible_to_user(current_user)
+ projects << group.projects.public_to_user(current_user)
end
unless only_owned
- projects << @group.shared_projects.visible_to_user(current_user)
- projects << @group.shared_projects.public_to_user(current_user)
+ projects << group.shared_projects.visible_to_user(current_user)
+ projects << group.shared_projects.public_to_user(current_user)
end
end
else
- projects << @group.projects.public_only unless only_shared
- projects << @group.shared_projects.public_only unless only_owned
+ projects << group.projects.public_only unless only_shared
+ projects << group.shared_projects.public_only unless only_owned
end
projects
end
+
+ def union(items)
+ find_union(items, Project)
+ end
end
diff --git a/app/finders/issuable_finder.rb b/app/finders/issuable_finder.rb
index f7ebb1807d7..4cc42b88a2a 100644
--- a/app/finders/issuable_finder.rb
+++ b/app/finders/issuable_finder.rb
@@ -116,9 +116,9 @@ class IssuableFinder
if current_user && params[:authorized_only].presence && !current_user_related?
current_user.authorized_projects
elsif group
- GroupProjectsFinder.new(group).execute(current_user)
+ GroupProjectsFinder.new(group: group, current_user: current_user).execute
else
- projects_finder.execute(current_user, item_project_ids(items))
+ ProjectsFinder.new(current_user: current_user, project_ids_relation: item_project_ids(items)).execute
end
@projects = projects.with_feature_available_for_user(klass, current_user).reorder(nil)
@@ -405,8 +405,4 @@ class IssuableFinder
def current_user_related?
params[:scope] == 'created-by-me' || params[:scope] == 'authored' || params[:scope] == 'assigned-to-me'
end
-
- def projects_finder
- @projects_finder ||= ProjectsFinder.new
- end
end
diff --git a/app/finders/labels_finder.rb b/app/finders/labels_finder.rb
index e52083f86e4..042d792dada 100644
--- a/app/finders/labels_finder.rb
+++ b/app/finders/labels_finder.rb
@@ -83,7 +83,7 @@ class LabelsFinder < UnionFinder
def projects
return @projects if defined?(@projects)
- @projects = skip_authorization ? Project.all : ProjectsFinder.new.execute(current_user)
+ @projects = skip_authorization ? Project.all : ProjectsFinder.new(current_user: current_user).execute
@projects = @projects.in_namespace(params[:group_id]) if group?
@projects = @projects.where(id: params[:project_ids]) if projects?
@projects = @projects.reorder(nil)
diff --git a/app/finders/projects_finder.rb b/app/finders/projects_finder.rb
index 18ec45f300d..f6d8226bf3f 100644
--- a/app/finders/projects_finder.rb
+++ b/app/finders/projects_finder.rb
@@ -1,19 +1,93 @@
+# ProjectsFinder
+#
+# Used to filter Projects by set of params
+#
+# Arguments:
+# current_user - which user use
+# project_ids_relation: int[] - project ids to use
+# params:
+# trending: boolean
+# non_public: boolean
+# starred: boolean
+# sort: string
+# visibility_level: int
+# tags: string[]
+# personal: boolean
+# search: string
+# non_archived: boolean
+#
class ProjectsFinder < UnionFinder
- def execute(current_user = nil, project_ids_relation = nil)
- segments = all_projects(current_user)
- segments.map! { |s| s.where(id: project_ids_relation) } if project_ids_relation
+ attr_accessor :params
+ attr_reader :current_user, :project_ids_relation
- find_union(segments, Project).with_route
+ def initialize(params: {}, current_user: nil, project_ids_relation: nil)
+ @params = params
+ @current_user = current_user
+ @project_ids_relation = project_ids_relation
+ end
+
+ def execute
+ items = init_collection
+ items = by_ids(items)
+ items = union(items)
+ items = by_personal(items)
+ items = by_visibilty_level(items)
+ items = by_tags(items)
+ items = by_search(items)
+ items = by_archived(items)
+ sort(items)
end
private
- def all_projects(current_user)
+ def init_collection
projects = []
- projects << current_user.authorized_projects if current_user
- projects << Project.unscoped.public_to_user(current_user)
+ if params[:trending].present?
+ projects << Project.trending
+ elsif params[:starred].present? && current_user
+ projects << current_user.viewable_starred_projects
+ else
+ projects << current_user.authorized_projects if current_user
+ projects << Project.unscoped.public_to_user(current_user) unless params[:non_public].present?
+ end
projects
end
+
+ def by_ids(items)
+ project_ids_relation ? items.map { |item| item.where(id: project_ids_relation) } : items
+ end
+
+ def union(items)
+ find_union(items, Project).with_route
+ end
+
+ def by_personal(items)
+ (params[:personal].present? && current_user) ? items.personal(current_user) : items
+ end
+
+ def by_visibilty_level(items)
+ params[:visibility_level].present? ? items.where(visibility_level: params[:visibility_level]) : items
+ end
+
+ def by_tags(items)
+ params[:tag].present? ? items.tagged_with(params[:tag]) : items
+ end
+
+ def by_search(items)
+ params[:search] ||= params[:name]
+ params[:search].present? ? items.search(params[:search]) : items
+ end
+
+ def sort(items)
+ params[:sort].present? ? items.sort(params[:sort]) : items
+ end
+
+ def by_archived(projects)
+ # Back-compatibility with the places where `params[:archived]` can be set explicitly to `false`
+ params[:non_archived] = !Gitlab::Utils.to_boolean(params[:archived]) if params.key?(:archived)
+
+ params[:non_archived] ? projects.non_archived : projects
+ end
end
diff --git a/app/finders/todos_finder.rb b/app/finders/todos_finder.rb
index b7f091f334d..dc13386184e 100644
--- a/app/finders/todos_finder.rb
+++ b/app/finders/todos_finder.rb
@@ -95,7 +95,7 @@ class TodosFinder
def projects(items)
item_project_ids = items.reorder(nil).select(:project_id)
- ProjectsFinder.new.execute(current_user, item_project_ids)
+ ProjectsFinder.new(current_user: current_user, project_ids_relation: item_project_ids).execute
end
def type?
diff --git a/app/helpers/sorting_helper.rb b/app/helpers/sorting_helper.rb
index 5c89cbea3fc..3a5d1b97c36 100644
--- a/app/helpers/sorting_helper.rb
+++ b/app/helpers/sorting_helper.rb
@@ -25,8 +25,8 @@ module SortingHelper
def projects_sort_options_hash
options = {
sort_value_name => sort_title_name,
- sort_value_recently_updated => sort_title_recently_updated,
- sort_value_oldest_updated => sort_title_oldest_updated,
+ sort_value_latest_activity => sort_title_latest_activity,
+ sort_value_oldest_activity => sort_title_oldest_activity,
sort_value_recently_created => sort_title_recently_created,
sort_value_oldest_created => sort_title_oldest_created
}
@@ -78,6 +78,14 @@ module SortingHelper
'Last updated'
end
+ def sort_title_oldest_activity
+ 'Oldest updated'
+ end
+
+ def sort_title_latest_activity
+ 'Last updated'
+ end
+
def sort_title_oldest_created
'Oldest created'
end
@@ -198,6 +206,14 @@ module SortingHelper
'updated_desc'
end
+ def sort_value_oldest_activity
+ 'latest_activity_asc'
+ end
+
+ def sort_value_latest_activity
+ 'latest_activity_desc'
+ end
+
def sort_value_oldest_created
'created_asc'
end
diff --git a/app/models/project.rb b/app/models/project.rb
index 12fd0668ff8..1f95d00baf8 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -349,10 +349,15 @@ class Project < ActiveRecord::Base
end
def sort(method)
- if method == 'storage_size_desc'
+ case method.to_s
+ when 'storage_size_desc'
# storage_size is a joined column so we need to
# pass a string to avoid AR adding the table name
reorder('project_statistics.storage_size DESC, projects.id DESC')
+ when 'latest_activity_desc'
+ reorder(last_activity_at: :desc)
+ when 'latest_activity_asc'
+ reorder(last_activity_at: :asc)
else
order_by(method)
end
diff --git a/app/policies/group_policy.rb b/app/policies/group_policy.rb
index 4cc21696eb6..cb58c115d54 100644
--- a/app/policies/group_policy.rb
+++ b/app/policies/group_policy.rb
@@ -12,7 +12,7 @@ class GroupPolicy < BasePolicy
can_read ||= globally_viewable
can_read ||= member
can_read ||= @user.admin?
- can_read ||= GroupProjectsFinder.new(@subject).execute(@user).any?
+ can_read ||= GroupProjectsFinder.new(group: @subject, current_user: @user).execute.any?
can! :read_group if can_read
# Only group masters and group owners can create new projects
@@ -41,6 +41,6 @@ class GroupPolicy < BasePolicy
return true if @subject.internal? && !@user.external?
return true if @subject.users.include?(@user)
- GroupProjectsFinder.new(@subject).execute(@user).any?
+ GroupProjectsFinder.new(group: @subject, current_user: @user).execute.any?
end
end
diff --git a/app/services/search/global_service.rb b/app/services/search/global_service.rb
index c1549df5ac6..8409b592b72 100644
--- a/app/services/search/global_service.rb
+++ b/app/services/search/global_service.rb
@@ -8,7 +8,7 @@ module Search
def execute
group = Group.find_by(id: params[:group_id]) if params[:group_id].present?
- projects = ProjectsFinder.new.execute(current_user)
+ projects = ProjectsFinder.new(current_user: current_user).execute
if group
projects = projects.inside_path(group.full_path)
diff --git a/app/views/dashboard/projects/_zero_authorized_projects.html.haml b/app/views/dashboard/projects/_zero_authorized_projects.html.haml
index 1bbd4602ecf..8843d4e7c84 100644
--- a/app/views/dashboard/projects/_zero_authorized_projects.html.haml
+++ b/app/views/dashboard/projects/_zero_authorized_projects.html.haml
@@ -1,4 +1,4 @@
-- publicish_project_count = ProjectsFinder.new.execute(current_user).count
+- publicish_project_count = ProjectsFinder.new(current_user: current_user).execute.count
.blank-state.blank-state-welcome
%h2.blank-state-welcome-title
Welcome to GitLab
diff --git a/app/views/shared/projects/_dropdown.html.haml b/app/views/shared/projects/_dropdown.html.haml
index 2d25b8aad62..8939aeb6c3a 100644
--- a/app/views/shared/projects/_dropdown.html.haml
+++ b/app/views/shared/projects/_dropdown.html.haml
@@ -1,4 +1,4 @@
-- @sort ||= sort_value_recently_updated
+- @sort ||= sort_value_latest_activity
.dropdown
- toggle_text = projects_sort_options_hash[@sort]
= dropdown_toggle(toggle_text, { toggle: 'dropdown' }, { id: 'sort-projects-dropdown' })
diff --git a/changelogs/unreleased/28810-projectfinder-should-handle-more-options.yml b/changelogs/unreleased/28810-projectfinder-should-handle-more-options.yml
new file mode 100644
index 00000000000..e4be16d4b37
--- /dev/null
+++ b/changelogs/unreleased/28810-projectfinder-should-handle-more-options.yml
@@ -0,0 +1,4 @@
+---
+title: ProjectsFinder should handle more options
+merge_request: 9682
+author: Jacopo Beschi @jacopo-beschi
diff --git a/lib/api/groups.rb b/lib/api/groups.rb
index 8f3799417e3..605769eddde 100644
--- a/lib/api/groups.rb
+++ b/lib/api/groups.rb
@@ -142,7 +142,7 @@ module API
end
get ":id/projects" do
group = find_group!(params[:id])
- projects = GroupProjectsFinder.new(group).execute(current_user)
+ projects = GroupProjectsFinder.new(group: group, current_user: current_user).execute
projects = filter_projects(projects)
entity = params[:simple] ? Entities::BasicProjectDetails : Entities::Project
present paginate(projects), with: entity, current_user: current_user
diff --git a/lib/api/projects.rb b/lib/api/projects.rb
index 0fbe1669d45..766fbea53e6 100644
--- a/lib/api/projects.rb
+++ b/lib/api/projects.rb
@@ -84,7 +84,7 @@ module API
end
get do
entity = current_user ? Entities::ProjectWithAccess : Entities::BasicProjectDetails
- present_projects ProjectsFinder.new.execute(current_user), with: entity, statistics: params[:statistics]
+ present_projects ProjectsFinder.new(current_user: current_user).execute, with: entity, statistics: params[:statistics]
end
desc 'Create new project' do
diff --git a/lib/api/users.rb b/lib/api/users.rb
index 530ca0b5235..992a751b37d 100644
--- a/lib/api/users.rb
+++ b/lib/api/users.rb
@@ -341,7 +341,7 @@ module API
not_found!('User') unless user
events = user.events.
- merge(ProjectsFinder.new.execute(current_user)).
+ merge(ProjectsFinder.new(current_user: current_user).execute).
references(:project).
with_associations.
recent
diff --git a/lib/api/v3/groups.rb b/lib/api/v3/groups.rb
index c5b37622d79..9b27411ae21 100644
--- a/lib/api/v3/groups.rb
+++ b/lib/api/v3/groups.rb
@@ -151,7 +151,7 @@ module API
end
get ":id/projects" do
group = find_group!(params[:id])
- projects = GroupProjectsFinder.new(group).execute(current_user)
+ projects = GroupProjectsFinder.new(group: group, current_user: current_user).execute
projects = filter_projects(projects)
entity = params[:simple] ? ::API::Entities::BasicProjectDetails : Entities::Project
present paginate(projects), with: entity, current_user: current_user
diff --git a/lib/api/v3/projects.rb b/lib/api/v3/projects.rb
index b753dbab381..ba9748ada59 100644
--- a/lib/api/v3/projects.rb
+++ b/lib/api/v3/projects.rb
@@ -107,7 +107,7 @@ module API
end
get '/visible' do
entity = current_user ? ::API::V3::Entities::ProjectWithAccess : ::API::Entities::BasicProjectDetails
- present_projects ProjectsFinder.new.execute(current_user), with: entity
+ present_projects ProjectsFinder.new(current_user: current_user).execute, with: entity
end
desc 'Get a projects list for authenticated user' do
diff --git a/lib/api/v3/users.rb b/lib/api/v3/users.rb
index 5e18cecc431..f4cda3b2eba 100644
--- a/lib/api/v3/users.rb
+++ b/lib/api/v3/users.rb
@@ -138,7 +138,7 @@ module API
not_found!('User') unless user
events = user.events.
- merge(ProjectsFinder.new.execute(current_user)).
+ merge(ProjectsFinder.new(current_user: current_user).execute).
references(:project).
with_associations.
recent
diff --git a/spec/finders/group_projects_finder_spec.rb b/spec/finders/group_projects_finder_spec.rb
index ef97b061ca7..3c7c9bdcd08 100644
--- a/spec/finders/group_projects_finder_spec.rb
+++ b/spec/finders/group_projects_finder_spec.rb
@@ -3,8 +3,9 @@ require 'spec_helper'
describe GroupProjectsFinder do
let(:group) { create(:group) }
let(:current_user) { create(:user) }
+ let(:options) { {} }
- let(:finder) { described_class.new(source_user) }
+ let(:finder) { described_class.new(group: group, current_user: current_user, options: options) }
let!(:public_project) { create(:empty_project, :public, group: group, path: '1') }
let!(:private_project) { create(:empty_project, :private, group: group, path: '2') }
@@ -18,22 +19,27 @@ describe GroupProjectsFinder do
shared_project_3.project_group_links.create(group_access: Gitlab::Access::MASTER, group: group)
end
+ subject { finder.execute }
+
describe 'with a group member current user' do
- before { group.add_user(current_user, Gitlab::Access::MASTER) }
+ before do
+ group.add_master(current_user)
+ end
context "only shared" do
- subject { described_class.new(group, only_shared: true).execute(current_user) }
- it { is_expected.to eq([shared_project_3, shared_project_2, shared_project_1]) }
+ let(:options) { { only_shared: true } }
+
+ it { is_expected.to match_array([shared_project_3, shared_project_2, shared_project_1]) }
end
context "only owned" do
- subject { described_class.new(group, only_owned: true).execute(current_user) }
- it { is_expected.to eq([private_project, public_project]) }
+ let(:options) { { only_owned: true } }
+
+ it { is_expected.to match_array([private_project, public_project]) }
end
context "all" do
- subject { described_class.new(group).execute(current_user) }
- it { is_expected.to eq([shared_project_3, shared_project_2, shared_project_1, private_project, public_project]) }
+ it { is_expected.to match_array([shared_project_3, shared_project_2, shared_project_1, private_project, public_project]) }
end
end
@@ -44,47 +50,57 @@ describe GroupProjectsFinder do
end
context "only shared" do
+ let(:options) { { only_shared: true } }
+
context "without external user" do
- subject { described_class.new(group, only_shared: true).execute(current_user) }
- it { is_expected.to eq([shared_project_3, shared_project_2, shared_project_1]) }
+ it { is_expected.to match_array([shared_project_3, shared_project_2, shared_project_1]) }
end
context "with external user" do
- before { current_user.update_attributes(external: true) }
- subject { described_class.new(group, only_shared: true).execute(current_user) }
- it { is_expected.to eq([shared_project_2, shared_project_1]) }
+ before do
+ current_user.update_attributes(external: true)
+ end
+
+ it { is_expected.to match_array([shared_project_2, shared_project_1]) }
end
end
context "only owned" do
+ let(:options) { { only_owned: true } }
+
context "without external user" do
- before { private_project.team << [current_user, Gitlab::Access::MASTER] }
- subject { described_class.new(group, only_owned: true).execute(current_user) }
- it { is_expected.to eq([private_project, public_project]) }
+ before do
+ private_project.team << [current_user, Gitlab::Access::MASTER]
+ end
+
+ it { is_expected.to match_array([private_project, public_project]) }
end
context "with external user" do
- before { current_user.update_attributes(external: true) }
- subject { described_class.new(group, only_owned: true).execute(current_user) }
- it { is_expected.to eq([public_project]) }
- end
+ before do
+ current_user.update_attributes(external: true)
+ end
- context "all" do
- subject { described_class.new(group).execute(current_user) }
- it { is_expected.to eq([shared_project_3, shared_project_2, shared_project_1, public_project]) }
+ it { is_expected.to eq([public_project]) }
end
end
+
+ context "all" do
+ it { is_expected.to match_array([shared_project_3, shared_project_2, shared_project_1, public_project]) }
+ end
end
describe "no user" do
context "only shared" do
- subject { described_class.new(group, only_shared: true).execute(current_user) }
- it { is_expected.to eq([shared_project_3, shared_project_1]) }
+ let(:options) { { only_shared: true } }
+
+ it { is_expected.to match_array([shared_project_3, shared_project_1]) }
end
context "only owned" do
- subject { described_class.new(group, only_owned: true).execute(current_user) }
- it { is_expected.to eq([public_project]) }
+ let(:options) { { only_owned: true } }
+
+ it { is_expected.to eq([public_project]) }
end
end
end
diff --git a/spec/finders/projects_finder_spec.rb b/spec/finders/projects_finder_spec.rb
index e44e7434c80..148adcffe3b 100644
--- a/spec/finders/projects_finder_spec.rb
+++ b/spec/finders/projects_finder_spec.rb
@@ -21,38 +21,144 @@ describe ProjectsFinder do
create(:empty_project, :private, name: 'D', path: 'D')
end
- let(:finder) { described_class.new }
+ let(:params) { {} }
+ let(:current_user) { user }
+ let(:project_ids_relation) { nil }
+ let(:finder) { described_class.new(params: params, current_user: current_user, project_ids_relation: project_ids_relation) }
+
+ subject { finder.execute }
describe 'without a user' do
- subject { finder.execute }
+ let(:current_user) { nil }
it { is_expected.to eq([public_project]) }
end
describe 'with a user' do
- subject { finder.execute(user) }
-
describe 'without private projects' do
- it { is_expected.to eq([public_project, internal_project]) }
+ it { is_expected.to match_array([public_project, internal_project]) }
end
describe 'with private projects' do
before do
- private_project.add_user(user, Gitlab::Access::MASTER)
+ private_project.add_master(user)
end
- it do
- is_expected.to eq([public_project, internal_project, private_project])
- end
+ it { is_expected.to match_array([public_project, internal_project, private_project]) }
end
end
describe 'with project_ids_relation' do
let(:project_ids_relation) { Project.where(id: internal_project.id) }
- subject { finder.execute(user, project_ids_relation) }
-
it { is_expected.to eq([internal_project]) }
end
+
+ describe 'filter by visibility_level' do
+ before do
+ private_project.add_master(user)
+ end
+
+ context 'private' do
+ let(:params) { { visibility_level: Gitlab::VisibilityLevel::PRIVATE } }
+
+ it { is_expected.to eq([private_project]) }
+ end
+
+ context 'internal' do
+ let(:params) { { visibility_level: Gitlab::VisibilityLevel::INTERNAL } }
+
+ it { is_expected.to eq([internal_project]) }
+ end
+
+ context 'public' do
+ let(:params) { { visibility_level: Gitlab::VisibilityLevel::PUBLIC } }
+
+ it { is_expected.to eq([public_project]) }
+ end
+ end
+
+ describe 'filter by tags' do
+ before do
+ public_project.tag_list.add('foo')
+ public_project.save!
+ end
+
+ let(:params) { { tag: 'foo' } }
+
+ it { is_expected.to eq([public_project]) }
+ end
+
+ describe 'filter by personal' do
+ let!(:personal_project) { create(:empty_project, namespace: user.namespace) }
+ let(:params) { { personal: true } }
+
+ it { is_expected.to eq([personal_project]) }
+ end
+
+ describe 'filter by search' do
+ let(:params) { { search: 'C' } }
+
+ it { is_expected.to eq([public_project]) }
+ end
+
+ describe 'filter by name for backward compatibility' do
+ let(:params) { { name: 'C' } }
+
+ it { is_expected.to eq([public_project]) }
+ end
+
+ describe 'filter by archived' do
+ let!(:archived_project) { create(:empty_project, :public, :archived, name: 'E', path: 'E') }
+
+ context 'non_archived=true' do
+ let(:params) { { non_archived: true } }
+
+ it { is_expected.to match_array([public_project, internal_project]) }
+ end
+
+ context 'non_archived=false' do
+ let(:params) { { non_archived: false } }
+
+ it { is_expected.to match_array([public_project, internal_project, archived_project]) }
+ end
+
+ describe 'filter by archived for backward compatibility' do
+ let(:params) { { archived: false } }
+
+ it { is_expected.to match_array([public_project, internal_project]) }
+ end
+ end
+
+ describe 'filter by trending' do
+ let!(:trending_project) { create(:trending_project, project: public_project) }
+ let(:params) { { trending: true } }
+
+ it { is_expected.to eq([public_project]) }
+ end
+
+ describe 'filter by non_public' do
+ let(:params) { { non_public: true } }
+ before do
+ private_project.add_developer(current_user)
+ end
+
+ it { is_expected.to eq([private_project]) }
+ end
+
+ describe 'filter by viewable_starred_projects' do
+ let(:params) { { starred: true } }
+ before do
+ current_user.toggle_star(public_project)
+ end
+
+ it { is_expected.to eq([public_project]) }
+ end
+
+ describe 'sorting' do
+ let(:params) { { sort: 'name_asc' } }
+
+ it { is_expected.to eq([internal_project, public_project]) }
+ end
end
end