summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFrancisco Lopez <fjlopez@gitlab.com>2017-11-27 12:24:33 +0100
committerFrancisco Lopez <fjlopez@gitlab.com>2017-12-01 18:32:12 +0100
commit58c5b463ff75618a557d067c16f49ef581cda85c (patch)
tree6de7fc1cb446b6120e8eb6c777912904b77efffd
parentc85f9c5b1d320f7a6f75e3d08bbafd2fb20d3f58 (diff)
downloadgitlab-ce-58c5b463ff75618a557d067c16f49ef581cda85c.tar.gz
Refactored /projects and /user/:user_id/projects endpoints
-rw-r--r--lib/api/entities.rb48
-rw-r--r--lib/api/groups.rb16
-rw-r--r--lib/api/projects.rb4
-rw-r--r--lib/api/projects_relation_builder.rb34
4 files changed, 77 insertions, 25 deletions
diff --git a/lib/api/entities.rb b/lib/api/entities.rb
index 5b9b0afed0f..8f41b930c0a 100644
--- a/lib/api/entities.rb
+++ b/lib/api/entities.rb
@@ -94,7 +94,13 @@ module API
project.avatar_url(only_path: false)
end
expose :star_count, :forks_count
- expose :last_activity_at
+ expose :created_at, :last_activity_at
+
+ def self.preload_relation(projects_relation)
+ projects_relation.preload(:project_feature, :route)
+ .preload(namespace: [:route, :owner],
+ tags: :taggings)
+ end
end
class Project < BasicProjectDetails
@@ -128,6 +134,18 @@ module API
expose :members do |project|
expose_url(api_v4_projects_members_path(id: project.id))
end
+
+ def self.preload_relation(projects_relation)
+ super(projects_relation).preload(:group)
+ .preload(project_group_links: :group,
+ fork_network: :root_project,
+ forked_project_link: :forked_from_project,
+ forked_from_project: [:route, :forks, namespace: :route, tags: :taggings])
+ end
+
+ def self.forks_counting_projects(projects_relation)
+ projects_relation + projects_relation.map(&:forked_from_project).compact
+ end
end
expose :archived?, as: :archived
@@ -635,9 +653,16 @@ module API
class MemberAccess < Grape::Entity
expose :access_level
expose :notification_level do |member, options|
- if member.notification_setting
- ::NotificationSetting.levels[member.notification_setting.level]
- end
+ notification = member_notification_setting(member)
+ ::NotificationSetting.levels[notification.level] if notification
+ end
+
+ private
+
+ def member_notification_setting(member)
+ member.user.notification_settings.select do |notification|
+ notification.source_id == member.source_id && notification.source_type == member.source_type
+ end.last
end
end
@@ -680,18 +705,21 @@ module API
expose :permissions do
expose :project_access, using: Entities::ProjectAccess do |project, options|
if options.key?(:project_members)
- (options[:project_members] || []).find { |member| member.source_id == project.id }
- else
- project.project_members.find_by(user_id: options[:current_user].id)
+ (options[:project_members] || []).select { |member| member.source_id == project.id }.last
+ elsif project.project_members.any?
+ # This is not the bet option to search in a CollectionProxy, but if
+ # we use find_by we will perform another query, even if the association
+ # is loaded
+ project.project_members.select { |project_member| project_member.user_id == options[:current_user].id }.last
end
end
expose :group_access, using: Entities::GroupAccess do |project, options|
if project.group
if options.key?(:group_members)
- (options[:group_members] || []).find { |member| member.source_id == project.namespace_id }
- else
- project.group.group_members.find_by(user_id: options[:current_user].id)
+ (options[:group_members] || []).select { |member| member.source_id == project.namespace_id }.last
+ elsif project.group.group_members.any?
+ project.group.group_members.select { |group_member| group_member.user_id == options[:current_user].id }.last
end
end
end
diff --git a/lib/api/groups.rb b/lib/api/groups.rb
index 83c7898150a..b81f07a1770 100644
--- a/lib/api/groups.rb
+++ b/lib/api/groups.rb
@@ -55,19 +55,8 @@ module API
def find_group_projects(params)
group = find_group!(params[:id])
projects = GroupProjectsFinder.new(group: group, current_user: current_user, params: project_finder_params).execute
- projects = projects.preload(:project_feature, :route, :group)
- .preload(namespace: [:route, :owner],
- tags: :taggings,
- project_group_links: :group,
- fork_network: :root_project,
- forked_project_link: :forked_from_project,
- forked_from_project: [:route, :forks, namespace: :route, tags: :taggings])
projects = reorder_projects(projects)
- projects = paginate(projects)
- projects_with_forks = projects + projects.map(&:forked_from_project).compact
- ::Projects::BatchForksCountService.new(projects_with_forks).refresh_cache
- ::Projects::BatchOpenIssuesCountService.new(projects).refresh_cache
- projects
+ paginate(projects)
end
def present_groups(params, groups)
@@ -190,7 +179,8 @@ module API
get ":id/projects" do
projects = find_group_projects(params)
entity = params[:simple] ? Entities::BasicProjectDetails : Entities::Project
- present projects, with: entity, current_user: current_user
+
+ present entity.prepare_relation(projects), with: entity, current_user: current_user
end
desc 'Get a list of subgroups in this group.' do
diff --git a/lib/api/projects.rb b/lib/api/projects.rb
index 4cd7e714aa2..12506203429 100644
--- a/lib/api/projects.rb
+++ b/lib/api/projects.rb
@@ -79,9 +79,9 @@ module API
projects = projects.with_statistics if params[:statistics]
projects = projects.with_issues_enabled if params[:with_issues_enabled]
projects = projects.with_merge_requests_enabled if params[:with_merge_requests_enabled]
+ projects = paginate(projects)
if current_user
- projects = projects.includes(:route, :taggings, namespace: :route)
project_members = current_user.project_members
group_members = current_user.group_members
end
@@ -95,7 +95,7 @@ module API
)
options[:with] = Entities::BasicProjectDetails if params[:simple]
- present paginate(projects), options
+ present options[:with].prepare_relation(projects), options
end
end
diff --git a/lib/api/projects_relation_builder.rb b/lib/api/projects_relation_builder.rb
new file mode 100644
index 00000000000..57df6157225
--- /dev/null
+++ b/lib/api/projects_relation_builder.rb
@@ -0,0 +1,34 @@
+module API
+ module ProjectsRelationBuilder
+ extend ActiveSupport::Concern
+
+ module ClassMethods
+ def prepare_relation(relation)
+ relation = preload_relation(relation)
+ execute_batch_counting(relation)
+ relation
+ end
+
+ def preload_relation(relation)
+ raise NotImplementedError, 'self.preload_relation method must be defined and return a relation'
+ end
+
+ def forks_counting_projects(projects_relation)
+ projects_relation
+ end
+
+ def batch_forks_counting(projects_relation)
+ ::Projects::BatchForksCountService.new(forks_counting_projects(projects_relation)).refresh_cache
+ end
+
+ def batch_open_issues_counting(projects_relation)
+ ::Projects::BatchOpenIssuesCountService.new(projects_relation).refresh_cache
+ end
+
+ def execute_batch_counting(projects_relation)
+ batch_forks_counting(projects_relation)
+ batch_open_issues_counting(projects_relation)
+ end
+ end
+ end
+end