summaryrefslogtreecommitdiff
path: root/lib/api
diff options
context:
space:
mode:
authorKamil Trzciński <ayufan@ayufan.eu>2018-02-28 20:35:22 +0100
committerKamil Trzciński <ayufan@ayufan.eu>2018-02-28 20:35:22 +0100
commite0401df1214397626e65e58166988fe62715d372 (patch)
tree087d8ca4a1611aa50a8ac98e66f7d1657ff1f90f /lib/api
parent2b7b60728426c10ef1188a1073d3630805773a35 (diff)
parent11c67e7c2f992299ff5918ce67995b73d1e0be6d (diff)
downloadgitlab-ce-e0401df1214397626e65e58166988fe62715d372.tar.gz
Merge commit '11c67e7c2f992299ff5918ce67995b73d1e0be6d' into object-storage-ee-to-ce-backport
Diffstat (limited to 'lib/api')
-rw-r--r--lib/api/api.rb1
-rw-r--r--lib/api/api_guard.rb24
-rw-r--r--lib/api/branches.rb23
-rw-r--r--lib/api/commits.rb18
-rw-r--r--lib/api/custom_attributes_endpoints.rb77
-rw-r--r--lib/api/entities.rb69
-rw-r--r--lib/api/helpers.rb40
-rw-r--r--lib/api/internal.rb9
-rw-r--r--lib/api/issues.rb3
-rw-r--r--lib/api/lint.rb2
-rw-r--r--lib/api/merge_requests.rb11
-rw-r--r--lib/api/notes.rb2
-rw-r--r--lib/api/notification_settings.rb2
-rw-r--r--lib/api/projects.rb23
-rw-r--r--lib/api/repositories.rb4
-rw-r--r--lib/api/tags.rb12
-rw-r--r--lib/api/templates.rb8
-rw-r--r--lib/api/users.rb24
-rw-r--r--lib/api/v3/branches.rb8
-rw-r--r--lib/api/v3/commits.rb16
-rw-r--r--lib/api/v3/entities.rb4
-rw-r--r--lib/api/v3/merge_requests.rb4
-rw-r--r--lib/api/v3/repositories.rb4
-rw-r--r--lib/api/v3/tags.rb4
-rw-r--r--lib/api/v3/templates.rb8
25 files changed, 270 insertions, 130 deletions
diff --git a/lib/api/api.rb b/lib/api/api.rb
index ee4e1688e12..79e55a2f4f7 100644
--- a/lib/api/api.rb
+++ b/lib/api/api.rb
@@ -8,7 +8,6 @@ module API
logger: Logger.new(LOG_FILENAME),
formatter: Gitlab::GrapeLogging::Formatters::LogrageWithTimestamp.new,
include: [
- GrapeLogging::Loggers::Response.new,
GrapeLogging::Loggers::FilterParameters.new,
GrapeLogging::Loggers::ClientEnv.new
]
diff --git a/lib/api/api_guard.rb b/lib/api/api_guard.rb
index c4c0fdda665..e79f988f549 100644
--- a/lib/api/api_guard.rb
+++ b/lib/api/api_guard.rb
@@ -75,7 +75,7 @@ module API
raise RevokedError
when AccessTokenValidationService::VALID
- @current_user = User.find(access_token.resource_owner_id)
+ User.find(access_token.resource_owner_id)
end
end
@@ -84,11 +84,13 @@ module API
return nil unless token_string.present?
- find_user_by_authentication_token(token_string) || find_user_by_personal_access_token(token_string, scopes)
- end
+ user =
+ find_user_by_authentication_token(token_string) ||
+ find_user_by_personal_access_token(token_string, scopes)
+
+ raise UnauthorizedError unless user
- def current_user
- @current_user
+ user
end
private
@@ -107,7 +109,16 @@ module API
end
def find_access_token
- @access_token ||= Doorkeeper.authenticate(doorkeeper_request, Doorkeeper.configuration.access_token_methods)
+ return @access_token if defined?(@access_token)
+
+ token = Doorkeeper::OAuth::Token.from_request(doorkeeper_request, *Doorkeeper.configuration.access_token_methods)
+ return @access_token = nil unless token
+
+ @access_token = Doorkeeper::AccessToken.by_token(token)
+ raise UnauthorizedError unless @access_token
+
+ @access_token.revoke_previous_refresh_token!
+ @access_token
end
def doorkeeper_request
@@ -169,6 +180,7 @@ module API
TokenNotFoundError = Class.new(StandardError)
ExpiredError = Class.new(StandardError)
RevokedError = Class.new(StandardError)
+ UnauthorizedError = Class.new(StandardError)
class InsufficientScopeError < StandardError
attr_reader :scopes
diff --git a/lib/api/branches.rb b/lib/api/branches.rb
index 642c1140fcc..61a2d688282 100644
--- a/lib/api/branches.rb
+++ b/lib/api/branches.rb
@@ -13,7 +13,7 @@ module API
end
resource :projects, requirements: API::PROJECT_ENDPOINT_REQUIREMENTS do
desc 'Get a project repository branches' do
- success Entities::RepoBranch
+ success Entities::Branch
end
params do
use :pagination
@@ -21,12 +21,15 @@ module API
get ':id/repository/branches' do
branches = ::Kaminari.paginate_array(user_project.repository.branches.sort_by(&:name))
- present paginate(branches), with: Entities::RepoBranch, project: user_project
+ # n+1: https://gitlab.com/gitlab-org/gitlab-ce/issues/37442
+ Gitlab::GitalyClient.allow_n_plus_1_calls do
+ present paginate(branches), with: Entities::Branch, project: user_project
+ end
end
resource ':id/repository/branches/:branch', requirements: BRANCH_ENDPOINT_REQUIREMENTS do
desc 'Get a single branch' do
- success Entities::RepoBranch
+ success Entities::Branch
end
params do
requires :branch, type: String, desc: 'The name of the branch'
@@ -38,7 +41,7 @@ module API
branch = user_project.repository.find_branch(params[:branch])
not_found!('Branch') unless branch
- present branch, with: Entities::RepoBranch, project: user_project
+ present branch, with: Entities::Branch, project: user_project
end
end
@@ -47,7 +50,7 @@ module API
# in `gitlab-org/gitlab-ce!5081`. The API interface has not been changed (to maintain compatibility),
# but it works with the changed data model to infer `developers_can_merge` and `developers_can_push`.
desc 'Protect a single branch' do
- success Entities::RepoBranch
+ success Entities::Branch
end
params do
requires :branch, type: String, desc: 'The name of the branch'
@@ -77,7 +80,7 @@ module API
end
if protected_branch.valid?
- present branch, with: Entities::RepoBranch, project: user_project
+ present branch, with: Entities::Branch, project: user_project
else
render_api_error!(protected_branch.errors.full_messages, 422)
end
@@ -85,7 +88,7 @@ module API
# Note: This API will be deprecated in favor of the protected branches API.
desc 'Unprotect a single branch' do
- success Entities::RepoBranch
+ success Entities::Branch
end
params do
requires :branch, type: String, desc: 'The name of the branch'
@@ -98,11 +101,11 @@ module API
protected_branch = user_project.protected_branches.find_by(name: branch.name)
protected_branch&.destroy
- present branch, with: Entities::RepoBranch, project: user_project
+ present branch, with: Entities::Branch, project: user_project
end
desc 'Create branch' do
- success Entities::RepoBranch
+ success Entities::Branch
end
params do
requires :branch, type: String, desc: 'The name of the branch'
@@ -116,7 +119,7 @@ module API
if result[:status] == :success
present result[:branch],
- with: Entities::RepoBranch,
+ with: Entities::Branch,
project: user_project
else
render_api_error!(result[:message], 400)
diff --git a/lib/api/commits.rb b/lib/api/commits.rb
index 4b8d248f5f7..4af37a2ad1d 100644
--- a/lib/api/commits.rb
+++ b/lib/api/commits.rb
@@ -13,7 +13,7 @@ module API
end
resource :projects, requirements: API::PROJECT_ENDPOINT_REQUIREMENTS do
desc 'Get a project repository commits' do
- success Entities::RepoCommit
+ success Entities::Commit
end
params do
optional :ref_name, type: String, desc: 'The name of a repository branch or tag, if not given the default branch is used'
@@ -46,11 +46,11 @@ module API
paginated_commits = Kaminari.paginate_array(commits, total_count: commit_count)
- present paginate(paginated_commits), with: Entities::RepoCommit
+ present paginate(paginated_commits), with: Entities::Commit
end
desc 'Commit multiple file changes as one commit' do
- success Entities::RepoCommitDetail
+ success Entities::CommitDetail
detail 'This feature was introduced in GitLab 8.13'
end
params do
@@ -72,14 +72,14 @@ module API
if result[:status] == :success
commit_detail = user_project.repository.commit(result[:result])
- present commit_detail, with: Entities::RepoCommitDetail
+ present commit_detail, with: Entities::CommitDetail
else
render_api_error!(result[:message], 400)
end
end
desc 'Get a specific commit of a project' do
- success Entities::RepoCommitDetail
+ success Entities::CommitDetail
failure [[404, 'Commit Not Found']]
end
params do
@@ -90,7 +90,7 @@ module API
not_found! 'Commit' unless commit
- present commit, with: Entities::RepoCommitDetail
+ present commit, with: Entities::CommitDetail
end
desc 'Get the diff for a specific commit of a project' do
@@ -104,7 +104,7 @@ module API
not_found! 'Commit' unless commit
- present commit.raw_diffs.to_a, with: Entities::RepoDiff
+ present commit.raw_diffs.to_a, with: Entities::Diff
end
desc "Get a commit's comments" do
@@ -126,7 +126,7 @@ module API
desc 'Cherry pick commit into a branch' do
detail 'This feature was introduced in GitLab 8.15'
- success Entities::RepoCommit
+ success Entities::Commit
end
params do
requires :sha, type: String, desc: 'A commit sha, or the name of a branch or tag to be cherry picked'
@@ -151,7 +151,7 @@ module API
if result[:status] == :success
branch = user_project.repository.find_branch(params[:branch])
- present user_project.repository.commit(branch.dereferenced_target), with: Entities::RepoCommit
+ present user_project.repository.commit(branch.dereferenced_target), with: Entities::Commit
else
render_api_error!(result[:message], 400)
end
diff --git a/lib/api/custom_attributes_endpoints.rb b/lib/api/custom_attributes_endpoints.rb
new file mode 100644
index 00000000000..5000aa0d9ac
--- /dev/null
+++ b/lib/api/custom_attributes_endpoints.rb
@@ -0,0 +1,77 @@
+module API
+ module CustomAttributesEndpoints
+ extend ActiveSupport::Concern
+
+ included do
+ attributable_class = name.demodulize.singularize
+ attributable_key = attributable_class.underscore
+ attributable_name = attributable_class.humanize(capitalize: false)
+ attributable_finder = "find_#{attributable_key}"
+
+ helpers do
+ params :custom_attributes_key do
+ requires :key, type: String, desc: 'The key of the custom attribute'
+ end
+ end
+
+ desc "Get all custom attributes on a #{attributable_name}" do
+ success Entities::CustomAttribute
+ end
+ get ':id/custom_attributes' do
+ resource = public_send(attributable_finder, params[:id]) # rubocop:disable GitlabSecurity/PublicSend
+ authorize! :read_custom_attribute
+
+ present resource.custom_attributes, with: Entities::CustomAttribute
+ end
+
+ desc "Get a custom attribute on a #{attributable_name}" do
+ success Entities::CustomAttribute
+ end
+ params do
+ use :custom_attributes_key
+ end
+ get ':id/custom_attributes/:key' do
+ resource = public_send(attributable_finder, params[:id]) # rubocop:disable GitlabSecurity/PublicSend
+ authorize! :read_custom_attribute
+
+ custom_attribute = resource.custom_attributes.find_by!(key: params[:key])
+
+ present custom_attribute, with: Entities::CustomAttribute
+ end
+
+ desc "Set a custom attribute on a #{attributable_name}"
+ params do
+ use :custom_attributes_key
+ requires :value, type: String, desc: 'The value of the custom attribute'
+ end
+ put ':id/custom_attributes/:key' do
+ resource = public_send(attributable_finder, params[:id]) # rubocop:disable GitlabSecurity/PublicSend
+ authorize! :update_custom_attribute
+
+ custom_attribute = resource.custom_attributes
+ .find_or_initialize_by(key: params[:key])
+
+ custom_attribute.update(value: params[:value])
+
+ if custom_attribute.valid?
+ present custom_attribute, with: Entities::CustomAttribute
+ else
+ render_validation_error!(custom_attribute)
+ end
+ end
+
+ desc "Delete a custom attribute on a #{attributable_name}"
+ params do
+ use :custom_attributes_key
+ end
+ delete ':id/custom_attributes/:key' do
+ resource = public_send(attributable_finder, params[:id]) # rubocop:disable GitlabSecurity/PublicSend
+ authorize! :update_custom_attribute
+
+ resource.custom_attributes.find_by!(key: params[:key]).destroy
+
+ status 204
+ end
+ end
+ end
+end
diff --git a/lib/api/entities.rb b/lib/api/entities.rb
index 52c49e5caa9..5f0bad14839 100644
--- a/lib/api/entities.rb
+++ b/lib/api/entities.rb
@@ -89,6 +89,9 @@ module API
expose :ssh_url_to_repo, :http_url_to_repo, :web_url
expose :name, :name_with_namespace
expose :path, :path_with_namespace
+ expose :avatar_url do |project, options|
+ project.avatar_url(only_path: false)
+ end
expose :star_count, :forks_count
expose :created_at, :last_activity_at
end
@@ -146,9 +149,7 @@ module API
expose :forked_from_project, using: Entities::BasicProjectDetails, if: lambda { |project, options| project.forked? }
expose :import_status
expose :import_error, if: lambda { |_project, options| options[:user_can_admin_project] }
- expose :avatar_url do |user, options|
- user.avatar_url(only_path: false)
- end
+
expose :open_issues_count, if: lambda { |project, options| project.feature_available?(:issues, options[:current_user]) }
expose :runners_token, if: lambda { |_project, options| options[:user_can_admin_project] }
expose :public_builds, as: :public_jobs
@@ -193,8 +194,8 @@ module API
class Group < Grape::Entity
expose :id, :name, :path, :description, :visibility
expose :lfs_enabled?, as: :lfs_enabled
- expose :avatar_url do |user, options|
- user.avatar_url(only_path: false)
+ expose :avatar_url do |group, options|
+ group.avatar_url(only_path: false)
end
expose :web_url
expose :request_access_enabled
@@ -219,7 +220,7 @@ module API
expose :shared_projects, using: Entities::Project
end
- class RepoCommit < Grape::Entity
+ class Commit < Grape::Entity
expose :id, :short_id, :title, :created_at
expose :parent_ids
expose :safe_message, as: :message
@@ -227,24 +228,28 @@ module API
expose :committer_name, :committer_email, :committed_date
end
- class RepoCommitStats < Grape::Entity
+ class CommitStats < Grape::Entity
expose :additions, :deletions, :total
end
- class RepoCommitDetail < RepoCommit
- expose :stats, using: Entities::RepoCommitStats
+ class CommitDetail < Commit
+ expose :stats, using: Entities::CommitStats
expose :status
+ expose :last_pipeline, using: 'API::Entities::PipelineBasic'
end
- class RepoBranch < Grape::Entity
+ class Branch < Grape::Entity
expose :name
- expose :commit, using: Entities::RepoCommit do |repo_branch, options|
+ expose :commit, using: Entities::Commit do |repo_branch, options|
options[:project].repository.commit(repo_branch.dereferenced_target)
end
expose :merged do |repo_branch, options|
- options[:project].repository.merged_to_root_ref?(repo_branch.name)
+ # n+1: https://gitlab.com/gitlab-org/gitlab-ce/issues/37442
+ Gitlab::GitalyClient.allow_n_plus_1_calls do
+ options[:project].repository.merged_to_root_ref?(repo_branch.name)
+ end
end
expose :protected do |repo_branch, options|
@@ -260,7 +265,7 @@ module API
end
end
- class RepoTreeObject < Grape::Entity
+ class TreeObject < Grape::Entity
expose :id, :name, :type, :path
expose :mode do |obj, options|
@@ -300,7 +305,7 @@ module API
expose :state, :created_at, :updated_at
end
- class RepoDiff < Grape::Entity
+ class Diff < Grape::Entity
expose :old_path, :new_path, :a_mode, :b_mode
expose :new_file?, as: :new_file
expose :renamed_file?, as: :renamed_file
@@ -332,6 +337,7 @@ module API
end
class IssueBasic < ProjectEntity
+ expose :closed_at
expose :labels do |issue, options|
# Avoids an N+1 query since labels are preloaded
issue.labels.map(&:title).sort
@@ -362,6 +368,7 @@ module API
end
expose :due_date
expose :confidential
+ expose :discussion_locked
expose :web_url do |issue, options|
Gitlab::UrlBuilder.build(issue)
@@ -458,6 +465,7 @@ module API
expose :diff_head_sha, as: :sha
expose :merge_commit_sha
expose :user_notes_count
+ expose :discussion_locked
expose :should_remove_source_branch?, as: :should_remove_source_branch
expose :force_remove_source_branch?, as: :force_remove_source_branch
@@ -477,7 +485,7 @@ module API
end
class MergeRequestChanges < MergeRequest
- expose :diffs, as: :changes, using: Entities::RepoDiff do |compare, _|
+ expose :diffs, as: :changes, using: Entities::Diff do |compare, _|
compare.raw_diffs(limits: false).to_a
end
end
@@ -488,9 +496,9 @@ module API
end
class MergeRequestDiffFull < MergeRequestDiff
- expose :commits, using: Entities::RepoCommit
+ expose :commits, using: Entities::Commit
- expose :diffs, using: Entities::RepoDiff do |compare, _|
+ expose :diffs, using: Entities::Diff do |compare, _|
compare.raw_diffs(limits: false).to_a
end
end
@@ -586,8 +594,7 @@ module API
expose :target_type
expose :target do |todo, options|
- target = todo.target_type == 'Commit' ? 'RepoCommit' : todo.target_type
- Entities.const_get(target).represent(todo.target, options)
+ Entities.const_get(todo.target_type).represent(todo.target, options)
end
expose :target_url do |todo, options|
@@ -723,15 +730,15 @@ module API
end
class Compare < Grape::Entity
- expose :commit, using: Entities::RepoCommit do |compare, options|
- Commit.decorate(compare.commits, nil).last
+ expose :commit, using: Entities::Commit do |compare, options|
+ ::Commit.decorate(compare.commits, nil).last
end
- expose :commits, using: Entities::RepoCommit do |compare, options|
- Commit.decorate(compare.commits, nil)
+ expose :commits, using: Entities::Commit do |compare, options|
+ ::Commit.decorate(compare.commits, nil)
end
- expose :diffs, using: Entities::RepoDiff do |compare, options|
+ expose :diffs, using: Entities::Diff do |compare, options|
compare.diffs(limits: false).to_a
end
@@ -767,10 +774,10 @@ module API
expose :description
end
- class RepoTag < Grape::Entity
+ class Tag < Grape::Entity
expose :name, :message
- expose :commit, using: Entities::RepoCommit do |repo_tag, options|
+ expose :commit, using: Entities::Commit do |repo_tag, options|
options[:project].repository.commit(repo_tag.dereferenced_target)
end
@@ -821,7 +828,7 @@ module API
expose :created_at, :started_at, :finished_at
expose :user, with: User
expose :artifacts_file, using: JobArtifactFile, if: -> (job, opts) { job.artifacts? }
- expose :commit, with: RepoCommit
+ expose :commit, with: Commit
expose :runner, with: Runner
expose :pipeline, with: PipelineBasic
end
@@ -874,7 +881,7 @@ module API
expose :deployable, using: Entities::Job
end
- class RepoLicense < Grape::Entity
+ class License < Grape::Entity
expose :key, :name, :nickname
expose :featured, as: :popular
expose :url, as: :html_url
@@ -1016,6 +1023,7 @@ module API
expose :cache, using: Cache
expose :credentials, using: Credentials
expose :dependencies, using: Dependency
+ expose :features
end
end
@@ -1030,5 +1038,10 @@ module API
expose :failing_on_hosts
expose :total_failures
end
+
+ class CustomAttribute < Grape::Entity
+ expose :key
+ expose :value
+ end
end
end
diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb
index 6a0be74623e..67ef329f01f 100644
--- a/lib/api/helpers.rb
+++ b/lib/api/helpers.rb
@@ -3,6 +3,8 @@ module API
include Gitlab::Utils
include Helpers::Pagination
+ UnauthorizedError = Class.new(StandardError)
+
SUDO_HEADER = "HTTP_SUDO".freeze
SUDO_PARAM = :sudo
@@ -139,7 +141,7 @@ module API
end
def authenticate!
- unauthorized! unless current_user && can?(initial_current_user, :access_api)
+ unauthorized! unless current_user
end
def authenticate_non_get!
@@ -285,7 +287,7 @@ module API
if sentry_enabled? && report_exception?(exception)
define_params_for_grape_middleware
sentry_context
- Raven.capture_exception(exception)
+ Raven.capture_exception(exception, extra: params)
end
# lifted from https://github.com/rails/rails/blob/master/actionpack/lib/action_dispatch/middleware/debug_exceptions.rb#L60
@@ -397,19 +399,27 @@ module API
def initial_current_user
return @initial_current_user if defined?(@initial_current_user)
- Gitlab::Auth::UniqueIpsLimiter.limit_user! do
- @initial_current_user ||= find_user_by_private_token(scopes: scopes_registered_for_endpoint)
- @initial_current_user ||= doorkeeper_guard(scopes: scopes_registered_for_endpoint)
- @initial_current_user ||= find_user_from_warden
-
- unless @initial_current_user && Gitlab::UserAccess.new(@initial_current_user).allowed?
- @initial_current_user = nil
- end
- @initial_current_user
+ begin
+ @initial_current_user = Gitlab::Auth::UniqueIpsLimiter.limit_user! { find_current_user }
+ rescue APIGuard::UnauthorizedError, UnauthorizedError
+ unauthorized!
end
end
+ def find_current_user
+ user =
+ find_user_by_private_token(scopes: scopes_registered_for_endpoint) ||
+ doorkeeper_guard(scopes: scopes_registered_for_endpoint) ||
+ find_user_from_warden
+
+ return nil unless user
+
+ raise UnauthorizedError unless Gitlab::UserAccess.new(user).allowed? && user.can?(:access_api)
+
+ user
+ end
+
def sudo!
return unless sudo_identifier
return unless initial_current_user
@@ -454,10 +464,12 @@ module API
header(*Gitlab::Workhorse.send_artifacts_entry(build, entry))
end
- # The Grape Error Middleware only has access to env but no params. We workaround this by
- # defining a method that returns the right value.
+ # The Grape Error Middleware only has access to `env` but not `params` nor
+ # `request`. We workaround this by defining methods that returns the right
+ # values.
def define_params_for_grape_middleware
- self.define_singleton_method(:params) { Rack::Request.new(env).params.symbolize_keys }
+ self.define_singleton_method(:request) { Rack::Request.new(env) }
+ self.define_singleton_method(:params) { request.params.symbolize_keys }
end
# We could get a Grape or a standard Ruby exception. We should only report anything that
diff --git a/lib/api/internal.rb b/lib/api/internal.rb
index c0fef56378f..6e78ac2c903 100644
--- a/lib/api/internal.rb
+++ b/lib/api/internal.rb
@@ -31,6 +31,12 @@ module API
protocol = params[:protocol]
actor.update_last_used_at if actor.is_a?(Key)
+ user =
+ if actor.is_a?(Key)
+ actor.user
+ else
+ actor
+ end
access_checker_klass = wiki? ? Gitlab::GitAccessWiki : Gitlab::GitAccess
access_checker = access_checker_klass
@@ -47,6 +53,7 @@ module API
{
status: true,
gl_repository: gl_repository,
+ gl_username: user&.username,
repository_path: repository_path,
gitaly: gitaly_payload(params[:action])
}
@@ -136,7 +143,7 @@ module API
codes = nil
- ::Users::UpdateService.new(user).execute! do |user|
+ ::Users::UpdateService.new(current_user, user: user).execute! do |user|
codes = user.generate_otp_backup_codes!
end
diff --git a/lib/api/issues.rb b/lib/api/issues.rb
index 1729df2aad0..0df41dcc903 100644
--- a/lib/api/issues.rb
+++ b/lib/api/issues.rb
@@ -48,6 +48,7 @@ module API
optional :labels, type: String, desc: 'Comma-separated list of label names'
optional :due_date, type: String, desc: 'Date string in the format YEAR-MONTH-DAY'
optional :confidential, type: Boolean, desc: 'Boolean parameter if the issue should be confidential'
+ optional :discussion_locked, type: Boolean, desc: " Boolean parameter indicating if the issue's discussion is locked"
end
params :issue_params do
@@ -193,7 +194,7 @@ module API
desc: 'Date time when the issue was updated. Available only for admins and project owners.'
optional :state_event, type: String, values: %w[reopen close], desc: 'State of the issue'
use :issue_params
- at_least_one_of :title, :description, :assignee_ids, :assignee_id, :milestone_id,
+ at_least_one_of :title, :description, :assignee_ids, :assignee_id, :milestone_id, :discussion_locked,
:labels, :created_at, :due_date, :confidential, :state_event
end
put ':id/issues/:issue_iid' do
diff --git a/lib/api/lint.rb b/lib/api/lint.rb
index ae43a4a3237..d202eaa4c49 100644
--- a/lib/api/lint.rb
+++ b/lib/api/lint.rb
@@ -6,7 +6,7 @@ module API
requires :content, type: String, desc: 'Content of .gitlab-ci.yml'
end
post '/lint' do
- error = Ci::GitlabCiYamlProcessor.validation_message(params[:content])
+ error = Gitlab::Ci::YamlProcessor.validation_message(params[:content])
status 200
diff --git a/lib/api/merge_requests.rb b/lib/api/merge_requests.rb
index 56d72d511da..be843ec8251 100644
--- a/lib/api/merge_requests.rb
+++ b/lib/api/merge_requests.rb
@@ -2,7 +2,7 @@ module API
class MergeRequests < Grape::API
include PaginationParams
- before { authenticate! }
+ before { authenticate_non_get! }
helpers ::Gitlab::IssuableMetadata
@@ -55,6 +55,7 @@ module API
desc: 'Return merge requests for the given scope: `created-by-me`, `assigned-to-me` or `all`'
end
get do
+ authenticate! unless params[:scope] == 'all'
merge_requests = find_merge_requests
options = { with: Entities::MergeRequestBasic,
@@ -182,13 +183,13 @@ module API
end
desc 'Get the commits of a merge request' do
- success Entities::RepoCommit
+ success Entities::Commit
end
get ':id/merge_requests/:merge_request_iid/commits' do
merge_request = find_merge_request_with_access(params[:merge_request_iid])
commits = ::Kaminari.paginate_array(merge_request.commits)
- present paginate(commits), with: Entities::RepoCommit
+ present paginate(commits), with: Entities::Commit
end
desc 'Show the merge request changes' do
@@ -213,12 +214,14 @@ module API
:remove_source_branch,
:state_event,
:target_branch,
- :title
+ :title,
+ :discussion_locked
]
optional :title, type: String, allow_blank: false, desc: 'The title of the merge request'
optional :target_branch, type: String, allow_blank: false, desc: 'The target branch'
optional :state_event, type: String, values: %w[close reopen],
desc: 'Status of the merge request'
+ optional :discussion_locked, type: Boolean, desc: 'Whether the MR discussion is locked'
use :optional_params
at_least_one_of(*at_least_one_of_ce)
diff --git a/lib/api/notes.rb b/lib/api/notes.rb
index d6e7203adaf..0b9ab4eeb05 100644
--- a/lib/api/notes.rb
+++ b/lib/api/notes.rb
@@ -78,6 +78,8 @@ module API
}
if can?(current_user, noteable_read_ability_name(noteable), noteable)
+ authorize! :create_note, noteable
+
if params[:created_at] && (current_user.admin? || user_project.owner == current_user)
opts[:created_at] = params[:created_at]
end
diff --git a/lib/api/notification_settings.rb b/lib/api/notification_settings.rb
index bcc0833aa5c..0266bf2f717 100644
--- a/lib/api/notification_settings.rb
+++ b/lib/api/notification_settings.rb
@@ -35,7 +35,7 @@ module API
new_notification_email = params.delete(:notification_email)
if new_notification_email
- ::Users::UpdateService.new(current_user, notification_email: new_notification_email).execute
+ ::Users::UpdateService.new(current_user, user: current_user, notification_email: new_notification_email).execute
end
notification_setting.update(declared_params(include_missing: false))
diff --git a/lib/api/projects.rb b/lib/api/projects.rb
index 7dc19788462..aab7a6c3f93 100644
--- a/lib/api/projects.rb
+++ b/lib/api/projects.rb
@@ -70,8 +70,11 @@ module API
optional :import_url, type: String, desc: 'URL from which the project is imported'
end
- def present_projects(options = {})
- projects = ProjectsFinder.new(current_user: current_user, params: project_finder_params).execute
+ def load_projects
+ ProjectsFinder.new(current_user: current_user, params: project_finder_params).execute
+ end
+
+ def present_projects(projects, options = {})
projects = reorder_projects(projects)
projects = projects.with_statistics if params[:statistics]
projects = projects.with_issues_enabled if params[:with_issues_enabled]
@@ -111,7 +114,7 @@ module API
params[:user] = user
- present_projects
+ present_projects load_projects
end
end
@@ -124,7 +127,7 @@ module API
use :statistics_params
end
get do
- present_projects
+ present_projects load_projects
end
desc 'Create new project' do
@@ -229,6 +232,18 @@ module API
end
end
+ desc 'List forks of this project' do
+ success Entities::Project
+ end
+ params do
+ use :collection_params
+ end
+ get ':id/forks' do
+ forks = ForkProjectsFinder.new(user_project, params: project_finder_params, current_user: current_user).execute
+
+ present_projects forks
+ end
+
desc 'Update an existing project' do
success Entities::Project
end
diff --git a/lib/api/repositories.rb b/lib/api/repositories.rb
index 2255fb1b70d..ceee3226732 100644
--- a/lib/api/repositories.rb
+++ b/lib/api/repositories.rb
@@ -35,7 +35,7 @@ module API
end
desc 'Get a project repository tree' do
- success Entities::RepoTreeObject
+ success Entities::TreeObject
end
params do
optional :ref, type: String, desc: 'The name of a repository branch or tag, if not given the default branch is used'
@@ -52,7 +52,7 @@ module API
tree = user_project.repository.tree(commit.id, path, recursive: params[:recursive])
entries = ::Kaminari.paginate_array(tree.sorted_entries)
- present paginate(entries), with: Entities::RepoTreeObject
+ present paginate(entries), with: Entities::TreeObject
end
desc 'Get raw blob contents from the repository'
diff --git a/lib/api/tags.rb b/lib/api/tags.rb
index 912415e3a7f..0d394a7b441 100644
--- a/lib/api/tags.rb
+++ b/lib/api/tags.rb
@@ -11,18 +11,18 @@ module API
end
resource :projects, requirements: API::PROJECT_ENDPOINT_REQUIREMENTS do
desc 'Get a project repository tags' do
- success Entities::RepoTag
+ success Entities::Tag
end
params do
use :pagination
end
get ':id/repository/tags' do
tags = ::Kaminari.paginate_array(user_project.repository.tags.sort_by(&:name).reverse)
- present paginate(tags), with: Entities::RepoTag, project: user_project
+ present paginate(tags), with: Entities::Tag, project: user_project
end
desc 'Get a single repository tag' do
- success Entities::RepoTag
+ success Entities::Tag
end
params do
requires :tag_name, type: String, desc: 'The name of the tag'
@@ -31,11 +31,11 @@ module API
tag = user_project.repository.find_tag(params[:tag_name])
not_found!('Tag') unless tag
- present tag, with: Entities::RepoTag, project: user_project
+ present tag, with: Entities::Tag, project: user_project
end
desc 'Create a new repository tag' do
- success Entities::RepoTag
+ success Entities::Tag
end
params do
requires :tag_name, type: String, desc: 'The name of the tag'
@@ -51,7 +51,7 @@ module API
if result[:status] == :success
present result[:tag],
- with: Entities::RepoTag,
+ with: Entities::Tag,
project: user_project
else
render_api_error!(result[:message], 400)
diff --git a/lib/api/templates.rb b/lib/api/templates.rb
index f70bc0622b7..6550b331fb8 100644
--- a/lib/api/templates.rb
+++ b/lib/api/templates.rb
@@ -49,7 +49,7 @@ module API
desc 'Get the list of the available license template' do
detail 'This feature was introduced in GitLab 8.7.'
- success ::API::Entities::RepoLicense
+ success ::API::Entities::License
end
params do
optional :popular, type: Boolean, desc: 'If passed, returns only popular licenses'
@@ -60,12 +60,12 @@ module API
featured: declared(params)[:popular].present? ? true : nil
}
licences = ::Kaminari.paginate_array(Licensee::License.all(options))
- present paginate(licences), with: Entities::RepoLicense
+ present paginate(licences), with: Entities::License
end
desc 'Get the text for a specific license' do
detail 'This feature was introduced in GitLab 8.7.'
- success ::API::Entities::RepoLicense
+ success ::API::Entities::License
end
params do
requires :name, type: String, desc: 'The name of the template'
@@ -75,7 +75,7 @@ module API
template = parsed_license_template
- present template, with: ::API::Entities::RepoLicense
+ present template, with: ::API::Entities::License
end
GLOBAL_TEMPLATE_TYPES.each do |template_type, properties|
diff --git a/lib/api/users.rb b/lib/api/users.rb
index 1825c90a23b..b6f97a1eac2 100644
--- a/lib/api/users.rb
+++ b/lib/api/users.rb
@@ -6,12 +6,14 @@ module API
allow_access_with_scope :read_user, if: -> (request) { request.get? }
resource :users, requirements: { uid: /[0-9]*/, id: /[0-9]*/ } do
+ include CustomAttributesEndpoints
+
before do
authenticate_non_get!
end
helpers do
- def find_user(params)
+ def find_user_by_id(params)
id = params[:user_id] || params[:id]
User.find_by(id: id) || not_found!('User')
end
@@ -88,7 +90,7 @@ module API
user = User.find_by(id: params[:id])
not_found!('User') unless user && can?(current_user, :read_user, user)
- opts = current_user&.admin? ? { with: Entities::UserWithAdmin } : {}
+ opts = current_user&.admin? ? { with: Entities::UserWithAdmin } : { with: Entities::User }
present user, opts
end
@@ -166,7 +168,7 @@ module API
user_params[:password_expires_at] = Time.now if user_params[:password].present?
- result = ::Users::UpdateService.new(user, user_params.except(:extern_uid, :provider)).execute
+ result = ::Users::UpdateService.new(current_user, user_params.except(:extern_uid, :provider).merge(user: user)).execute
if result[:status] == :success
present user, with: Entities::UserPublic
@@ -326,10 +328,9 @@ module API
user = User.find_by(id: params.delete(:id))
not_found!('User') unless user
- email = Emails::CreateService.new(user, declared_params(include_missing: false)).execute
+ email = Emails::CreateService.new(current_user, declared_params(include_missing: false).merge(user: user)).execute
if email.errors.blank?
- NotificationService.new.new_email(email)
present email, with: Entities::Email
else
render_validation_error!(email)
@@ -367,10 +368,8 @@ module API
not_found!('Email') unless email
destroy_conditionally!(email) do |email|
- Emails::DestroyService.new(current_user, email: email.email).execute
+ Emails::DestroyService.new(current_user, user: user).execute(email)
end
-
- user.update_secondary_emails!
end
desc 'Delete a user. Available only for admins.' do
@@ -430,7 +429,7 @@ module API
resource :impersonation_tokens do
helpers do
def finder(options = {})
- user = find_user(params)
+ user = find_user_by_id(params)
PersonalAccessTokensFinder.new({ user: user, impersonation: true }.merge(options))
end
@@ -672,10 +671,9 @@ module API
requires :email, type: String, desc: 'The new email'
end
post "emails" do
- email = Emails::CreateService.new(current_user, declared_params).execute
+ email = Emails::CreateService.new(current_user, declared_params.merge(user: current_user)).execute
if email.errors.blank?
- NotificationService.new.new_email(email)
present email, with: Entities::Email
else
render_validation_error!(email)
@@ -691,10 +689,8 @@ module API
not_found!('Email') unless email
destroy_conditionally!(email) do |email|
- Emails::DestroyService.new(current_user, email: email.email).execute
+ Emails::DestroyService.new(current_user, user: current_user).execute(email)
end
-
- current_user.update_secondary_emails!
end
desc 'Get a list of user activities'
diff --git a/lib/api/v3/branches.rb b/lib/api/v3/branches.rb
index 81b13249892..69cd12de72c 100644
--- a/lib/api/v3/branches.rb
+++ b/lib/api/v3/branches.rb
@@ -11,12 +11,12 @@ module API
end
resource :projects, requirements: { id: %r{[^/]+} } do
desc 'Get a project repository branches' do
- success ::API::Entities::RepoBranch
+ success ::API::Entities::Branch
end
get ":id/repository/branches" do
branches = user_project.repository.branches.sort_by(&:name)
- present branches, with: ::API::Entities::RepoBranch, project: user_project
+ present branches, with: ::API::Entities::Branch, project: user_project
end
desc 'Delete a branch'
@@ -47,7 +47,7 @@ module API
end
desc 'Create branch' do
- success ::API::Entities::RepoBranch
+ success ::API::Entities::Branch
end
params do
requires :branch_name, type: String, desc: 'The name of the branch'
@@ -60,7 +60,7 @@ module API
if result[:status] == :success
present result[:branch],
- with: ::API::Entities::RepoBranch,
+ with: ::API::Entities::Branch,
project: user_project
else
render_api_error!(result[:message], 400)
diff --git a/lib/api/v3/commits.rb b/lib/api/v3/commits.rb
index 5936f4700aa..345cb7e7c11 100644
--- a/lib/api/v3/commits.rb
+++ b/lib/api/v3/commits.rb
@@ -13,7 +13,7 @@ module API
end
resource :projects, requirements: { id: %r{[^/]+} } do
desc 'Get a project repository commits' do
- success ::API::Entities::RepoCommit
+ success ::API::Entities::Commit
end
params do
optional :ref_name, type: String, desc: 'The name of a repository branch or tag, if not given the default branch is used'
@@ -34,11 +34,11 @@ module API
after: params[:since],
before: params[:until])
- present commits, with: ::API::Entities::RepoCommit
+ present commits, with: ::API::Entities::Commit
end
desc 'Commit multiple file changes as one commit' do
- success ::API::Entities::RepoCommitDetail
+ success ::API::Entities::CommitDetail
detail 'This feature was introduced in GitLab 8.13'
end
params do
@@ -59,14 +59,14 @@ module API
if result[:status] == :success
commit_detail = user_project.repository.commits(result[:result], limit: 1).first
- present commit_detail, with: ::API::Entities::RepoCommitDetail
+ present commit_detail, with: ::API::Entities::CommitDetail
else
render_api_error!(result[:message], 400)
end
end
desc 'Get a specific commit of a project' do
- success ::API::Entities::RepoCommitDetail
+ success ::API::Entities::CommitDetail
failure [[404, 'Not Found']]
end
params do
@@ -77,7 +77,7 @@ module API
not_found! "Commit" unless commit
- present commit, with: ::API::Entities::RepoCommitDetail
+ present commit, with: ::API::Entities::CommitDetail
end
desc 'Get the diff for a specific commit of a project' do
@@ -113,7 +113,7 @@ module API
desc 'Cherry pick commit into a branch' do
detail 'This feature was introduced in GitLab 8.15'
- success ::API::Entities::RepoCommit
+ success ::API::Entities::Commit
end
params do
requires :sha, type: String, desc: 'A commit sha to be cherry picked'
@@ -138,7 +138,7 @@ module API
if result[:status] == :success
branch = user_project.repository.find_branch(params[:branch])
- present user_project.repository.commit(branch.dereferenced_target), with: ::API::Entities::RepoCommit
+ present user_project.repository.commit(branch.dereferenced_target), with: ::API::Entities::Commit
else
render_api_error!(result[:message], 400)
end
diff --git a/lib/api/v3/entities.rb b/lib/api/v3/entities.rb
index c928ce5265b..afdd7b83998 100644
--- a/lib/api/v3/entities.rb
+++ b/lib/api/v3/entities.rb
@@ -220,7 +220,7 @@ module API
expose :created_at, :started_at, :finished_at
expose :user, with: ::API::Entities::User
expose :artifacts_file, using: ::API::Entities::JobArtifactFile, if: -> (build, opts) { build.artifacts? }
- expose :commit, with: ::API::Entities::RepoCommit
+ expose :commit, with: ::API::Entities::Commit
expose :runner, with: ::API::Entities::Runner
expose :pipeline, with: ::API::Entities::PipelineBasic
end
@@ -237,7 +237,7 @@ module API
end
class MergeRequestChanges < MergeRequest
- expose :diffs, as: :changes, using: ::API::Entities::RepoDiff do |compare, _|
+ expose :diffs, as: :changes, using: ::API::Entities::Diff do |compare, _|
compare.raw_diffs(limits: false).to_a
end
end
diff --git a/lib/api/v3/merge_requests.rb b/lib/api/v3/merge_requests.rb
index b6b7254ae29..1d6d823f32b 100644
--- a/lib/api/v3/merge_requests.rb
+++ b/lib/api/v3/merge_requests.rb
@@ -135,12 +135,12 @@ module API
end
desc 'Get the commits of a merge request' do
- success ::API::Entities::RepoCommit
+ success ::API::Entities::Commit
end
get "#{path}/commits" do
merge_request = find_merge_request_with_access(params[:merge_request_id])
- present merge_request.commits, with: ::API::Entities::RepoCommit
+ present merge_request.commits, with: ::API::Entities::Commit
end
desc 'Show the merge request changes' do
diff --git a/lib/api/v3/repositories.rb b/lib/api/v3/repositories.rb
index 0eaa0de2eef..41a7c6b83ae 100644
--- a/lib/api/v3/repositories.rb
+++ b/lib/api/v3/repositories.rb
@@ -19,7 +19,7 @@ module API
end
desc 'Get a project repository tree' do
- success ::API::Entities::RepoTreeObject
+ success ::API::Entities::TreeObject
end
params do
optional :ref_name, type: String, desc: 'The name of a repository branch or tag, if not given the default branch is used'
@@ -35,7 +35,7 @@ module API
tree = user_project.repository.tree(commit.id, path, recursive: params[:recursive])
- present tree.sorted_entries, with: ::API::Entities::RepoTreeObject
+ present tree.sorted_entries, with: ::API::Entities::TreeObject
end
desc 'Get a raw file contents'
diff --git a/lib/api/v3/tags.rb b/lib/api/v3/tags.rb
index 7e5875cd030..6e37d31d153 100644
--- a/lib/api/v3/tags.rb
+++ b/lib/api/v3/tags.rb
@@ -8,11 +8,11 @@ module API
end
resource :projects, requirements: { id: %r{[^/]+} } do
desc 'Get a project repository tags' do
- success ::API::Entities::RepoTag
+ success ::API::Entities::Tag
end
get ":id/repository/tags" do
tags = user_project.repository.tags.sort_by(&:name).reverse
- present tags, with: ::API::Entities::RepoTag, project: user_project
+ present tags, with: ::API::Entities::Tag, project: user_project
end
desc 'Delete a repository tag'
diff --git a/lib/api/v3/templates.rb b/lib/api/v3/templates.rb
index 2a2fb59045c..7298203df10 100644
--- a/lib/api/v3/templates.rb
+++ b/lib/api/v3/templates.rb
@@ -52,7 +52,7 @@ module API
detailed_desc = 'This feature was introduced in GitLab 8.7.'
detailed_desc << DEPRECATION_MESSAGE unless status == :ok
detail detailed_desc
- success ::API::Entities::RepoLicense
+ success ::API::Entities::License
end
params do
optional :popular, type: Boolean, desc: 'If passed, returns only popular licenses'
@@ -61,7 +61,7 @@ module API
options = {
featured: declared(params)[:popular].present? ? true : nil
}
- present Licensee::License.all(options), with: ::API::Entities::RepoLicense
+ present Licensee::License.all(options), with: ::API::Entities::License
end
end
@@ -70,7 +70,7 @@ module API
detailed_desc = 'This feature was introduced in GitLab 8.7.'
detailed_desc << DEPRECATION_MESSAGE unless status == :ok
detail detailed_desc
- success ::API::Entities::RepoLicense
+ success ::API::Entities::License
end
params do
requires :name, type: String, desc: 'The name of the template'
@@ -80,7 +80,7 @@ module API
template = parsed_license_template
- present template, with: ::API::Entities::RepoLicense
+ present template, with: ::API::Entities::License
end
end