From 33dc5171e5885bbc1de1db7b9be58453edfa9453 Mon Sep 17 00:00:00 2001 From: Oswaldo Ferreira Date: Tue, 25 Jul 2017 09:35:45 +0000 Subject: Resolve "More RESTful API: include resource URLs in responses" --- lib/api/api.rb | 1 + lib/api/entities.rb | 52 ++++++++++++++++++++++++++++ lib/api/helpers/related_resources_helpers.rb | 28 +++++++++++++++ lib/api/issues.rb | 2 +- lib/api/v3/entities.rb | 31 ++++++++++++++++- 5 files changed, 112 insertions(+), 2 deletions(-) create mode 100644 lib/api/helpers/related_resources_helpers.rb (limited to 'lib/api') diff --git a/lib/api/api.rb b/lib/api/api.rb index efcf0976a81..9a983d31ac6 100644 --- a/lib/api/api.rb +++ b/lib/api/api.rb @@ -3,6 +3,7 @@ module API include APIGuard allow_access_with_scope :api + prefix :api version %w(v3 v4), using: :path diff --git a/lib/api/entities.rb b/lib/api/entities.rb index 1719e9f7205..c165236105f 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -82,6 +82,38 @@ module API end class Project < Grape::Entity + include ::API::Helpers::RelatedResourcesHelpers + + expose :_links do + expose :self do |project| + expose_url(api_v4_projects_path(id: project.id)) + end + + expose :issues, if: -> (*args) { issues_available?(*args) } do |project| + expose_url(api_v4_projects_issues_path(id: project.id)) + end + + expose :merge_requests, if: -> (*args) { mrs_available?(*args) } do |project| + expose_url(api_v4_projects_merge_requests_path(id: project.id)) + end + + expose :repo_branches do |project| + expose_url(api_v4_projects_repository_branches_path(id: project.id)) + end + + expose :labels do |project| + expose_url(api_v4_projects_labels_path(id: project.id)) + end + + expose :events do |project| + expose_url(api_v4_projects_events_path(id: project.id)) + end + + expose :members do |project| + expose_url(api_v4_projects_members_path(id: project.id)) + end + end + expose :id, :description, :default_branch, :tag_list expose :archived?, as: :archived expose :visibility, :ssh_url_to_repo, :http_url_to_repo, :web_url @@ -297,6 +329,26 @@ module API end class Issue < IssueBasic + include ::API::Helpers::RelatedResourcesHelpers + + expose :_links do + expose :self do |issue| + expose_url(api_v4_project_issue_path(id: issue.project_id, issue_iid: issue.iid)) + end + + expose :notes do |issue| + expose_url(api_v4_projects_issues_notes_path(id: issue.project_id, noteable_id: issue.iid)) + end + + expose :award_emoji do |issue| + expose_url(api_v4_projects_issues_award_emoji_path(id: issue.project_id, issue_iid: issue.iid)) + end + + expose :project do |issue| + expose_url(api_v4_projects_path(id: issue.project_id)) + end + end + expose :subscribed do |issue, options| issue.subscribed?(options[:current_user], options[:project] || issue.project) end diff --git a/lib/api/helpers/related_resources_helpers.rb b/lib/api/helpers/related_resources_helpers.rb new file mode 100644 index 00000000000..769cc1457fc --- /dev/null +++ b/lib/api/helpers/related_resources_helpers.rb @@ -0,0 +1,28 @@ +module API + module Helpers + module RelatedResourcesHelpers + include GrapeRouteHelpers::NamedRouteMatcher + + def issues_available?(project, options) + available?(:issues, project, options[:current_user]) + end + + def mrs_available?(project, options) + available?(:merge_requests, project, options[:current_user]) + end + + def expose_url(path) + url_options = Rails.application.routes.default_url_options + protocol, host, port = url_options.slice(:protocol, :host, :port).values + + URI::HTTP.build(scheme: protocol, host: host, port: port, path: path).to_s + end + + private + + def available?(feature, project, current_user) + project.feature_available?(feature, current_user) + end + end + end +end diff --git a/lib/api/issues.rb b/lib/api/issues.rb index 14b26f28ebf..93ebe18508d 100644 --- a/lib/api/issues.rb +++ b/lib/api/issues.rb @@ -112,7 +112,7 @@ module API params do requires :issue_iid, type: Integer, desc: 'The internal ID of a project issue' end - get ":id/issues/:issue_iid" do + get ":id/issues/:issue_iid", as: :api_v4_project_issue do issue = find_project_issue(params[:issue_iid]) present issue, with: Entities::Issue, current_user: current_user, project: user_project end diff --git a/lib/api/v3/entities.rb b/lib/api/v3/entities.rb index 3759250f7f6..773f667abe0 100644 --- a/lib/api/v3/entities.rb +++ b/lib/api/v3/entities.rb @@ -259,11 +259,40 @@ module API expose :job_events, as: :build_events end - class Issue < ::API::Entities::Issue + class ProjectEntity < Grape::Entity + expose :id, :iid + expose(:project_id) { |entity| entity&.project.try(:id) } + expose :title, :description + expose :state, :created_at, :updated_at + end + + class IssueBasic < ProjectEntity + expose :label_names, as: :labels + expose :milestone, using: ::API::Entities::Milestone + expose :assignees, :author, using: ::API::Entities::UserBasic + + expose :assignee, using: ::API::Entities::UserBasic do |issue, options| + issue.assignees.first + end + + expose :user_notes_count + expose :upvotes, :downvotes + expose :due_date + expose :confidential + + expose :web_url do |issue, options| + Gitlab::UrlBuilder.build(issue) + end + end + + class Issue < IssueBasic unexpose :assignees expose :assignee do |issue, options| ::API::Entities::UserBasic.represent(issue.assignees.first, options) end + expose :subscribed do |issue, options| + issue.subscribed?(options[:current_user], options[:project] || issue.project) + end end end end -- cgit v1.2.3