summaryrefslogtreecommitdiff
path: root/lib/api
diff options
context:
space:
mode:
Diffstat (limited to 'lib/api')
-rw-r--r--lib/api/api.rb3
-rw-r--r--lib/api/api_guard.rb13
-rw-r--r--lib/api/boards.rb4
-rw-r--r--lib/api/boards_responses.rb14
-rw-r--r--lib/api/ci/runner.rb1
-rw-r--r--lib/api/concerns/packages/nuget_endpoints.rb63
-rw-r--r--lib/api/debian_project_packages.rb5
-rw-r--r--lib/api/entities/basic_repository_storage_move.rb13
-rw-r--r--lib/api/entities/basic_snippet.rb18
-rw-r--r--lib/api/entities/board.rb2
-rw-r--r--lib/api/entities/note.rb1
-rw-r--r--lib/api/entities/project.rb1
-rw-r--r--lib/api/entities/project_repository_storage_move.rb7
-rw-r--r--lib/api/entities/release.rb7
-rw-r--r--lib/api/entities/snippet.rb12
-rw-r--r--lib/api/entities/snippet_repository_storage_move.rb9
-rw-r--r--lib/api/generic_packages.rb8
-rw-r--r--lib/api/group_boards.rb34
-rw-r--r--lib/api/group_packages.rb4
-rw-r--r--lib/api/helpers.rb16
-rw-r--r--lib/api/helpers/authentication.rb73
-rw-r--r--lib/api/helpers/merge_requests_helpers.rb12
-rw-r--r--lib/api/helpers/packages/basic_auth_helpers.rb13
-rw-r--r--lib/api/helpers/pagination.rb4
-rw-r--r--lib/api/helpers/projects_helpers.rb4
-rw-r--r--lib/api/helpers/services_helpers.rb2
-rw-r--r--lib/api/internal/base.rb1
-rw-r--r--lib/api/invitations.rb18
-rw-r--r--lib/api/job_artifacts.rb7
-rw-r--r--lib/api/jobs.rb21
-rw-r--r--lib/api/lint.rb5
-rw-r--r--lib/api/maven_packages.rb6
-rw-r--r--lib/api/nuget_group_packages.rb58
-rw-r--r--lib/api/nuget_project_packages.rb68
-rw-r--r--lib/api/project_packages.rb4
-rw-r--r--lib/api/project_templates.rb4
-rw-r--r--lib/api/projects.rb4
-rw-r--r--lib/api/settings.rb1
-rw-r--r--lib/api/snippet_repository_storage_moves.rb110
-rw-r--r--lib/api/templates.rb3
-rw-r--r--lib/api/terraform/state.rb2
-rw-r--r--lib/api/usage_data.rb2
-rw-r--r--lib/api/user_counts.rb4
-rw-r--r--lib/api/users.rb3
44 files changed, 516 insertions, 148 deletions
diff --git a/lib/api/api.rb b/lib/api/api.rb
index 06c2b46a2f2..ada0da28749 100644
--- a/lib/api/api.rb
+++ b/lib/api/api.rb
@@ -59,6 +59,7 @@ module API
project: -> { @project },
namespace: -> { @group },
caller_id: route.origin,
+ remote_ip: request.ip,
feature_category: feature_category
)
end
@@ -212,6 +213,7 @@ module API
mount ::API::GroupPackages
mount ::API::PackageFiles
mount ::API::NugetProjectPackages
+ mount ::API::NugetGroupPackages
mount ::API::PypiPackages
mount ::API::ComposerPackages
mount ::API::ConanProjectPackages
@@ -251,6 +253,7 @@ module API
mount ::API::Services
mount ::API::Settings
mount ::API::SidekiqMetrics
+ mount ::API::SnippetRepositoryStorageMoves
mount ::API::Snippets
mount ::API::Statistics
mount ::API::Submodules
diff --git a/lib/api/api_guard.rb b/lib/api/api_guard.rb
index 0a486307653..8641271f2df 100644
--- a/lib/api/api_guard.rb
+++ b/lib/api/api_guard.rb
@@ -69,10 +69,15 @@ module API
def find_user_from_sources
strong_memoize(:find_user_from_sources) do
- deploy_token_from_request ||
- find_user_from_bearer_token ||
- find_user_from_job_token ||
- user_from_warden
+ if try(:namespace_inheritable, :authentication)
+ user_from_namespace_inheritable ||
+ user_from_warden
+ else
+ deploy_token_from_request ||
+ find_user_from_bearer_token ||
+ find_user_from_job_token ||
+ user_from_warden
+ end
end
end
diff --git a/lib/api/boards.rb b/lib/api/boards.rb
index e2d30dd7c2b..5fd4ca3546c 100644
--- a/lib/api/boards.rb
+++ b/lib/api/boards.rb
@@ -7,10 +7,10 @@ module API
prepend_if_ee('EE::API::BoardsResponses') # rubocop: disable Cop/InjectEnterpriseEditionModule
- before { authenticate! }
-
feature_category :boards
+ before { authenticate! }
+
helpers do
def board_parent
user_project
diff --git a/lib/api/boards_responses.rb b/lib/api/boards_responses.rb
index 89355c84401..5a30de1f766 100644
--- a/lib/api/boards_responses.rb
+++ b/lib/api/boards_responses.rb
@@ -80,10 +80,20 @@ module API
requires :label_id, type: Integer, desc: 'The ID of an existing label'
end
- params :update_params do
+ params :update_params_ce do
+ optional :name, type: String, desc: 'The board name'
+ optional :hide_backlog_list, type: Grape::API::Boolean, desc: 'Hide the Open list'
+ optional :hide_closed_list, type: Grape::API::Boolean, desc: 'Hide the Closed list'
+ end
+
+ params :update_params_ee do
# Configurable issue boards are not available in CE/EE Core.
# https://docs.gitlab.com/ee/user/project/issue_board.html#configurable-issue-boards
- optional :name, type: String, desc: 'The board name'
+ end
+
+ params :update_params do
+ use :update_params_ce
+ use :update_params_ee
end
end
end
diff --git a/lib/api/ci/runner.rb b/lib/api/ci/runner.rb
index 86e1a939df1..5cfb65e1fbb 100644
--- a/lib/api/ci/runner.rb
+++ b/lib/api/ci/runner.rb
@@ -180,6 +180,7 @@ module API
optional :checksum, type: String, desc: %q(Job's trace CRC32 checksum)
optional :bytesize, type: Integer, desc: %q(Job's trace size in bytes)
end
+ optional :exit_code, type: Integer, desc: %q(Job's exit code)
end
put '/:id' do
job = authenticate_job!
diff --git a/lib/api/concerns/packages/nuget_endpoints.rb b/lib/api/concerns/packages/nuget_endpoints.rb
index 1a03a6a6dad..53b778875fc 100644
--- a/lib/api/concerns/packages/nuget_endpoints.rb
+++ b/lib/api/concerns/packages/nuget_endpoints.rb
@@ -19,44 +19,49 @@ module API
included do
helpers do
- def find_packages
- packages = package_finder.execute
+ def find_packages(package_name)
+ packages = package_finder(package_name).execute
not_found!('Packages') unless packages.exists?
packages
end
- def find_package
- package = package_finder(package_version: params[:package_version]).execute
- .first
+ def find_package(package_name, package_version)
+ package = package_finder(package_name, package_version).execute
+ .first
not_found!('Package') unless package
package
end
- def package_finder(finder_params = {})
+ def package_finder(package_name, package_version = nil)
::Packages::Nuget::PackageFinder.new(
- authorized_user_project,
- **finder_params.merge(package_name: params[:package_name])
+ current_user,
+ project_or_group,
+ package_name: package_name,
+ package_version: package_version
)
end
+
+ def search_packages(search_term, search_options)
+ ::Packages::Nuget::SearchService
+ .new(current_user, project_or_group, params[:q], search_options)
+ .execute
+ end
end
# https://docs.microsoft.com/en-us/nuget/api/service-index
desc 'The NuGet Service Index' do
detail 'This feature was introduced in GitLab 12.6'
end
-
- route_setting :authentication, deploy_token_allowed: true, job_token_allowed: :basic_auth, basic_auth_personal_access_token: true
-
get 'index', format: :json do
- authorize_read_package!(authorized_user_project)
+ authorize_read_package!(project_or_group)
track_package_event('cli_metadata', :nuget, category: 'API::NugetPackages')
- present ::Packages::Nuget::ServiceIndexPresenter.new(authorized_user_project),
- with: ::API::Entities::Nuget::ServiceIndex
+ present ::Packages::Nuget::ServiceIndexPresenter.new(project_or_group),
+ with: ::API::Entities::Nuget::ServiceIndex
end
# https://docs.microsoft.com/en-us/nuget/api/registration-base-url-resource
@@ -64,18 +69,15 @@ module API
requires :package_name, type: String, desc: 'The NuGet package name', regexp: API::NO_SLASH_URL_PART_REGEX
end
namespace '/metadata/*package_name' do
- before do
- authorize_read_package!(authorized_user_project)
+ after_validation do
+ authorize_read_package!(project_or_group)
end
desc 'The NuGet Metadata Service - Package name level' do
detail 'This feature was introduced in GitLab 12.8'
end
-
- route_setting :authentication, deploy_token_allowed: true, job_token_allowed: :basic_auth, basic_auth_personal_access_token: true
-
get 'index', format: :json do
- present ::Packages::Nuget::PackagesMetadataPresenter.new(find_packages),
+ present ::Packages::Nuget::PackagesMetadataPresenter.new(find_packages(params[:package_name])),
with: ::API::Entities::Nuget::PackagesMetadata
end
@@ -85,11 +87,8 @@ module API
params do
requires :package_version, type: String, desc: 'The NuGet package version', regexp: API::NO_SLASH_URL_PART_REGEX
end
-
- route_setting :authentication, deploy_token_allowed: true, job_token_allowed: :basic_auth, basic_auth_personal_access_token: true
-
get '*package_version', format: :json do
- present ::Packages::Nuget::PackageMetadataPresenter.new(find_package),
+ present ::Packages::Nuget::PackageMetadataPresenter.new(find_package(params[:package_name], params[:package_version])),
with: ::API::Entities::Nuget::PackageMetadata
end
end
@@ -102,30 +101,26 @@ module API
optional :prerelease, type: ::Grape::API::Boolean, desc: 'Include prerelease versions', default: true
end
namespace '/query' do
- before do
- authorize_read_package!(authorized_user_project)
+ after_validation do
+ authorize_read_package!(project_or_group)
end
desc 'The NuGet Search Service' do
detail 'This feature was introduced in GitLab 12.8'
end
-
- route_setting :authentication, deploy_token_allowed: true, job_token_allowed: :basic_auth, basic_auth_personal_access_token: true
-
get format: :json do
search_options = {
include_prerelease_versions: params[:prerelease],
per_page: params[:take],
padding: params[:skip]
}
- search = ::Packages::Nuget::SearchService
- .new(authorized_user_project, params[:q], search_options)
- .execute
+
+ results = search_packages(params[:q], search_options)
track_package_event('search_package', :nuget, category: 'API::NugetPackages')
- present ::Packages::Nuget::SearchResultsPresenter.new(search),
- with: ::API::Entities::Nuget::SearchResults
+ present ::Packages::Nuget::SearchResultsPresenter.new(results),
+ with: ::API::Entities::Nuget::SearchResults
end
end
end
diff --git a/lib/api/debian_project_packages.rb b/lib/api/debian_project_packages.rb
index bcb4e8c8cbc..f8129c18dff 100644
--- a/lib/api/debian_project_packages.rb
+++ b/lib/api/debian_project_packages.rb
@@ -21,6 +21,8 @@ module API
end
namespace 'incoming/:file_name', requirements: FILE_NAME_REQUIREMENTS do
+ content_type :json, Gitlab::Workhorse::INTERNAL_API_CONTENT_TYPE
+
# PUT {projects|groups}/:id/-/packages/debian/incoming/:file_name
params do
requires :file, type: ::API::Validations::Types::WorkhorseFile, desc: 'The package file to be published (generated by Multipart middleware)'
@@ -42,10 +44,9 @@ module API
# PUT {projects|groups}/:id/-/packages/debian/incoming/:file_name/authorize
route_setting :authentication, deploy_token_allowed: true, basic_auth_personal_access_token: true, job_token_allowed: :basic_auth
- post 'authorize' do
+ put 'authorize' do
authorize_workhorse!(
subject: authorized_user_project,
- has_length: false,
maximum_size: authorized_user_project.actual_limits.debian_max_file_size
)
end
diff --git a/lib/api/entities/basic_repository_storage_move.rb b/lib/api/entities/basic_repository_storage_move.rb
new file mode 100644
index 00000000000..3ee112fb9a2
--- /dev/null
+++ b/lib/api/entities/basic_repository_storage_move.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: true
+
+module API
+ module Entities
+ class BasicRepositoryStorageMove < Grape::Entity
+ expose :id
+ expose :created_at
+ expose :human_state_name, as: :state
+ expose :source_storage_name
+ expose :destination_storage_name
+ end
+ end
+end
diff --git a/lib/api/entities/basic_snippet.rb b/lib/api/entities/basic_snippet.rb
new file mode 100644
index 00000000000..26297514798
--- /dev/null
+++ b/lib/api/entities/basic_snippet.rb
@@ -0,0 +1,18 @@
+# frozen_string_literal: true
+
+module API
+ module Entities
+ class BasicSnippet < Grape::Entity
+ expose :id, :title, :description, :visibility
+ expose :updated_at, :created_at
+ expose :project_id
+ expose :web_url do |snippet|
+ Gitlab::UrlBuilder.build(snippet)
+ end
+ expose :raw_url do |snippet|
+ Gitlab::UrlBuilder.build(snippet, raw: true)
+ end
+ expose :ssh_url_to_repo, :http_url_to_repo, if: ->(snippet) { snippet.repository_exists? }
+ end
+ end
+end
diff --git a/lib/api/entities/board.rb b/lib/api/entities/board.rb
index b7a50408313..fe0182ad772 100644
--- a/lib/api/entities/board.rb
+++ b/lib/api/entities/board.rb
@@ -5,6 +5,8 @@ module API
class Board < Grape::Entity
expose :id
expose :name
+ expose :hide_backlog_list
+ expose :hide_closed_list
expose :project, using: Entities::BasicProjectDetails
expose :lists, using: Entities::List do |board|
diff --git a/lib/api/entities/note.rb b/lib/api/entities/note.rb
index 9a60c04220d..a597aa7bb4a 100644
--- a/lib/api/entities/note.rb
+++ b/lib/api/entities/note.rb
@@ -23,6 +23,7 @@ module API
expose :resolvable?, as: :resolvable
expose :resolved?, as: :resolved, if: ->(note, options) { note.resolvable? }
expose :resolved_by, using: Entities::UserBasic, if: ->(note, options) { note.resolvable? }
+ expose :resolved_at, if: ->(note, options) { note.resolvable? }
expose :confidential?, as: :confidential
diff --git a/lib/api/entities/project.rb b/lib/api/entities/project.rb
index 317caefe0a1..6ad6123a20e 100644
--- a/lib/api/entities/project.rb
+++ b/lib/api/entities/project.rb
@@ -100,6 +100,7 @@ module API
end
expose :only_allow_merge_if_pipeline_succeeds
expose :allow_merge_on_skipped_pipeline
+ expose :restrict_user_defined_variables
expose :request_access_enabled
expose :only_allow_merge_if_all_discussions_are_resolved
expose :remove_source_branch_after_merge
diff --git a/lib/api/entities/project_repository_storage_move.rb b/lib/api/entities/project_repository_storage_move.rb
index 25643651a14..191bbaf19d7 100644
--- a/lib/api/entities/project_repository_storage_move.rb
+++ b/lib/api/entities/project_repository_storage_move.rb
@@ -2,12 +2,7 @@
module API
module Entities
- class ProjectRepositoryStorageMove < Grape::Entity
- expose :id
- expose :created_at
- expose :human_state_name, as: :state
- expose :source_storage_name
- expose :destination_storage_name
+ class ProjectRepositoryStorageMove < BasicRepositoryStorageMove
expose :project, using: Entities::ProjectIdentity
end
end
diff --git a/lib/api/entities/release.rb b/lib/api/entities/release.rb
index 44a46c5861e..f6c3dd5a509 100644
--- a/lib/api/entities/release.rb
+++ b/lib/api/entities/release.rb
@@ -16,7 +16,12 @@ module API
expose :author, using: Entities::UserBasic, if: -> (release, _) { release.author.present? }
expose :commit, using: Entities::Commit, if: ->(_, _) { can_download_code? }
expose :upcoming_release?, as: :upcoming_release
- expose :milestones, using: Entities::MilestoneWithStats, if: -> (release, _) { release.milestones.present? && can_read_milestone? }
+ expose :milestones,
+ using: Entities::MilestoneWithStats,
+ if: -> (release, _) { release.milestones.present? && can_read_milestone? } do |release, _|
+ release.milestones.order_by_dates_and_title
+ end
+
expose :commit_path, expose_nil: false
expose :tag_path, expose_nil: false
diff --git a/lib/api/entities/snippet.rb b/lib/api/entities/snippet.rb
index 85148c03d18..f05e593a302 100644
--- a/lib/api/entities/snippet.rb
+++ b/lib/api/entities/snippet.rb
@@ -2,18 +2,8 @@
module API
module Entities
- class Snippet < Grape::Entity
- expose :id, :title, :description, :visibility
+ class Snippet < BasicSnippet
expose :author, using: Entities::UserBasic
- expose :updated_at, :created_at
- expose :project_id
- expose :web_url do |snippet|
- Gitlab::UrlBuilder.build(snippet)
- end
- expose :raw_url do |snippet|
- Gitlab::UrlBuilder.build(snippet, raw: true)
- end
- expose :ssh_url_to_repo, :http_url_to_repo, if: ->(snippet) { snippet.repository_exists? }
expose :file_name do |snippet|
snippet.file_name_on_repo || snippet.file_name
end
diff --git a/lib/api/entities/snippet_repository_storage_move.rb b/lib/api/entities/snippet_repository_storage_move.rb
new file mode 100644
index 00000000000..ee86816bd14
--- /dev/null
+++ b/lib/api/entities/snippet_repository_storage_move.rb
@@ -0,0 +1,9 @@
+# frozen_string_literal: true
+
+module API
+ module Entities
+ class SnippetRepositoryStorageMove < BasicRepositoryStorageMove
+ expose :snippet, using: Entities::BasicSnippet
+ end
+ end
+end
diff --git a/lib/api/generic_packages.rb b/lib/api/generic_packages.rb
index 3e1dd044c8d..167531fdaec 100644
--- a/lib/api/generic_packages.rb
+++ b/lib/api/generic_packages.rb
@@ -21,7 +21,7 @@ module API
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
- route_setting :authentication, job_token_allowed: true
+ route_setting :authentication, job_token_allowed: true, basic_auth_personal_access_token: true, deploy_token_allowed: true
namespace ':id/packages/generic' do
namespace ':package_name/*package_version/:file_name', requirements: GENERIC_PACKAGES_REQUIREMENTS do
@@ -29,7 +29,7 @@ module API
detail 'This feature was introduced in GitLab 13.5'
end
- route_setting :authentication, job_token_allowed: true
+ route_setting :authentication, job_token_allowed: true, basic_auth_personal_access_token: true, deploy_token_allowed: true
params do
requires :package_name, type: String, desc: 'Package name', regexp: Gitlab::Regex.generic_package_name_regex, file_path: true
@@ -52,7 +52,7 @@ module API
requires :file, type: ::API::Validations::Types::WorkhorseFile, desc: 'The package file to be published (generated by Multipart middleware)'
end
- route_setting :authentication, job_token_allowed: true
+ route_setting :authentication, job_token_allowed: true, basic_auth_personal_access_token: true, deploy_token_allowed: true
put do
authorize_upload!(project)
@@ -82,7 +82,7 @@ module API
requires :file_name, type: String, desc: 'Package file name', regexp: Gitlab::Regex.generic_package_file_name_regex, file_path: true
end
- route_setting :authentication, job_token_allowed: true
+ route_setting :authentication, job_token_allowed: true, basic_auth_personal_access_token: true, deploy_token_allowed: true
get do
authorize_read_package!(project)
diff --git a/lib/api/group_boards.rb b/lib/api/group_boards.rb
index 2bfd98a5b69..7425e1bd145 100644
--- a/lib/api/group_boards.rb
+++ b/lib/api/group_boards.rb
@@ -9,9 +9,7 @@ module API
feature_category :boards
- before do
- authenticate!
- end
+ before { authenticate! }
helpers do
def board_parent
@@ -22,28 +20,40 @@ module API
params do
requires :id, type: String, desc: 'The ID of a group'
end
-
resource :groups, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
segment ':id/boards' do
+ desc 'Get all group boards' do
+ detail 'This feature was introduced in 10.6'
+ success Entities::Board
+ end
+ params do
+ use :pagination
+ end
+ get '/' do
+ authorize!(:read_board, user_group)
+ present paginate(board_parent.boards.with_associations), with: Entities::Board
+ end
+
desc 'Find a group board' do
detail 'This feature was introduced in 10.6'
- success ::API::Entities::Board
+ success Entities::Board
end
get '/:board_id' do
authorize!(:read_board, user_group)
- present board, with: ::API::Entities::Board
+ present board, with: Entities::Board
end
- desc 'Get all group boards' do
- detail 'This feature was introduced in 10.6'
+ desc 'Update a group board' do
+ detail 'This feature was introduced in 11.0'
success Entities::Board
end
params do
- use :pagination
+ use :update_params
end
- get '/' do
- authorize!(:read_board, user_group)
- present paginate(board_parent.boards.with_associations), with: Entities::Board
+ put '/:board_id' do
+ authorize!(:admin_board, board_parent)
+
+ update_board
end
end
diff --git a/lib/api/group_packages.rb b/lib/api/group_packages.rb
index 31b28c3990f..d482f4d0585 100644
--- a/lib/api/group_packages.rb
+++ b/lib/api/group_packages.rb
@@ -31,12 +31,14 @@ module API
desc: 'Return packages of a certain type'
optional :package_name, type: String,
desc: 'Return packages with this name'
+ optional :include_versionless, type: Boolean,
+ desc: 'Returns packages without a version'
end
get ':id/packages' do
packages = Packages::GroupPackagesFinder.new(
current_user,
user_group,
- declared(params).slice(:exclude_subgroups, :order_by, :sort, :package_type, :package_name)
+ declared(params).slice(:exclude_subgroups, :order_by, :sort, :package_type, :package_name, :include_versionless)
).execute
present paginate(packages), with: ::API::Entities::Package, user: current_user, group: true
diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb
index 6fe25471289..79af9c37378 100644
--- a/lib/api/helpers.rb
+++ b/lib/api/helpers.rb
@@ -220,6 +220,10 @@ module API
user_project.builds.find(id.to_i)
end
+ def find_job!(id)
+ user_project.processables.find(id.to_i)
+ end
+
def authenticate!
unauthorized! unless current_user
end
@@ -275,6 +279,10 @@ module API
authorize! :read_build_trace, build
end
+ def authorize_read_job_artifacts!(build)
+ authorize! :read_job_artifacts, build
+ end
+
def authorize_destroy_artifacts!
authorize! :destroy_artifacts, user_project
end
@@ -364,7 +372,7 @@ module API
def forbidden!(reason = nil)
message = ['403 Forbidden']
- message << " - #{reason}" if reason
+ message << "- #{reason}" if reason
render_api_error!(message.join(' '), 403)
end
@@ -513,7 +521,7 @@ module API
case headers['X-Sendfile-Type']
when 'X-Sendfile'
header['X-Sendfile'] = path
- body
+ body '' # to avoid an error from API::APIGuard::ResponseCoercerMiddleware
else
sendfile path
end
@@ -529,7 +537,7 @@ module API
else
header(*Gitlab::Workhorse.send_url(file.url))
status :ok
- body ""
+ body '' # to avoid an error from API::APIGuard::ResponseCoercerMiddleware
end
end
@@ -562,7 +570,7 @@ module API
return unless Feature.enabled?(feature_flag, default_enabled: true)
- Gitlab::UsageDataCounters::HLLRedisCounter.track_event(values, event_name)
+ Gitlab::UsageDataCounters::HLLRedisCounter.track_event(event_name, values: values)
rescue => error
Gitlab::AppLogger.warn("Redis tracking event failed for event: #{event_name}, message: #{error.message}")
end
diff --git a/lib/api/helpers/authentication.rb b/lib/api/helpers/authentication.rb
new file mode 100644
index 00000000000..a6cfe930190
--- /dev/null
+++ b/lib/api/helpers/authentication.rb
@@ -0,0 +1,73 @@
+# frozen_string_literal: true
+
+module API
+ module Helpers
+ module Authentication
+ extend ActiveSupport::Concern
+
+ class_methods do
+ def authenticate_with(&block)
+ strategies = ::Gitlab::APIAuthentication::Builder.new.build(&block)
+ namespace_inheritable :authentication, strategies
+ end
+ end
+
+ included do
+ helpers ::Gitlab::Utils::StrongMemoize
+
+ helpers do
+ def token_from_namespace_inheritable
+ strong_memoize(:token_from_namespace_inheritable) do
+ strategies = namespace_inheritable(:authentication)
+ next unless strategies&.any?
+
+ # Extract credentials from the request
+ found = strategies.to_h { |location, _| [location, ::Gitlab::APIAuthentication::TokenLocator.new(location).extract(current_request)] }
+ found.filter! { |location, raw| raw }
+ next unless found.any?
+
+ # Specifying multiple credentials is an error
+ # https://gitlab.com/gitlab-org/gitlab/-/merge_requests/38627#note_475984136
+ bad_request!('Found more than one set of credentials') if found.size > 1
+
+ location, raw = found.first
+ find_token_from_raw_credentials(strategies[location], raw)
+ end
+
+ rescue ::Gitlab::Auth::UnauthorizedError
+ # TODO: this should be rescued and converted by the exception handling middleware
+ # https://gitlab.com/gitlab-org/gitlab/-/merge_requests/38627#note_475174516
+ unauthorized!
+ end
+
+ def access_token_from_namespace_inheritable
+ token = token_from_namespace_inheritable
+ token if token.is_a? PersonalAccessToken
+ end
+
+ def user_from_namespace_inheritable
+ token = token_from_namespace_inheritable
+ return token if token.is_a? DeployToken
+
+ token&.user
+ end
+
+ private
+
+ def find_token_from_raw_credentials(token_types, raw)
+ token_types.each do |token_type|
+ # Resolve a token from the raw credentials
+ token = ::Gitlab::APIAuthentication::TokenResolver.new(token_type).resolve(raw)
+ return token if token
+ end
+
+ # If a request provides credentials via an allowed transport, the
+ # credentials must be valid. If we reach this point, the credentials
+ # must not be valid credentials of an allowed type.
+ raise ::Gitlab::Auth::UnauthorizedError
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/api/helpers/merge_requests_helpers.rb b/lib/api/helpers/merge_requests_helpers.rb
index 9b38eeb1e72..f8fe40f7135 100644
--- a/lib/api/helpers/merge_requests_helpers.rb
+++ b/lib/api/helpers/merge_requests_helpers.rb
@@ -21,6 +21,9 @@ module API
coerce_with: Validations::Validators::CheckAssigneesCount.coerce,
desc: 'Return merge requests which are assigned to the user with the given username'
mutually_exclusive :assignee_id, :assignee_username
+ optional :reviewer_username,
+ type: String,
+ desc: 'Return merge requests which have the user as a reviewer with the given username'
optional :labels,
type: Array[String],
@@ -32,6 +35,11 @@ module API
params :merge_requests_base_params do
use :merge_requests_negatable_params
+ optional :reviewer_id,
+ types: [Integer, String],
+ integer_none_any: true,
+ desc: 'Return merge requests which have the user as a reviewer with the given ID'
+ mutually_exclusive :reviewer_id, :reviewer_username
optional :state,
type: String,
values: %w[opened closed locked merged all],
@@ -72,6 +80,10 @@ module API
optional :wip, type: String, values: %w[yes no], desc: 'Search merge requests for WIP in the title'
optional :not, type: Hash, desc: 'Parameters to negate' do
use :merge_requests_negatable_params
+ optional :reviewer_id,
+ types: Integer,
+ desc: 'Return merge requests which have the user as a reviewer with the given ID'
+ mutually_exclusive :reviewer_id, :reviewer_username
end
optional :deployed_before,
diff --git a/lib/api/helpers/packages/basic_auth_helpers.rb b/lib/api/helpers/packages/basic_auth_helpers.rb
index 0784efc11d6..c32ce199dd6 100644
--- a/lib/api/helpers/packages/basic_auth_helpers.rb
+++ b/lib/api/helpers/packages/basic_auth_helpers.rb
@@ -12,6 +12,7 @@ module API
end
include Constants
+ include Gitlab::Utils::StrongMemoize
def unauthorized_user_project
@unauthorized_user_project ||= find_project(params[:id])
@@ -35,6 +36,18 @@ module API
project
end
+ def find_authorized_group!
+ strong_memoize(:authorized_group) do
+ group = find_group(params[:id])
+
+ unless group && can?(current_user, :read_group, group)
+ next unauthorized_or! { not_found! }
+ end
+
+ group
+ end
+ end
+
def authorize!(action, subject = :global, reason = nil)
return if can?(current_user, action, subject)
diff --git a/lib/api/helpers/pagination.rb b/lib/api/helpers/pagination.rb
index 227aec224e5..48618e7d26d 100644
--- a/lib/api/helpers/pagination.rb
+++ b/lib/api/helpers/pagination.rb
@@ -3,8 +3,8 @@
module API
module Helpers
module Pagination
- def paginate(*args)
- Gitlab::Pagination::OffsetPagination.new(self).paginate(*args)
+ def paginate(*args, **kwargs)
+ Gitlab::Pagination::OffsetPagination.new(self).paginate(*args, **kwargs)
end
end
end
diff --git a/lib/api/helpers/projects_helpers.rb b/lib/api/helpers/projects_helpers.rb
index f5f45cf7351..cf2bcace33b 100644
--- a/lib/api/helpers/projects_helpers.rb
+++ b/lib/api/helpers/projects_helpers.rb
@@ -87,6 +87,7 @@ module API
params :optional_update_params_ce do
optional :ci_forward_deployment_enabled, type: Boolean, desc: 'Skip older deployment jobs that are still pending'
+ optional :restrict_user_defined_variables, type: Boolean, desc: 'Restrict use of user-defined variables when triggering a pipeline'
end
params :optional_update_params_ee do
@@ -99,7 +100,7 @@ module API
params :optional_container_expiration_policy_params do
optional :cadence, type: String, desc: 'Container expiration policy cadence for recurring job'
- optional :keep_n, type: String, desc: 'Container expiration policy number of images to keep'
+ optional :keep_n, type: Integer, desc: 'Container expiration policy number of images to keep'
optional :older_than, type: String, desc: 'Container expiration policy remove images older than value'
optional :name_regex, type: String, desc: 'Container expiration policy regex for image removal'
optional :name_regex_keep, type: String, desc: 'Container expiration policy regex for image retention'
@@ -141,6 +142,7 @@ module API
:repository_access_level,
:request_access_enabled,
:resolve_outdated_diff_discussions,
+ :restrict_user_defined_variables,
:shared_runners_enabled,
:snippets_access_level,
:tag_list,
diff --git a/lib/api/helpers/services_helpers.rb b/lib/api/helpers/services_helpers.rb
index 9d2fd9978d9..6101a8d307e 100644
--- a/lib/api/helpers/services_helpers.rb
+++ b/lib/api/helpers/services_helpers.rb
@@ -161,7 +161,6 @@ module API
def self.services
{
- 'alerts' => [],
'asana' => [
{
required: true,
@@ -807,7 +806,6 @@ module API
def self.service_classes
[
- ::AlertsService,
::AsanaService,
::AssemblaService,
::BambooService,
diff --git a/lib/api/internal/base.rb b/lib/api/internal/base.rb
index 332f2f1986f..12bb6e77c3e 100644
--- a/lib/api/internal/base.rb
+++ b/lib/api/internal/base.rb
@@ -16,6 +16,7 @@ module API
user: -> { actor&.user },
project: -> { project },
caller_id: route.origin,
+ remote_ip: request.ip,
feature_category: feature_category
)
end
diff --git a/lib/api/invitations.rb b/lib/api/invitations.rb
index be8147908e9..2ab1f97afe6 100644
--- a/lib/api/invitations.rb
+++ b/lib/api/invitations.rb
@@ -48,6 +48,24 @@ module API
present_member_invitations invitations
end
+
+ desc 'Removes an invitation from a group or project.'
+ params do
+ requires :email, type: String, desc: 'The email address of the invitation'
+ end
+ delete ":id/invitations/:email", requirements: { email: /[^\/]+/ } do
+ source = find_source(source_type, params[:id])
+ invite_email = params[:email]
+ authorize_admin_source!(source_type, source)
+
+ invite = retrieve_member_invitations(source, invite_email).first
+ not_found! unless invite
+
+ destroy_conditionally!(invite) do
+ ::Members::DestroyService.new(current_user, params).execute(invite)
+ unprocessable_entity! unless invite.destroyed?
+ end
+ end
end
end
end
diff --git a/lib/api/job_artifacts.rb b/lib/api/job_artifacts.rb
index 1faa28d6f07..28737f61f61 100644
--- a/lib/api/job_artifacts.rb
+++ b/lib/api/job_artifacts.rb
@@ -32,6 +32,7 @@ module API
authorize_download_artifacts!
latest_build = user_project.latest_successful_build_for_ref!(params[:job], params[:ref_name])
+ authorize_read_job_artifacts!(latest_build)
present_carrierwave_file!(latest_build.artifacts_file)
end
@@ -50,6 +51,7 @@ module API
authorize_download_artifacts!
build = user_project.latest_successful_build_for_ref!(params[:job], params[:ref_name])
+ authorize_read_job_artifacts!(build)
path = Gitlab::Ci::Build::Artifacts::Path
.new(params[:artifact_path])
@@ -70,6 +72,7 @@ module API
authorize_download_artifacts!
build = find_build!(params[:job_id])
+ authorize_read_job_artifacts!(build)
present_carrierwave_file!(build.artifacts_file)
end
@@ -82,9 +85,11 @@ module API
requires :artifact_path, type: String, desc: 'Artifact path'
end
get ':id/jobs/:job_id/artifacts/*artifact_path', format: false do
- authorize_read_builds!
+ authorize_download_artifacts!
build = find_build!(params[:job_id])
+ authorize_read_job_artifacts!(build)
+
not_found! unless build.artifacts?
path = Gitlab::Ci::Build::Artifacts::Path
diff --git a/lib/api/jobs.rb b/lib/api/jobs.rb
index 44751b3d76c..e14a4a5e680 100644
--- a/lib/api/jobs.rb
+++ b/lib/api/jobs.rb
@@ -138,25 +138,32 @@ module API
present build, with: Entities::Ci::Job
end
- desc 'Trigger a actionable job (manual, delayed, etc)' do
- success Entities::Ci::Job
+ desc 'Trigger an actionable job (manual, delayed, etc)' do
+ success Entities::Ci::JobBasic
detail 'This feature was added in GitLab 8.11'
end
params do
requires :job_id, type: Integer, desc: 'The ID of a Job'
end
+
post ":id/jobs/:job_id/play" do
authorize_read_builds!
- build = find_build!(params[:job_id])
+ job = find_job!(params[:job_id])
- authorize!(:update_build, build)
- bad_request!("Unplayable Job") unless build.playable?
+ authorize!(:play_job, job)
- build.play(current_user)
+ bad_request!("Unplayable Job") unless job.playable?
+
+ job.play(current_user)
status 200
- present build, with: Entities::Ci::Job
+
+ if job.is_a?(::Ci::Build)
+ present job, with: Entities::Ci::Job
+ else
+ present job, with: Entities::Ci::Bridge
+ end
end
end
diff --git a/lib/api/lint.rb b/lib/api/lint.rb
index 58181adaa93..f1f34622187 100644
--- a/lib/api/lint.rb
+++ b/lib/api/lint.rb
@@ -12,14 +12,13 @@ module API
end
post '/lint' do
result = Gitlab::Ci::YamlProcessor.new(params[:content], user: current_user).execute
- error = result.errors.first
status 200
- response = if error.blank?
+ response = if result.errors.empty?
{ status: 'valid', errors: [], warnings: result.warnings }
else
- { status: 'invalid', errors: [error], warnings: result.warnings }
+ { status: 'invalid', errors: result.errors, warnings: result.warnings }
end
response.tap do |response|
diff --git a/lib/api/maven_packages.rb b/lib/api/maven_packages.rb
index 7b4e52d18e8..4a5b2ead163 100644
--- a/lib/api/maven_packages.rb
+++ b/lib/api/maven_packages.rb
@@ -220,9 +220,13 @@ module API
file_name, format = extract_format(params[:file_name])
- package = ::Packages::Maven::FindOrCreatePackageService
+ result = ::Packages::Maven::FindOrCreatePackageService
.new(user_project, current_user, params.merge(build: current_authenticated_job)).execute
+ bad_request!(result.errors.first) if result.error?
+
+ package = result.payload[:package]
+
case format
when 'sha1'
# After uploading a file, Maven tries to upload a sha1 and md5 version of it.
diff --git a/lib/api/nuget_group_packages.rb b/lib/api/nuget_group_packages.rb
new file mode 100644
index 00000000000..e373f051b24
--- /dev/null
+++ b/lib/api/nuget_group_packages.rb
@@ -0,0 +1,58 @@
+# frozen_string_literal: true
+
+# NuGet Package Manager Client API
+#
+# These API endpoints are not meant to be consumed directly by users. They are
+# called by the NuGet package manager client when users run commands
+# like `nuget install` or `nuget push`.
+#
+# This is the group level API.
+module API
+ class NugetGroupPackages < ::API::Base
+ helpers ::API::Helpers::PackagesHelpers
+ helpers ::API::Helpers::Packages::BasicAuthHelpers
+ include ::API::Helpers::Authentication
+
+ feature_category :package_registry
+
+ default_format :json
+
+ authenticate_with do |accept|
+ accept.token_types(:personal_access_token, :deploy_token, :job_token)
+ .sent_through(:http_basic_auth)
+ end
+
+ rescue_from ArgumentError do |e|
+ render_api_error!(e.message, 400)
+ end
+
+ after_validation do
+ require_packages_enabled!
+ end
+
+ helpers do
+ def project_or_group
+ find_authorized_group!
+ end
+
+ def require_authenticated!
+ unauthorized! unless current_user
+ end
+ end
+
+ params do
+ requires :id, type: String, desc: 'The ID of a group', regexp: ::API::Concerns::Packages::NugetEndpoints::POSITIVE_INTEGER_REGEX
+ end
+
+ resource :groups, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
+ namespace ':id/-/packages/nuget' do
+ after_validation do
+ # This API can't be accessed anonymously
+ require_authenticated!
+ end
+
+ include ::API::Concerns::Packages::NugetEndpoints
+ end
+ end
+ end
+end
diff --git a/lib/api/nuget_project_packages.rb b/lib/api/nuget_project_packages.rb
index b2516cc91f8..2146f4d4b78 100644
--- a/lib/api/nuget_project_packages.rb
+++ b/lib/api/nuget_project_packages.rb
@@ -5,10 +5,13 @@
# These API endpoints are not meant to be consumed directly by users. They are
# called by the NuGet package manager client when users run commands
# like `nuget install` or `nuget push`.
+#
+# This is the project level API.
module API
class NugetProjectPackages < ::API::Base
- helpers ::API::Helpers::PackagesManagerClientsHelpers
+ helpers ::API::Helpers::PackagesHelpers
helpers ::API::Helpers::Packages::BasicAuthHelpers
+ include ::API::Helpers::Authentication
feature_category :package_registry
@@ -16,25 +19,29 @@ module API
default_format :json
+ authenticate_with do |accept|
+ accept.token_types(:personal_access_token, :deploy_token, :job_token)
+ .sent_through(:http_basic_auth)
+ end
+
rescue_from ArgumentError do |e|
render_api_error!(e.message, 400)
end
- before do
+ after_validation do
require_packages_enabled!
end
+ helpers do
+ def project_or_group
+ authorized_user_project
+ end
+ end
+
params do
requires :id, type: String, desc: 'The ID of a project', regexp: ::API::Concerns::Packages::NugetEndpoints::POSITIVE_INTEGER_REGEX
end
-
- route_setting :authentication, deploy_token_allowed: true, job_token_allowed: :basic_auth, basic_auth_personal_access_token: true
-
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
- before do
- authorized_user_project
- end
-
namespace ':id/packages/nuget' do
include ::API::Concerns::Packages::NugetEndpoints
@@ -46,28 +53,20 @@ module API
params do
requires :package, type: ::API::Validations::Types::WorkhorseFile, desc: 'The package file to be published (generated by Multipart middleware)'
end
-
- route_setting :authentication, deploy_token_allowed: true, job_token_allowed: :basic_auth, basic_auth_personal_access_token: true
-
put do
- authorize_upload!(authorized_user_project)
- bad_request!('File is too large') if authorized_user_project.actual_limits.exceeded?(:nuget_max_file_size, params[:package].size)
+ authorize_upload!(project_or_group)
+ bad_request!('File is too large') if project_or_group.actual_limits.exceeded?(:nuget_max_file_size, params[:package].size)
file_params = params.merge(
file: params[:package],
file_name: PACKAGE_FILENAME
)
- package = ::Packages::Nuget::CreatePackageService.new(
- authorized_user_project,
- current_user,
- declared_params.merge(build: current_authenticated_job)
- ).execute
+ package = ::Packages::Nuget::CreatePackageService.new(project_or_group, current_user, declared_params.merge(build: current_authenticated_job))
+ .execute
- package_file = ::Packages::CreatePackageFileService.new(
- package,
- file_params.merge(build: current_authenticated_job)
- ).execute
+ package_file = ::Packages::CreatePackageFileService.new(package, file_params.merge(build: current_authenticated_job))
+ .execute
track_package_event('push_package', :nuget, category: 'API::NugetPackages')
@@ -75,18 +74,15 @@ module API
created!
rescue ObjectStorage::RemoteStoreError => e
- Gitlab::ErrorTracking.track_exception(e, extra: { file_name: params[:file_name], project_id: authorized_user_project.id })
+ Gitlab::ErrorTracking.track_exception(e, extra: { file_name: params[:file_name], project_id: project_or_group.id })
forbidden!
end
-
- route_setting :authentication, deploy_token_allowed: true, job_token_allowed: :basic_auth, basic_auth_personal_access_token: true
-
put 'authorize' do
authorize_workhorse!(
- subject: authorized_user_project,
+ subject: project_or_group,
has_length: false,
- maximum_size: authorized_user_project.actual_limits.nuget_max_file_size
+ maximum_size: project_or_group.actual_limits.nuget_max_file_size
)
end
@@ -95,18 +91,15 @@ module API
requires :package_name, type: String, desc: 'The NuGet package name', regexp: API::NO_SLASH_URL_PART_REGEX
end
namespace '/download/*package_name' do
- before do
- authorize_read_package!(authorized_user_project)
+ after_validation do
+ authorize_read_package!(project_or_group)
end
desc 'The NuGet Content Service - index request' do
detail 'This feature was introduced in GitLab 12.8'
end
-
- route_setting :authentication, deploy_token_allowed: true, job_token_allowed: :basic_auth, basic_auth_personal_access_token: true
-
get 'index', format: :json do
- present ::Packages::Nuget::PackagesVersionsPresenter.new(find_packages),
+ present ::Packages::Nuget::PackagesVersionsPresenter.new(find_packages(params[:package_name])),
with: ::API::Entities::Nuget::PackagesVersions
end
@@ -117,12 +110,9 @@ module API
requires :package_version, type: String, desc: 'The NuGet package version', regexp: API::NO_SLASH_URL_PART_REGEX
requires :package_filename, type: String, desc: 'The NuGet package filename', regexp: API::NO_SLASH_URL_PART_REGEX
end
-
- route_setting :authentication, deploy_token_allowed: true, job_token_allowed: :basic_auth, basic_auth_personal_access_token: true
-
get '*package_version/*package_filename', format: :nupkg do
filename = "#{params[:package_filename]}.#{params[:format]}"
- package_file = ::Packages::PackageFileFinder.new(find_package, filename, with_file_name_like: true)
+ package_file = ::Packages::PackageFileFinder.new(find_package(params[:package_name], params[:package_version]), filename, with_file_name_like: true)
.execute
not_found!('Package') unless package_file
diff --git a/lib/api/project_packages.rb b/lib/api/project_packages.rb
index 56e94333433..32636662987 100644
--- a/lib/api/project_packages.rb
+++ b/lib/api/project_packages.rb
@@ -30,11 +30,13 @@ module API
desc: 'Return packages of a certain type'
optional :package_name, type: String,
desc: 'Return packages with this name'
+ optional :include_versionless, type: Boolean,
+ desc: 'Returns packages without a version'
end
get ':id/packages' do
packages = ::Packages::PackagesFinder.new(
user_project,
- declared_params.slice(:order_by, :sort, :package_type, :package_name)
+ declared_params.slice(:order_by, :sort, :package_type, :package_name, :include_versionless)
).execute
present paginate(packages), with: ::API::Entities::Package, user: current_user
diff --git a/lib/api/project_templates.rb b/lib/api/project_templates.rb
index af5d96969ef..19244ed697f 100644
--- a/lib/api/project_templates.rb
+++ b/lib/api/project_templates.rb
@@ -4,7 +4,7 @@ module API
class ProjectTemplates < ::API::Base
include PaginationParams
- TEMPLATE_TYPES = %w[dockerfiles gitignores gitlab_ci_ymls licenses metrics_dashboard_ymls issues merge_requests].freeze
+ TEMPLATE_TYPES = %w[dockerfiles gitignores gitlab_ci_ymls gitlab_ci_syntax_ymls licenses metrics_dashboard_ymls issues merge_requests].freeze
# The regex is needed to ensure a period (e.g. agpl-3.0)
# isn't confused with a format type. We also need to allow encoded
# values (e.g. C%2B%2B for C++), so allow % and + as well.
@@ -16,7 +16,7 @@ module API
params do
requires :id, type: String, desc: 'The ID of a project'
- requires :type, type: String, values: TEMPLATE_TYPES, desc: 'The type (dockerfiles|gitignores|gitlab_ci_ymls|licenses|metrics_dashboard_ymls|issues|merge_requests) of the template'
+ requires :type, type: String, values: TEMPLATE_TYPES, desc: 'The type (dockerfiles|gitignores|gitlab_ci_ymls|gitlab_ci_syntax_ymls|licenses|metrics_dashboard_ymls|issues|merge_requests) of the template'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
desc 'Get a list of templates available to this project' do
diff --git a/lib/api/projects.rb b/lib/api/projects.rb
index 2012c348cd1..2d09ad01757 100644
--- a/lib/api/projects.rb
+++ b/lib/api/projects.rb
@@ -566,8 +566,8 @@ module API
authorize_admin_project
begin
- ::Projects::HousekeepingService.new(user_project, :gc).execute
- rescue ::Projects::HousekeepingService::LeaseTaken => error
+ ::Repositories::HousekeepingService.new(user_project, :gc).execute
+ rescue ::Repositories::HousekeepingService::LeaseTaken => error
conflict!(error.message)
end
end
diff --git a/lib/api/settings.rb b/lib/api/settings.rb
index b3f09b431b0..f329a94adf2 100644
--- a/lib/api/settings.rb
+++ b/lib/api/settings.rb
@@ -91,6 +91,7 @@ module API
optional :import_sources, type: Array[String], coerce_with: Validations::Types::CommaSeparatedToArray.coerce,
values: %w[github bitbucket bitbucket_server gitlab google_code fogbugz git gitlab_project gitea manifest phabricator],
desc: 'Enabled sources for code import during project creation. OmniAuth must be configured for GitHub, Bitbucket, and GitLab.com'
+ optional :invisible_captcha_enabled, type: Boolean, desc: 'Enable Invisible Captcha spam detection during signup.'
optional :max_artifacts_size, type: Integer, desc: "Set the maximum file size for each job's artifacts"
optional :max_attachment_size, type: Integer, desc: 'Maximum attachment size in MB'
optional :max_import_size, type: Integer, desc: 'Maximum import size in MB'
diff --git a/lib/api/snippet_repository_storage_moves.rb b/lib/api/snippet_repository_storage_moves.rb
new file mode 100644
index 00000000000..1a5b41eb1ec
--- /dev/null
+++ b/lib/api/snippet_repository_storage_moves.rb
@@ -0,0 +1,110 @@
+# frozen_string_literal: true
+
+module API
+ class SnippetRepositoryStorageMoves < ::API::Base
+ include PaginationParams
+
+ before { authenticated_as_admin! }
+
+ feature_category :gitaly
+
+ resource :snippet_repository_storage_moves do
+ desc 'Get a list of all snippet repository storage moves' do
+ detail 'This feature was introduced in GitLab 13.8.'
+ success Entities::SnippetRepositoryStorageMove
+ end
+ params do
+ use :pagination
+ end
+ get do
+ storage_moves = SnippetRepositoryStorageMove.order_created_at_desc
+
+ present paginate(storage_moves), with: Entities::SnippetRepositoryStorageMove, current_user: current_user
+ end
+
+ desc 'Get a snippet repository storage move' do
+ detail 'This feature was introduced in GitLab 13.8.'
+ success Entities::SnippetRepositoryStorageMove
+ end
+ params do
+ requires :repository_storage_move_id, type: Integer, desc: 'The ID of a snippet repository storage move'
+ end
+ get ':repository_storage_move_id' do
+ storage_move = SnippetRepositoryStorageMove.find(params[:repository_storage_move_id])
+
+ present storage_move, with: Entities::SnippetRepositoryStorageMove, current_user: current_user
+ end
+
+ desc 'Schedule bulk snippet repository storage moves' do
+ detail 'This feature was introduced in GitLab 13.8.'
+ end
+ params do
+ requires :source_storage_name, type: String, desc: 'The source storage shard', values: -> { Gitlab.config.repositories.storages.keys }
+ optional :destination_storage_name, type: String, desc: 'The destination storage shard', values: -> { Gitlab.config.repositories.storages.keys }
+ end
+ post do
+ ::Snippets::ScheduleBulkRepositoryShardMovesService.enqueue(
+ declared_params[:source_storage_name],
+ declared_params[:destination_storage_name]
+ )
+
+ accepted!
+ end
+ end
+
+ params do
+ requires :id, type: String, desc: 'The ID of a snippet'
+ end
+ resource :snippets do
+ helpers do
+ def user_snippet
+ Snippet.find_by(id: params[:id]) # rubocop: disable CodeReuse/ActiveRecord
+ end
+ end
+ desc 'Get a list of all snippets repository storage moves' do
+ detail 'This feature was introduced in GitLab 13.8.'
+ success Entities::SnippetRepositoryStorageMove
+ end
+ params do
+ use :pagination
+ end
+ get ':id/repository_storage_moves' do
+ storage_moves = user_snippet.repository_storage_moves.order_created_at_desc
+
+ present paginate(storage_moves), with: Entities::SnippetRepositoryStorageMove, current_user: current_user
+ end
+
+ desc 'Get a snippet repository storage move' do
+ detail 'This feature was introduced in GitLab 13.8.'
+ success Entities::SnippetRepositoryStorageMove
+ end
+ params do
+ requires :repository_storage_move_id, type: Integer, desc: 'The ID of a snippet repository storage move'
+ end
+ get ':id/repository_storage_moves/:repository_storage_move_id' do
+ storage_move = user_snippet.repository_storage_moves.find(params[:repository_storage_move_id])
+
+ present storage_move, with: Entities::SnippetRepositoryStorageMove, current_user: current_user
+ end
+
+ desc 'Schedule a snippet repository storage move' do
+ detail 'This feature was introduced in GitLab 13.8.'
+ success Entities::SnippetRepositoryStorageMove
+ end
+ params do
+ optional :destination_storage_name, type: String, desc: 'The destination storage shard'
+ end
+ post ':id/repository_storage_moves' do
+ storage_move = user_snippet.repository_storage_moves.build(
+ declared_params.merge(source_storage_name: user_snippet.repository_storage)
+ )
+
+ if storage_move.schedule
+ present storage_move, with: Entities::SnippetRepositoryStorageMove, current_user: current_user
+ else
+ render_validation_error!(storage_move)
+ end
+ end
+ end
+ end
+end
diff --git a/lib/api/templates.rb b/lib/api/templates.rb
index b7fb35eac03..bc1e427bcaa 100644
--- a/lib/api/templates.rb
+++ b/lib/api/templates.rb
@@ -13,6 +13,9 @@ module API
gitlab_ci_ymls: {
gitlab_version: 8.9
},
+ gitlab_ci_syntax_ymls: {
+ gitlab_version: 13.8
+ },
dockerfiles: {
gitlab_version: 8.15
}
diff --git a/lib/api/terraform/state.rb b/lib/api/terraform/state.rb
index c664c0a4590..f6dfbcafbb6 100644
--- a/lib/api/terraform/state.rb
+++ b/lib/api/terraform/state.rb
@@ -14,6 +14,8 @@ module API
before do
authenticate!
authorize! :read_terraform_state, user_project
+
+ increment_unique_values('p_terraform_state_api_unique_users', current_user.id)
end
params do
diff --git a/lib/api/usage_data.rb b/lib/api/usage_data.rb
index cad2f52e951..c7d63f8d6ac 100644
--- a/lib/api/usage_data.rb
+++ b/lib/api/usage_data.rb
@@ -4,7 +4,7 @@ module API
class UsageData < ::API::Base
before { authenticate! }
- feature_category :collection
+ feature_category :usage_ping
namespace 'usage_data' do
before do
diff --git a/lib/api/user_counts.rb b/lib/api/user_counts.rb
index 3071f08e1de..31c923a219a 100644
--- a/lib/api/user_counts.rb
+++ b/lib/api/user_counts.rb
@@ -12,7 +12,9 @@ module API
unauthorized! unless current_user
{
- merge_requests: current_user.assigned_open_merge_requests_count
+ merge_requests: current_user.assigned_open_merge_requests_count, # @deprecated
+ assigned_merge_requests: current_user.assigned_open_merge_requests_count,
+ review_requested_merge_requests: current_user.review_requested_open_merge_requests_count
}
end
end
diff --git a/lib/api/users.rb b/lib/api/users.rb
index 8b9b82877f7..cee09f60a2b 100644
--- a/lib/api/users.rb
+++ b/lib/api/users.rb
@@ -87,6 +87,7 @@ module API
optional :created_before, type: DateTime, desc: 'Return users created before the specified time'
optional :without_projects, type: Boolean, default: false, desc: 'Filters only users without projects'
optional :exclude_internal, as: :non_internal, type: Boolean, default: false, desc: 'Filters only non internal users'
+ optional :admins, type: Boolean, default: false, desc: 'Filters only admin users'
all_or_none_of :extern_uid, :provider
use :sort_params
@@ -745,8 +746,6 @@ module API
optional :expires_at, type: Date, desc: 'The expiration date in the format YEAR-MONTH-DAY of the personal access token'
end
post feature_category: :authentication_and_authorization do
- not_found! unless Feature.enabled?(:pat_creation_api_for_admin)
-
response = ::PersonalAccessTokens::CreateService.new(
current_user: current_user, target_user: target_user, params: declared_params(include_missing: false)
).execute