Commit 32db15b2 authored by Rémy Coutable's avatar Rémy Coutable

Merge branch '28810-projectfinder-should-handle-more-options' into 'master'

ProjectsFinder should handle more options

Closes #28810

See merge request !9682
parents d7e3f232 b996a82f
...@@ -3,6 +3,7 @@ class Admin::ProjectsController < Admin::ApplicationController ...@@ -3,6 +3,7 @@ class Admin::ProjectsController < Admin::ApplicationController
before_action :group, only: [:show, :transfer] before_action :group, only: [:show, :transfer]
def index def index
params[:sort] ||= 'latest_activity_desc'
@projects = Project.with_statistics @projects = Project.with_statistics
@projects = @projects.in_namespace(params[:namespace_id]) if params[:namespace_id].present? @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? @projects = @projects.where(visibility_level: params[:visibility_level]) if params[:visibility_level].present?
......
# == 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
module ParamsBackwardCompatibility
private
def set_non_archived_param
params[:non_archived] = params[:archived].blank?
end
end
class Dashboard::ProjectsController < Dashboard::ApplicationController class Dashboard::ProjectsController < Dashboard::ApplicationController
include FilterProjects include ParamsBackwardCompatibility
before_action :set_non_archived_param
before_action :default_sorting
def index def index
@projects = load_projects(current_user.authorized_projects) @projects = load_projects(params.merge(non_public: true)).page(params[:page])
@projects = @projects.sort(@sort = params[:sort])
@projects = @projects.page(params[:page])
respond_to do |format| respond_to do |format|
format.html { @last_push = current_user.recent_push } format.html { @last_push = current_user.recent_push }
...@@ -21,10 +22,8 @@ class Dashboard::ProjectsController < Dashboard::ApplicationController ...@@ -21,10 +22,8 @@ class Dashboard::ProjectsController < Dashboard::ApplicationController
end end
def starred def starred
@projects = load_projects(current_user.viewable_starred_projects) @projects = load_projects(params.merge(starred: true)).
@projects = @projects.includes(:forked_from_project, :tags) includes(:forked_from_project, :tags).page(params[:page])
@projects = @projects.sort(@sort = params[:sort])
@projects = @projects.page(params[:page])
@last_push = current_user.recent_push @last_push = current_user.recent_push
@groups = [] @groups = []
...@@ -41,14 +40,18 @@ class Dashboard::ProjectsController < Dashboard::ApplicationController ...@@ -41,14 +40,18 @@ class Dashboard::ProjectsController < Dashboard::ApplicationController
private private
def load_projects(base_scope) def default_sorting
projects = base_scope.sorted_by_activity.includes(:route, namespace: :route) 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 end
def load_events 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 = event_filter.apply_filter(@events).with_associations
@events = @events.limit(20).offset(params[:offset] || 0) @events = @events.limit(20).offset(params[:offset] || 0)
end end
......
class Explore::ProjectsController < Explore::ApplicationController class Explore::ProjectsController < Explore::ApplicationController
include FilterProjects include ParamsBackwardCompatibility
before_action :set_non_archived_param
def index def index
@projects = load_projects params[:sort] ||= 'latest_activity_desc'
@tags = @projects.tags_on(:tags) @sort = params[:sort]
@projects = @projects.tagged_with(params[:tag]) if params[:tag].present? @projects = load_projects.page(params[:page])
@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])
respond_to do |format| respond_to do |format|
format.html format.html
...@@ -21,10 +19,9 @@ class Explore::ProjectsController < Explore::ApplicationController ...@@ -21,10 +19,9 @@ class Explore::ProjectsController < Explore::ApplicationController
end end
def trending def trending
@projects = load_projects(Project.trending) params[:trending] = true
@projects = filter_projects(@projects) @sort = params[:sort]
@projects = @projects.sort(@sort = params[:sort]) @projects = load_projects.page(params[:page])
@projects = @projects.page(params[:page])
respond_to do |format| respond_to do |format|
format.html format.html
...@@ -37,10 +34,7 @@ class Explore::ProjectsController < Explore::ApplicationController ...@@ -37,10 +34,7 @@ class Explore::ProjectsController < Explore::ApplicationController
end end
def starred def starred
@projects = load_projects @projects = load_projects.reorder('star_count DESC').page(params[:page])
@projects = filter_projects(@projects)
@projects = @projects.reorder('star_count DESC')
@projects = @projects.page(params[:page])
respond_to do |format| respond_to do |format|
format.html format.html
...@@ -52,10 +46,10 @@ class Explore::ProjectsController < Explore::ApplicationController ...@@ -52,10 +46,10 @@ class Explore::ProjectsController < Explore::ApplicationController
end end
end end
protected private
def load_projects(base_scope = nil) def load_projects
base_scope ||= ProjectsFinder.new.execute(current_user) ProjectsFinder.new(current_user: current_user, params: params).
base_scope.includes(:route, namespace: :route) execute.includes(:route, namespace: :route)
end end
end end
...@@ -27,7 +27,7 @@ class Groups::ApplicationController < ApplicationController ...@@ -27,7 +27,7 @@ class Groups::ApplicationController < ApplicationController
end end
def group_projects def group_projects
@projects ||= GroupProjectsFinder.new(group).execute(current_user) @projects ||= GroupProjectsFinder.new(group: group, current_user: current_user).execute
end end
def authorize_admin_group! def authorize_admin_group!
......
class GroupsController < Groups::ApplicationController class GroupsController < Groups::ApplicationController
include FilterProjects
include IssuesAction include IssuesAction
include MergeRequestsAction include MergeRequestsAction
include ParamsBackwardCompatibility
respond_to :html respond_to :html
...@@ -105,15 +105,16 @@ class GroupsController < Groups::ApplicationController ...@@ -105,15 +105,16 @@ class GroupsController < Groups::ApplicationController
protected protected
def setup_projects def setup_projects
set_non_archived_param
params[:sort] ||= 'latest_activity_desc'
@sort = params[:sort]
options = {} options = {}
options[:only_owned] = true if params[:shared] == '0' options[:only_owned] = true if params[:shared] == '0'
options[:only_shared] = true if params[:shared] == '1' 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.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? @projects = @projects.page(params[:page]) if params[:name].blank?
end end
......
...@@ -9,7 +9,7 @@ class Projects::ForksController < Projects::ApplicationController ...@@ -9,7 +9,7 @@ class Projects::ForksController < Projects::ApplicationController
def index def index
base_query = project.forks.includes(:creator) 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 @total_forks_count = base_query.size
@private_forks_count = @total_forks_count - @forks.size @private_forks_count = @total_forks_count - @forks.size
@public_forks_count = @total_forks_count - @private_forks_count @public_forks_count = @total_forks_count - @private_forks_count
......
...@@ -140,6 +140,6 @@ class UsersController < ApplicationController ...@@ -140,6 +140,6 @@ class UsersController < ApplicationController
end end
def projects_for_current_user def projects_for_current_user
ProjectsFinder.new.execute(current_user) ProjectsFinder.new(current_user: current_user).execute
end end
end end
class GroupProjectsFinder < UnionFinder # GroupProjectsFinder
def initialize(group, options = {}) #
# 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 @group = group
@options = options @options = options
end end
def execute(current_user = nil)
segments = group_projects(current_user)
find_union(segments, Project)
end
private private
def group_projects(current_user) def init_collection
only_owned = @options.fetch(:only_owned, false) only_owned = options.fetch(:only_owned, false)
only_shared = @options.fetch(:only_shared, false) only_shared = options.fetch(:only_shared, false)
projects = [] projects = []
if current_user if current_user
if @group.users.include?(current_user) if group.users.include?(current_user)
projects << @group.projects unless only_shared projects << group.projects unless only_shared
projects << @group.shared_projects unless only_owned projects << group.shared_projects unless only_owned
else else
unless only_shared unless only_shared
projects << @group.projects.visible_to_user(current_user) projects << group.projects.visible_to_user(current_user)
projects << @group.projects.public_to_user(current_user) projects << group.projects.public_to_user(current_user)
end end
unless only_owned unless only_owned
projects << @group.shared_projects.visible_to_user(current_user) projects << group.shared_projects.visible_to_user(current_user)
projects << @group.shared_projects.public_to_user(current_user) projects << group.shared_projects.public_to_user(current_user)
end end
end end
else else
projects << @group.projects.public_only unless only_shared projects << group.projects.public_only unless only_shared
projects << @group.shared_projects.public_only unless only_owned projects << group.shared_projects.public_only unless only_owned
end end
projects projects
end end
def union(items)
find_union(items, Project)
end
end end
...@@ -116,9 +116,9 @@ class IssuableFinder ...@@ -116,9 +116,9 @@ class IssuableFinder
if current_user && params[:authorized_only].presence && !current_user_related? if current_user && params[:authorized_only].presence && !current_user_related?
current_user.authorized_projects current_user.authorized_projects
elsif group elsif group
GroupProjectsFinder.new(group).execute(current_user) GroupProjectsFinder.new(group: group, current_user: current_user).execute
else 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 end
@projects = projects.with_feature_available_for_user(klass, current_user).reorder(nil) @projects = projects.with_feature_available_for_user(klass, current_user).reorder(nil)
...@@ -405,8 +405,4 @@ class IssuableFinder ...@@ -405,8 +405,4 @@ class IssuableFinder
def current_user_related? def current_user_related?
params[:scope] == 'created-by-me' || params[:scope] == 'authored' || params[:scope] == 'assigned-to-me' params[:scope] == 'created-by-me' || params[:scope] == 'authored' || params[:scope] == 'assigned-to-me'
end end
def projects_finder
@projects_finder ||= ProjectsFinder.new
end
end end
...@@ -83,7 +83,7 @@ class LabelsFinder < UnionFinder ...@@ -83,7 +83,7 @@ class LabelsFinder < UnionFinder
def projects def projects
return @projects if defined?(@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.in_namespace(params[:group_id]) if group?
@projects = @projects.where(id: params[:project_ids]) if projects? @projects = @projects.where(id: params[:project_ids]) if projects?
@projects = @projects.reorder(nil) @projects = @projects.reorder(nil)
......
# 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 class ProjectsFinder < UnionFinder
def execute(current_user = nil, project_ids_relation = nil) attr_accessor :params
segments = all_projects(current_user) attr_reader :current_user, :project_ids_relation
segments.map! { |s| s.where(id: project_ids_relation) } if 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 end
private private
def all_projects(current_user) def init_collection
projects = [] projects = []
projects << current_user.authorized_projects if current_user if params[:trending].present?
projects << Project.unscoped.public_to_user(current_user) 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 projects
end 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 end
...@@ -95,7 +95,7 @@ class TodosFinder ...@@ -95,7 +95,7 @@ class TodosFinder
def projects(items) def projects(items)
item_project_ids = items.reorder(nil).select(:project_id) 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 end
def type? def type?
......
...@@ -25,8 +25,8 @@ module SortingHelper ...@@ -25,8 +25,8 @@ module SortingHelper
def projects_sort_options_hash def projects_sort_options_hash
options = { options = {
sort_value_name => sort_title_name, sort_value_name => sort_title_name,
sort_value_recently_updated => sort_title_recently_updated, sort_value_latest_activity => sort_title_latest_activity,
sort_value_oldest_updated => sort_title_oldest_updated, sort_value_oldest_activity => sort_title_oldest_activity,
sort_value_recently_created => sort_title_recently_created, sort_value_recently_created => sort_title_recently_created,
sort_value_oldest_created => sort_title_oldest_created sort_value_oldest_created => sort_title_oldest_created
} }
...@@ -78,6 +78,14 @@ module SortingHelper ...@@ -78,6 +78,14 @@ module SortingHelper
'Last updated' 'Last updated'
end end
def sort_title_oldest_activity
'Oldest updated'
end
def sort_title_latest_activity
'Last updated'
end
def sort_title_oldest_created def sort_title_oldest_created
'Oldest created' 'Oldest created'
end end
...@@ -198,6 +206,14 @@ module SortingHelper ...@@ -198,6 +206,14 @@ module SortingHelper
'updated_desc' 'updated_desc'
end end
def sort_value_oldest_activity
'latest_activity_asc'
end
def sort_value_latest_activity
'latest_activity_desc'
end
def sort_value_oldest_created def sort_value_oldest_created
'created_asc' 'created_asc'
end end
......
...@@ -349,10 +349,15 @@ class Project < ActiveRecord::Base ...@@ -349,10 +349,15 @@ class Project < ActiveRecord::Base
end end
def sort(method) 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 # storage_size is a joined column so we need to
# pass a string to avoid AR adding the table name # pass a string to avoid AR adding the table name
reorder('project_statistics.storage_size DESC, projects.id DESC') 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 else
order_by(method) order_by(method)
end end
......
...@@ -12,7 +12,7 @@ class GroupPolicy < BasePolicy ...@@ -12,7 +12,7 @@ class GroupPolicy < BasePolicy
can_read ||= globally_viewable can_read ||= globally_viewable
can_read ||= member can_read ||= member
can_read ||= @user.admin? 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 can! :read_group if can_read
# Only group masters and group owners can create new projects # Only group masters and group owners can create new projects
...@@ -41,6 +41,6 @@ class GroupPolicy < BasePolicy ...@@ -41,6 +41,6 @@ class GroupPolicy < BasePolicy
return true if @subject.internal? && !@user.external? return true if @subject.internal? && !@user.external?
return true if @subject.users.include?(@user) return true if @subject.users.include?(@user)
GroupProjectsFinder.new(@subject).execute(@user).any? GroupProjectsFinder.new(group: @subject, current_user: @user).execute.any?
end end
end end
...@@ -8,7 +8,7 @@ module Search ...@@ -8,7 +8,7 @@ module Search
def execute def execute
group = Group.find_by(id: params[:group_id]) if params[:group_id].present? 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 if group
projects = projects.inside_path(group.full_path) projects = projects.inside_path(group.full_path)
......
- 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 .blank-state.blank-state-welcome
%h2.blank-state-welcome-title %h2.blank-state-welcome-title
Welcome to GitLab Welcome to GitLab
......
- @sort ||= sort_value_recently_updated - @sort ||= sort_value_latest_activity
.dropdown .dropdown
- toggle_text = projects_sort_options_hash[@sort] - toggle_text = projects_sort_options_hash[@sort]
= dropdown_toggle(toggle_text, { toggle: 'dropdown' }, { id: 'sort-projects-dropdown' }) = dropdown_toggle(toggle_text, { toggle: 'dropdown' }, { id: 'sort-projects-dropdown' })
......
---
title: ProjectsFinder should handle more options
merge_request: 9682
author: Jacopo Beschi @jacopo-beschi
...@@ -142,7 +142,7 @@ module API ...@@ -142,7 +142,7 @@ module API
end end
get ":id/projects" do get ":id/projects" do
group = find_group!(params[:id]) 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) projects = filter_projects(projects)
entity = params[:simple] ? Entities::BasicProjectDetails : Entities::Project entity = params[:simple] ? Entities::BasicProjectDetails : Entities::Project
present paginate(projects), with: entity, current_user: current_user present paginate(projects), with: entity, current_user: current_user
......
...@@ -84,7 +84,7 @@ module API ...@@ -84,7 +84,7 @@ module API
end end
get do get do
entity = current_user ? Entities::ProjectWithAccess : Entities::BasicProjectDetails 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 end
desc 'Create new project' do desc 'Create new project' do
......
...@@ -341,7 +341,7 @@ module API ...@@ -341,7 +341,7 @@ module API
not_found!('User') unless user not_found!('User') unless user
events = user.events. events = user.events.
merge(ProjectsFinder.new.execute(current_user)). merge(ProjectsFinder.new(current_user: current_user).execute).
references(:project). references(:project).
with_associations. with_associations.
recent recent
......
...@@ -151,7 +151,7 @@ module API ...@@ -151,7 +151,7 @@ module API
end end
get ":id/projects" do get ":id/projects" do
group = find_group!(params[:id]) 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) projects = filter_projects(projects)
entity = params[:simple] ? ::API::Entities::BasicProjectDetails : Entities::Project entity = params[:simple] ? ::API::Entities::BasicProjectDetails : Entities::Project
present paginate(projects), with: entity, current_user: current_user present paginate(projects), with: entity, current_user: current_user
......
...@@ -107,7 +107,7 @@ module API ...@@ -107,7 +107,7 @@ module API
end end
get '/visible' do get '/visible' do
entity = current_user ? ::API::V3::Entities::ProjectWithAccess : ::API::Entities::BasicProjectDetails 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 end
desc 'Get a projects list for authenticated user' do desc 'Get a projects list for authenticated user' do
......
...@@ -138,7 +138,7 @@ module API ...@@ -138,7 +138,7 @@ module API
not_found!('User') unless user not_found!('User') unless user
events = user.events. events = user.events.
merge(ProjectsFinder.new.execute(current_user)). merge(ProjectsFinder.new(current_user: current_user).execute).
references(:project). references(:project).
with_associations. with_associations.
recent recent
......
...@@ -3,8 +3,9 @@ require 'spec_helper' ...@@ -3,8 +3,9 @@ require 'spec_helper'
describe GroupProjectsFinder do describe GroupProjectsFinder do
let(:group) { create(:group) } let(:group) { create(:group) }
let(:current_user) { create(:user) } 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!(:public_project) { create(:empty_project, :public, group: group, path: '1') }
let!(:private_project) { create(:empty_project, :private, group: group, path: '2') } let!(:private_project) { create(:empty_project, :private, group: group, path: '2') }
...@@ -18,22 +19,27 @@ describe GroupProjectsFinder do ...@@ -18,22 +19,27 @@ describe GroupProjectsFinder do
shared_project_3.project_group_links.create(group_access: Gitlab::Access::MASTER, group: group) shared_project_3.project_group_links.create(group_access: Gitlab::Access::MASTER, group: group)
end end
subject { finder.execute }
describe 'with a group member current user' do 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 context "only shared" do
subject { described_class.new(group, only_shared: true).execute(current_user) } let(:options) { { only_shared: true } }
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 end
context "only owned" do context "only owned" do
subject { described_class.new(group, only_owned: true).execute(current_user) } let(:options) { { only_owned: true } }
it { is_expected.to eq([private_project, public_project]) }
it { is_expected.to match_array([private_project, public_project]) }
end end
context "all" do context "all" do
subject { described_class.new(group).execute(current_user) } it { is_expected.to match_array([shared_project_3, shared_project_2, shared_project_1, private_project, public_project]) }
it { is_expected.to eq([shared_project_3, shared_project_2, shared_project_1, private_project, public_project]) }
end end
end end
...@@ -44,47 +50,57 @@ describe GroupProjectsFinder do ...@@ -44,47 +50,57 @@ describe GroupProjectsFinder do
end end
context "only shared" do context "only shared" do
let(:options) { { only_shared: true } }
context "without external user" do context "without external user" do
subject { described_class.new(group, only_shared: true).execute(current_user) } it { is_expected.to match_array([shared_project_3, shared_project_2, shared_project_1]) }
it { is_expected.to eq([shared_project_3, shared_project_2, shared_project_1]) }
end end
context "with external user" do context "with external user" do
before { current_user.update_attributes(external: true) } before do
subject { described_class.new(group, only_shared: true).execute(current_user) } current_user.update_attributes(external: true)
it { is_expected.to eq([shared_project_2, shared_project_1]) } end
it { is_expected.to match_array([shared_project_2, shared_project_1]) }
end end
end end
context "only owned" do context "only owned" do
let(:options) { { only_owned: true } }
context "without external user" do context "without external user" do
before { private_project.team << [current_user, Gitlab::Access::MASTER] } before do
subject { described_class.new(group, only_owned: true).execute(current_user) } private_project.team << [current_user, Gitlab::Access::MASTER]
it { is_expected.to eq([private_project, public_project]) } end
it { is_expected.to match_array([private_project, public_project]) }
end end
context "with external user" do context "with external user" do
before { current_user.update_attributes(external: true) } before do
subject { described_class.new(group, only_owned: true).execute(current_user) } current_user.update_attributes(external: true)
it { is_expected.to eq([public_project]) } end
end
context "all" do it { is_expected.to eq([public_project]) }
subject { described_class.new(group).execute(current_user) }
it { is_expected.to eq([shared_project_3, shared_project_2, shared_project_1, public_project]) }
end end
end end
context "all" do
it { is_expected.to match_array([shared_project_3, shared_project_2, shared_project_1, public_project]) }
end
end end
describe "no user" do describe "no user" do
context "only shared" do context "only shared" do
subject { described_class.new(group, only_shared: true).execute(current_user) } let(:options) { { only_shared: true } }
it { is_expected.to eq([shared_project_3, shared_project_1]) }
it { is_expected.to match_array([shared_project_3, shared_project_1]) }
end end
context "only owned" do context "only owned" do
subject { described_class.new(group, only_owned: true).execute(current_user) } let(:options) { { only_owned: true } }
it { is_expected.to eq([public_project]) }
it { is_expected.to eq([public_project]) }
end end
end end
end end
...@@ -21,38 +21,144 @@ describe ProjectsFinder do ...@@ -21,38 +21,144 @@ describe ProjectsFinder do
create(:empty_project, :private, name: 'D', path: 'D') create(:empty_project, :private, name: 'D', path: 'D')
end 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 describe 'without a user' do
subject { finder.execute } let(:current_user) { nil }
it { is_expected.to eq([public_project]) } it { is_expected.to eq([public_project]) }
end end
describe 'with a user' do describe 'with a user' do
subject { finder.execute(user) }
describe 'without private projects' do 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 end
describe 'with private projects' do describe 'with private projects' do
before do before do
private_project.add_user(user, Gitlab::Access::MASTER) private_project.add_master(user)
end end
it do it { is_expected.to match_array([public_project, internal_project, private_project]) }
is_expected.to eq([public_project, internal_project, private_project])
end
end end
end end
describe 'with project_ids_relation' do describe 'with project_ids_relation' do
let(:project_ids_relation) { Project.where(id: internal_project.id) } let(:project_ids_relation) { Project.where(id: internal_project.id) }
subject { finder.execute(user, project_ids_relation) }
it { is_expected.to eq([internal_project]) } it { is_expected.to eq([internal_project]) }
end 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
end end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment