From 5ec28dc387fb4adc3c5b65ac47819a8663186954 Mon Sep 17 00:00:00 2001 From: Alexandru Croitor Date: Mon, 8 Apr 2019 14:17:22 +0300 Subject: Changes to issues api When issues_controller endpoint was used for search, the parameters passed to the controller were slightly different then the ones passed to API. Because the searchbar UI is reused in different places and builds the parameters passed to request in same way we need to account for old parameter names. Add issues_statistics api endpoints Adds issue_statistics api endpoints for issue lists and returns counts of issues for all, closed and opened states. Expose more label attributes based on a param When requesting issues list through API expose more attributes for labels, like color, description if with_labels_data param is being passed, avoiding this way to change response schema for users that already use API. https://gitlab.com/gitlab-org/gitlab-ce/issues/57402 --- lib/api/entities.rb | 10 ++++- lib/api/helpers/issues_helpers.rb | 37 +++++++++++++++++++ lib/api/issues.rb | 78 ++++++++++++++++++++++++++------------- 3 files changed, 97 insertions(+), 28 deletions(-) (limited to 'lib') diff --git a/lib/api/entities.rb b/lib/api/entities.rb index 296688ba25b..a57c7e9f851 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -542,9 +542,13 @@ module API class IssueBasic < ProjectEntity expose :closed_at expose :closed_by, using: Entities::UserBasic - expose :labels do |issue| + expose :labels do |issue, options| # Avoids an N+1 query since labels are preloaded - issue.labels.map(&:title).sort + if options[:with_labels_data] + ::API::Entities::LabelBasic.represent(issue.labels.sort_by(&:title)) + else + issue.labels.map(&:title).sort + end end expose :milestone, using: Entities::Milestone expose :assignees, :author, using: Entities::UserBasic @@ -560,6 +564,8 @@ module API expose :due_date expose :confidential expose :discussion_locked + expose(:has_tasks) {|issue, _| !issue.task_list_items.empty? } + expose :task_status, if: -> (issue, _) { !issue.task_list_items.empty? } expose :web_url do |issue| Gitlab::UrlBuilder.build(issue) diff --git a/lib/api/helpers/issues_helpers.rb b/lib/api/helpers/issues_helpers.rb index f6762910b0c..00aaf5243b7 100644 --- a/lib/api/helpers/issues_helpers.rb +++ b/lib/api/helpers/issues_helpers.rb @@ -18,6 +18,43 @@ module API :title ] end + + def issue_finder(args = {}) + args = declared_params.merge(args) + + args.delete(:id) + args[:milestone_title] ||= args.delete(:milestone) + args[:milestone_title] ||= args.delete(:milestone_title) + args[:label_name] ||= args.delete(:labels) + args[:scope] = args[:scope].underscore if args[:scope] + + IssuesFinder.new(current_user, args) + end + + def find_issues(args = {}) + # rubocop: disable CodeReuse/ActiveRecord + finder = issue_finder(args) + issues = finder.execute.with_api_entity_associations + order_by = declared_params[:sort].present? && %w(asc desc).include?(declared_params[:sort].downcase) + issues = issues.reorder(order_options_with_tie_breaker) if order_by + issues + # rubocop: enable CodeReuse/ActiveRecord + end + + def issues_statistics(args = {}) + finder = issue_finder(args) + counter = Gitlab::IssuablesCountForState.new(finder) + + { + statistics: { + counts: { + all: counter[:all], + closed: counter[:closed], + opened: counter[:opened] + } + } + } + end end end end diff --git a/lib/api/issues.rb b/lib/api/issues.rb index d0a93b77951..67da1c46480 100644 --- a/lib/api/issues.rb +++ b/lib/api/issues.rb @@ -3,27 +3,12 @@ module API class Issues < Grape::API include PaginationParams + helpers Helpers::IssuesHelpers + helpers ::Gitlab::IssuableMetadata before { authenticate_non_get! } - helpers ::Gitlab::IssuableMetadata - helpers do - # rubocop: disable CodeReuse/ActiveRecord - def find_issues(args = {}) - args = declared_params.merge(args) - - args.delete(:id) - args[:milestone_title] = args.delete(:milestone) - args[:label_name] = args.delete(:labels) - args[:scope] = args[:scope].underscore if args[:scope] - - issues = IssuesFinder.new(current_user, args).execute - .with_api_entity_associations - issues.reorder(order_options_with_tie_breaker) - end - # rubocop: enable CodeReuse/ActiveRecord - if Gitlab.ee? params :issues_params_ee do optional :weight, types: [Integer, String], integer_none_any: true, desc: 'The weight of the issue' @@ -35,13 +20,14 @@ module API end params :issues_params do - optional :labels, type: Array[String], coerce_with: Validations::Types::LabelsList.coerce, desc: 'Comma-separated list of label names' + optional :labels, :label_name, type: Array[String], coerce_with: Validations::Types::LabelsList.coerce, desc: 'Comma-separated list of label names' + optional :with_labels_data, type: Boolean, desc: 'Return more label data than just lable title', default: false optional :milestone, type: String, desc: 'Milestone title' optional :order_by, type: String, values: %w[created_at updated_at], default: 'created_at', desc: 'Return issues ordered by `created_at` or `updated_at` fields.' - optional :sort, type: String, values: %w[asc desc], default: 'desc', + optional :sort, type: String, default: 'desc', desc: 'Return issues sorted in `asc` or `desc` order.' - optional :milestone, type: String, desc: 'Return issues for a specific milestone' + optional :milestone, :milestone_title, type: String, desc: 'Return issues for a specific milestone' optional :iids, type: Array[Integer], desc: 'The IID array of issues' optional :search, type: String, desc: 'Search issues for text present in the title, description, or any combination of these' optional :in, type: String, desc: '`title`, `description`, or a string joining them with comma' @@ -50,12 +36,17 @@ module API optional :updated_after, type: DateTime, desc: 'Return issues updated after the specified time' optional :updated_before, type: DateTime, desc: 'Return issues updated before the specified time' optional :author_id, type: Integer, desc: 'Return issues which are authored by the user with the given ID' + optional :author_username, type: String, desc: 'Return issues which are authored by the user with the given username' optional :assignee_id, types: [Integer, String], integer_none_any: true, desc: 'Return issues which are assigned to the user with the given ID' + optional :assignee_username, type: Array[String], + desc: 'Return issues which are assigned to the user with the given username' optional :scope, type: String, values: %w[created-by-me assigned-to-me created_by_me assigned_to_me all], desc: 'Return issues for the given scope: `created_by_me`, `assigned_to_me` or `all`' optional :my_reaction_emoji, type: String, desc: 'Return issues reacted by the authenticated user by the given emoji' optional :confidential, type: Boolean, desc: 'Filter confidential or public issues' + optional :state, type: String, values: %w[opened closed all], default: 'all', + desc: 'Return opened, closed, or all issues' use :pagination use :issues_params_ee if Gitlab.ee? @@ -75,13 +66,25 @@ module API end end + desc "Get currently authenticated user's issues statistics" + params do + use :issues_params + optional :scope, type: String, values: %w[created-by-me assigned-to-me created_by_me assigned_to_me all], default: 'created_by_me', + desc: 'Return issues for the given scope: `created_by_me`, `assigned_to_me` or `all`' + end + get '/issues_statistics' do + authenticate! unless params[:scope] == 'all' + + stats = issues_statistics + + present stats, with: Grape::Presenters::Presenter + end + resource :issues do desc "Get currently authenticated user's issues" do success Entities::IssueBasic end params do - optional :state, type: String, values: %w[opened closed all], default: 'all', - desc: 'Return opened, closed, or all issues' use :issues_params optional :scope, type: String, values: %w[created-by-me assigned-to-me created_by_me assigned_to_me all], default: 'created_by_me', desc: 'Return issues for the given scope: `created_by_me`, `assigned_to_me` or `all`' @@ -92,6 +95,7 @@ module API options = { with: Entities::IssueBasic, + with_labels_data: declared_params[:with_labels_data], current_user: current_user, issuable_metadata: issuable_meta_data(issues, 'Issue') } @@ -108,8 +112,6 @@ module API success Entities::IssueBasic end params do - optional :state, type: String, values: %w[opened closed all], default: 'all', - desc: 'Return opened, closed, or all issues' use :issues_params end get ":id/issues" do @@ -119,12 +121,25 @@ module API options = { with: Entities::IssueBasic, + with_labels_data: declared_params[:with_labels_data], current_user: current_user, issuable_metadata: issuable_meta_data(issues, 'Issue') } present issues, options end + + desc 'Get statistics for the list of group issues' + params do + use :issues_params + end + get ":id/issues_statistics" do + group = find_group!(params[:id]) + + stats = issues_statistics(group_id: group.id, include_subgroups: true) + + present stats, with: Grape::Presenters::Presenter + end end params do @@ -137,8 +152,6 @@ module API success Entities::IssueBasic end params do - optional :state, type: String, values: %w[opened closed all], default: 'all', - desc: 'Return opened, closed, or all issues' use :issues_params end get ":id/issues" do @@ -148,6 +161,7 @@ module API options = { with: Entities::IssueBasic, + with_labels_data: declared_params[:with_labels_data], current_user: current_user, project: user_project, issuable_metadata: issuable_meta_data(issues, 'Issue') @@ -156,6 +170,18 @@ module API present issues, options end + desc 'Get statistics for the list of project issues' + params do + use :issues_params + end + get ":id/issues_statistics" do + project = find_project!(params[:id]) + + stats = issues_statistics(project_id: project.id) + + present stats, with: Grape::Presenters::Presenter + end + desc 'Get a single project issue' do success Entities::Issue end -- cgit v1.2.3