Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
e89a412ba3
commit
f791b9447b
19 changed files with 437 additions and 96 deletions
|
@ -186,18 +186,12 @@ RSpec/ExpectChange:
|
|||
# Offense count: 47
|
||||
RSpec/ExpectGitlabTracking:
|
||||
Exclude:
|
||||
- 'ee/spec/controllers/projects/settings/operations_controller_spec.rb'
|
||||
- 'ee/spec/requests/api/visual_review_discussions_spec.rb'
|
||||
- 'ee/spec/services/epics/issue_promote_service_spec.rb'
|
||||
- 'spec/controllers/groups/registry/repositories_controller_spec.rb'
|
||||
- 'spec/controllers/projects/registry/repositories_controller_spec.rb'
|
||||
- 'spec/controllers/projects/registry/tags_controller_spec.rb'
|
||||
- 'spec/controllers/projects/settings/operations_controller_spec.rb'
|
||||
- 'spec/controllers/registrations_controller_spec.rb'
|
||||
- 'spec/lib/api/helpers_spec.rb'
|
||||
- 'spec/requests/api/project_container_repositories_spec.rb'
|
||||
- 'spec/support/shared_examples/controllers/trackable_shared_examples.rb'
|
||||
- 'spec/support/shared_examples/requests/api/container_repositories_shared_examples.rb'
|
||||
- 'spec/support/shared_examples/requests/api/discussions_shared_examples.rb'
|
||||
- 'spec/support/shared_examples/requests/api/packages_shared_examples.rb'
|
||||
- 'spec/support/shared_examples/requests/api/tracking_shared_examples.rb'
|
||||
|
|
|
@ -395,7 +395,7 @@ class Environment < ApplicationRecord
|
|||
|
||||
# Overrides ReactiveCaching default to activate limit checking behind a FF
|
||||
def reactive_cache_limit_enabled?
|
||||
Feature.enabled?(:reactive_caching_limit_environment, project)
|
||||
Feature.enabled?(:reactive_caching_limit_environment, project, default_enabled: true)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
5
changelogs/unreleased/270200-downtier-pat-apis.yml
Normal file
5
changelogs/unreleased/270200-downtier-pat-apis.yml
Normal file
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Move Personal Access Token API to Core
|
||||
merge_request: 46145
|
||||
author:
|
||||
type: changed
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Make all Project Issue Boards API available even in CE
|
||||
merge_request: 46137
|
||||
author: Takuya Noguchi
|
||||
type: changed
|
|
@ -0,0 +1,6 @@
|
|||
---
|
||||
title: Limits the Deploy Boards data to 10 MB. This change is enabled by default behind
|
||||
a feature flag
|
||||
merge_request: 46043
|
||||
author:
|
||||
type: changed
|
|
@ -4,4 +4,4 @@ introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/34202
|
|||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/202633
|
||||
group: group::configure
|
||||
type: development
|
||||
default_enabled: false
|
||||
default_enabled: true
|
||||
|
|
|
@ -3,5 +3,5 @@ name: suggest_pipeline
|
|||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/45926
|
||||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/267492
|
||||
type: development
|
||||
group: group::growth
|
||||
group: group::expansion
|
||||
default_enabled: true
|
||||
|
|
|
@ -4,13 +4,14 @@ group: unassigned
|
|||
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#designated-technical-writers
|
||||
---
|
||||
|
||||
# Personal access tokens API **(ULTIMATE)**
|
||||
# Personal access tokens API
|
||||
|
||||
You can read more about [personal access tokens](../user/profile/personal_access_tokens.md#personal-access-tokens).
|
||||
|
||||
## List personal access tokens
|
||||
|
||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/227264) in [GitLab Ultimate](https://about.gitlab.com/pricing/) 13.3.
|
||||
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/227264) in [GitLab Ultimate](https://about.gitlab.com/pricing/) 13.3.
|
||||
> - [Moved](https://gitlab.com/gitlab-org/gitlab/-/issues/270200) to [GitLab Core](https://about.gitlab.com/pricing/) in 13.6.
|
||||
|
||||
Get a list of personal access tokens.
|
||||
|
||||
|
|
|
@ -237,6 +237,7 @@ module API
|
|||
mount ::API::ProjectTemplates
|
||||
mount ::API::Terraform::State
|
||||
mount ::API::Terraform::StateVersion
|
||||
mount ::API::PersonalAccessTokens
|
||||
mount ::API::ProtectedBranches
|
||||
mount ::API::ProtectedTags
|
||||
mount ::API::Releases
|
||||
|
|
|
@ -42,6 +42,43 @@ module API
|
|||
authorize!(:read_board, user_project)
|
||||
present board, with: Entities::Board
|
||||
end
|
||||
|
||||
desc 'Create a project board' do
|
||||
detail 'This feature was introduced in 10.4'
|
||||
success Entities::Board
|
||||
end
|
||||
params do
|
||||
requires :name, type: String, desc: 'The board name'
|
||||
end
|
||||
post '/' do
|
||||
authorize!(:admin_board, board_parent)
|
||||
|
||||
create_board
|
||||
end
|
||||
|
||||
desc 'Update a project board' do
|
||||
detail 'This feature was introduced in 11.0'
|
||||
success Entities::Board
|
||||
end
|
||||
params do
|
||||
use :update_params
|
||||
end
|
||||
put '/:board_id' do
|
||||
authorize!(:admin_board, board_parent)
|
||||
|
||||
update_board
|
||||
end
|
||||
|
||||
desc 'Delete a project board' do
|
||||
detail 'This feature was introduced in 10.4'
|
||||
success Entities::Board
|
||||
end
|
||||
|
||||
delete '/:board_id' do
|
||||
authorize!(:admin_board, board_parent)
|
||||
|
||||
delete_board
|
||||
end
|
||||
end
|
||||
|
||||
params do
|
||||
|
|
|
@ -10,6 +10,35 @@ module API
|
|||
board_parent.boards.find(params[:board_id])
|
||||
end
|
||||
|
||||
def create_board
|
||||
forbidden! unless board_parent.multiple_issue_boards_available?
|
||||
|
||||
response =
|
||||
::Boards::CreateService.new(board_parent, current_user, { name: params[:name] }).execute
|
||||
|
||||
present response.payload, with: Entities::Board
|
||||
end
|
||||
|
||||
def update_board
|
||||
service = ::Boards::UpdateService.new(board_parent, current_user, declared_params(include_missing: false))
|
||||
service.execute(board)
|
||||
|
||||
if board.valid?
|
||||
present board, with: Entities::Board
|
||||
else
|
||||
bad_request!("Failed to save board #{board.errors.messages}")
|
||||
end
|
||||
end
|
||||
|
||||
def delete_board
|
||||
forbidden! unless board_parent.multiple_issue_boards_available?
|
||||
|
||||
destroy_conditionally!(board) do |board|
|
||||
service = ::Boards::DestroyService.new(board_parent, current_user)
|
||||
service.execute(board)
|
||||
end
|
||||
end
|
||||
|
||||
def board_lists
|
||||
board.destroyable_lists
|
||||
end
|
||||
|
@ -62,6 +91,12 @@ module API
|
|||
params :list_creation_params do
|
||||
requires :label_id, type: Integer, desc: 'The ID of an existing label'
|
||||
end
|
||||
|
||||
params :update_params 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
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -4,6 +4,7 @@ module API
|
|||
module Entities
|
||||
class Board < Grape::Entity
|
||||
expose :id
|
||||
expose :name
|
||||
expose :project, using: Entities::BasicProjectDetails
|
||||
|
||||
expose :lists, using: Entities::List do |board|
|
||||
|
|
59
lib/api/personal_access_tokens.rb
Normal file
59
lib/api/personal_access_tokens.rb
Normal file
|
@ -0,0 +1,59 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module API
|
||||
class PersonalAccessTokens < ::API::Base
|
||||
include ::API::PaginationParams
|
||||
|
||||
desc 'Get all Personal Access Tokens' do
|
||||
detail 'This feature was added in GitLab 13.3'
|
||||
success Entities::PersonalAccessToken
|
||||
end
|
||||
params do
|
||||
optional :user_id, type: Integer, desc: 'User ID'
|
||||
|
||||
use :pagination
|
||||
end
|
||||
|
||||
before do
|
||||
authenticate!
|
||||
restrict_non_admins! unless current_user.admin?
|
||||
end
|
||||
|
||||
helpers do
|
||||
def finder_params(current_user)
|
||||
current_user.admin? ? { user: user(params[:user_id]) } : { user: current_user }
|
||||
end
|
||||
|
||||
def user(user_id)
|
||||
UserFinder.new(user_id).find_by_id
|
||||
end
|
||||
|
||||
def restrict_non_admins!
|
||||
return if params[:user_id].blank?
|
||||
|
||||
unauthorized! unless Ability.allowed?(current_user, :read_user_personal_access_tokens, user(params[:user_id]))
|
||||
end
|
||||
|
||||
def find_token(id)
|
||||
PersonalAccessToken.find(id) || not_found!
|
||||
end
|
||||
end
|
||||
|
||||
resources :personal_access_tokens do
|
||||
get do
|
||||
tokens = PersonalAccessTokensFinder.new(finder_params(current_user), current_user).execute
|
||||
|
||||
present paginate(tokens), with: Entities::PersonalAccessToken
|
||||
end
|
||||
|
||||
delete ':id' do
|
||||
service = ::PersonalAccessTokens::RevokeService.new(
|
||||
current_user,
|
||||
{ token: find_token(params[:id]) }
|
||||
).execute
|
||||
|
||||
service.success? ? no_content! : bad_request!(nil)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -64,12 +64,11 @@ RSpec.describe Groups::Registry::RepositoriesController do
|
|||
context 'html format' do
|
||||
let(:format) { :html }
|
||||
|
||||
it 'show index page' do
|
||||
expect(Gitlab::Tracking).not_to receive(:event)
|
||||
|
||||
it 'show index page', :snowplow do
|
||||
subject
|
||||
|
||||
expect(response).to have_gitlab_http_status(:ok)
|
||||
expect_no_snowplow_event
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
require 'spec_helper'
|
||||
|
||||
# rubocop: disable RSpec/FactoriesInMigrationSpecs
|
||||
RSpec.describe Gitlab::BackgroundMigration::LegacyUploadMover do
|
||||
RSpec.describe Gitlab::BackgroundMigration::LegacyUploadMover, :aggregate_failures do
|
||||
let(:test_dir) { FileUploader.options['storage_path'] }
|
||||
let(:filename) { 'image.png' }
|
||||
|
||||
|
@ -67,27 +67,35 @@ RSpec.describe Gitlab::BackgroundMigration::LegacyUploadMover do
|
|||
end
|
||||
end
|
||||
|
||||
shared_examples 'migrates the file correctly' do
|
||||
before do
|
||||
described_class.new(legacy_upload).execute
|
||||
end
|
||||
shared_examples 'migrates the file correctly' do |remote|
|
||||
it 'creates a new upload record correctly, updates the legacy upload note so that it references the file in the markdown, removes the attachment from the note model, removes the file, moves legacy uploads to the correct location, removes the upload record' do
|
||||
expect(File.exist?(legacy_upload.absolute_path)).to be_truthy unless remote
|
||||
|
||||
described_class.new(legacy_upload).execute
|
||||
|
||||
it 'creates a new uplaod record correctly' do
|
||||
expect(new_upload.secret).not_to be_nil
|
||||
expect(new_upload.path).to end_with("#{new_upload.secret}/image.png")
|
||||
expect(new_upload.path).to end_with("#{new_upload.secret}/#{filename}")
|
||||
expect(new_upload.model_id).to eq(project.id)
|
||||
expect(new_upload.model_type).to eq('Project')
|
||||
expect(new_upload.uploader).to eq('FileUploader')
|
||||
end
|
||||
|
||||
it 'updates the legacy upload note so that it references the file in the markdown' do
|
||||
expected_path = File.join('/uploads', new_upload.secret, 'image.png')
|
||||
expected_path = File.join('/uploads', new_upload.secret, filename)
|
||||
expected_markdown = "some note \n ![image](#{expected_path})"
|
||||
expect(note.reload.note).to eq(expected_markdown)
|
||||
end
|
||||
|
||||
it 'removes the attachment from the note model' do
|
||||
expect(note.reload.attachment.file).to be_nil
|
||||
expect(note.reload.note).to eq(expected_markdown)
|
||||
expect(note.attachment.file).to be_nil
|
||||
|
||||
if remote
|
||||
expect(bucket.files.get(remote_file[:key])).to be_nil
|
||||
connection = ::Fog::Storage.new(FileUploader.object_store_credentials)
|
||||
expect(connection.get_object('uploads', new_upload.path)[:status]).to eq(200)
|
||||
else
|
||||
expect(File.exist?(legacy_upload.absolute_path)).to be_falsey
|
||||
expected_path = File.join(test_dir, 'uploads', project.disk_path, new_upload.secret, filename)
|
||||
expect(File.exist?(expected_path)).to be_truthy
|
||||
end
|
||||
|
||||
expect { legacy_upload.reload }.to raise_error(ActiveRecord::RecordNotFound)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -120,23 +128,6 @@ RSpec.describe Gitlab::BackgroundMigration::LegacyUploadMover do
|
|||
end
|
||||
|
||||
context 'when the upload is in local storage' do
|
||||
shared_examples 'legacy local file' do
|
||||
it 'removes the file correctly' do
|
||||
expect(File.exist?(legacy_upload.absolute_path)).to be_truthy
|
||||
|
||||
described_class.new(legacy_upload).execute
|
||||
|
||||
expect(File.exist?(legacy_upload.absolute_path)).to be_falsey
|
||||
end
|
||||
|
||||
it 'moves legacy uploads to the correct location' do
|
||||
described_class.new(legacy_upload).execute
|
||||
|
||||
expected_path = File.join(test_dir, 'uploads', project.disk_path, new_upload.secret, filename)
|
||||
expect(File.exist?(expected_path)).to be_truthy
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the upload file does not exist on the filesystem' do
|
||||
let(:legacy_upload) { create_upload(note, filename, false) }
|
||||
|
||||
|
@ -201,15 +192,11 @@ RSpec.describe Gitlab::BackgroundMigration::LegacyUploadMover do
|
|||
path: "uploads/-/system/note/attachment/#{note.id}/#{filename}", model: note, mount_point: nil)
|
||||
end
|
||||
|
||||
it_behaves_like 'migrates the file correctly'
|
||||
it_behaves_like 'legacy local file'
|
||||
it_behaves_like 'legacy upload deletion'
|
||||
it_behaves_like 'migrates the file correctly', false
|
||||
end
|
||||
|
||||
context 'when the file can be handled correctly' do
|
||||
it_behaves_like 'migrates the file correctly'
|
||||
it_behaves_like 'legacy local file'
|
||||
it_behaves_like 'legacy upload deletion'
|
||||
it_behaves_like 'migrates the file correctly', false
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -217,17 +204,13 @@ RSpec.describe Gitlab::BackgroundMigration::LegacyUploadMover do
|
|||
context 'when the file belongs to a legacy project' do
|
||||
let(:project) { legacy_project }
|
||||
|
||||
it_behaves_like 'migrates the file correctly'
|
||||
it_behaves_like 'legacy local file'
|
||||
it_behaves_like 'legacy upload deletion'
|
||||
it_behaves_like 'migrates the file correctly', false
|
||||
end
|
||||
|
||||
context 'when the file belongs to a hashed project' do
|
||||
let(:project) { hashed_project }
|
||||
|
||||
it_behaves_like 'migrates the file correctly'
|
||||
it_behaves_like 'legacy local file'
|
||||
it_behaves_like 'legacy upload deletion'
|
||||
it_behaves_like 'migrates the file correctly', false
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -244,17 +227,13 @@ RSpec.describe Gitlab::BackgroundMigration::LegacyUploadMover do
|
|||
context 'when the file belongs to a legacy project' do
|
||||
let(:project) { legacy_project }
|
||||
|
||||
it_behaves_like 'migrates the file correctly'
|
||||
it_behaves_like 'legacy local file'
|
||||
it_behaves_like 'legacy upload deletion'
|
||||
it_behaves_like 'migrates the file correctly', false
|
||||
end
|
||||
|
||||
context 'when the file belongs to a hashed project' do
|
||||
let(:project) { hashed_project }
|
||||
|
||||
it_behaves_like 'migrates the file correctly'
|
||||
it_behaves_like 'legacy local file'
|
||||
it_behaves_like 'legacy upload deletion'
|
||||
it_behaves_like 'migrates the file correctly', false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -272,23 +251,6 @@ RSpec.describe Gitlab::BackgroundMigration::LegacyUploadMover do
|
|||
stub_uploads_object_storage(FileUploader)
|
||||
end
|
||||
|
||||
shared_examples 'legacy remote file' do
|
||||
it 'removes the file correctly' do
|
||||
# expect(bucket.files.get(remote_file[:key])).to be_nil
|
||||
|
||||
described_class.new(legacy_upload).execute
|
||||
|
||||
expect(bucket.files.get(remote_file[:key])).to be_nil
|
||||
end
|
||||
|
||||
it 'moves legacy uploads to the correct remote location' do
|
||||
described_class.new(legacy_upload).execute
|
||||
|
||||
connection = ::Fog::Storage.new(FileUploader.object_store_credentials)
|
||||
expect(connection.get_object('uploads', new_upload.path)[:status]).to eq(200)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the upload file does not exist on the filesystem' do
|
||||
it_behaves_like 'legacy upload deletion'
|
||||
end
|
||||
|
@ -300,9 +262,7 @@ RSpec.describe Gitlab::BackgroundMigration::LegacyUploadMover do
|
|||
|
||||
let(:project) { legacy_project }
|
||||
|
||||
it_behaves_like 'migrates the file correctly'
|
||||
it_behaves_like 'legacy remote file'
|
||||
it_behaves_like 'legacy upload deletion'
|
||||
it_behaves_like 'migrates the file correctly', true
|
||||
end
|
||||
|
||||
context 'when the file belongs to a hashed project' do
|
||||
|
@ -312,9 +272,7 @@ RSpec.describe Gitlab::BackgroundMigration::LegacyUploadMover do
|
|||
|
||||
let(:project) { hashed_project }
|
||||
|
||||
it_behaves_like 'migrates the file correctly'
|
||||
it_behaves_like 'legacy remote file'
|
||||
it_behaves_like 'legacy upload deletion'
|
||||
it_behaves_like 'migrates the file correctly', true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -35,7 +35,46 @@ RSpec.describe API::Boards do
|
|||
|
||||
it_behaves_like 'group and project boards', "/projects/:id/boards"
|
||||
|
||||
describe "POST /projects/:id/boards/lists" do
|
||||
describe "POST /projects/:id/boards" do
|
||||
let(:url) { "/projects/#{board_parent.id}/boards" }
|
||||
|
||||
it 'creates a new issue board' do
|
||||
post api(url, user), params: { name: 'foo' }
|
||||
|
||||
expect(response).to have_gitlab_http_status(:created)
|
||||
expect(json_response['name']).to eq('foo')
|
||||
end
|
||||
|
||||
it 'fails to create a new board' do
|
||||
post api(url, user), params: { some_name: 'foo' }
|
||||
|
||||
expect(response).to have_gitlab_http_status(:bad_request)
|
||||
expect(json_response['error']).to eq('name is missing')
|
||||
end
|
||||
end
|
||||
|
||||
describe "PUT /projects/:id/boards/:board_id" do
|
||||
let(:url) { "/projects/#{board_parent.id}/boards/#{board.id}" }
|
||||
|
||||
it 'updates the issue board' do
|
||||
put api(url, user), params: { name: 'changed board name' }
|
||||
|
||||
expect(response).to have_gitlab_http_status(:ok)
|
||||
expect(json_response['name']).to eq('changed board name')
|
||||
end
|
||||
end
|
||||
|
||||
describe "DELETE /projects/:id/boards/:board_id" do
|
||||
let(:url) { "/projects/#{board_parent.id}/boards/#{board.id}" }
|
||||
|
||||
it 'delete the issue board' do
|
||||
delete api(url, user)
|
||||
|
||||
expect(response).to have_gitlab_http_status(:no_content)
|
||||
end
|
||||
end
|
||||
|
||||
describe "POST /projects/:id/boards/:board_id/lists" do
|
||||
let(:url) { "/projects/#{board_parent.id}/boards/#{board.id}/lists" }
|
||||
|
||||
it 'creates a new issue board list for group labels' do
|
||||
|
@ -65,7 +104,7 @@ RSpec.describe API::Boards do
|
|||
end
|
||||
end
|
||||
|
||||
describe "POST /groups/:id/boards/lists" do
|
||||
describe "POST /groups/:id/boards/:board_id/lists" do
|
||||
let_it_be(:group) { create(:group) }
|
||||
let_it_be(:board_parent) { create(:group, parent: group ) }
|
||||
let(:url) { "/groups/#{board_parent.id}/boards/#{board.id}/lists" }
|
||||
|
|
112
spec/requests/api/personal_access_tokens_spec.rb
Normal file
112
spec/requests/api/personal_access_tokens_spec.rb
Normal file
|
@ -0,0 +1,112 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe API::PersonalAccessTokens do
|
||||
let_it_be(:path) { '/personal_access_tokens' }
|
||||
let_it_be(:token1) { create(:personal_access_token) }
|
||||
let_it_be(:token2) { create(:personal_access_token) }
|
||||
let_it_be(:current_user) { create(:user) }
|
||||
|
||||
describe 'GET /personal_access_tokens' do
|
||||
context 'logged in as an Administrator' do
|
||||
let_it_be(:current_user) { create(:admin) }
|
||||
|
||||
it 'returns all PATs by default' do
|
||||
get api(path, current_user)
|
||||
|
||||
expect(response).to have_gitlab_http_status(:ok)
|
||||
expect(json_response.count).to eq(PersonalAccessToken.all.count)
|
||||
end
|
||||
|
||||
context 'filtered with user_id parameter' do
|
||||
it 'returns only PATs belonging to that user' do
|
||||
get api(path, current_user), params: { user_id: token1.user.id }
|
||||
|
||||
expect(response).to have_gitlab_http_status(:ok)
|
||||
expect(json_response.count).to eq(1)
|
||||
expect(json_response.first['user_id']).to eq(token1.user.id)
|
||||
end
|
||||
end
|
||||
|
||||
context 'logged in as a non-Administrator' do
|
||||
let_it_be(:current_user) { create(:user) }
|
||||
let_it_be(:user) { create(:user) }
|
||||
let_it_be(:token) { create(:personal_access_token, user: current_user)}
|
||||
let_it_be(:other_token) { create(:personal_access_token, user: user) }
|
||||
|
||||
it 'returns all PATs belonging to the signed-in user' do
|
||||
get api(path, current_user, personal_access_token: token)
|
||||
|
||||
expect(response).to have_gitlab_http_status(:ok)
|
||||
expect(json_response.count).to eq(1)
|
||||
expect(json_response.map { |r| r['user_id'] }.uniq).to contain_exactly(current_user.id)
|
||||
end
|
||||
|
||||
context 'filtered with user_id parameter' do
|
||||
it 'returns PATs belonging to the specific user' do
|
||||
get api(path, current_user, personal_access_token: token), params: { user_id: current_user.id }
|
||||
|
||||
expect(response).to have_gitlab_http_status(:ok)
|
||||
expect(json_response.count).to eq(1)
|
||||
expect(json_response.map { |r| r['user_id'] }.uniq).to contain_exactly(current_user.id)
|
||||
end
|
||||
|
||||
it 'is unauthorized if filtered by a user other than current_user' do
|
||||
get api(path, current_user, personal_access_token: token), params: { user_id: user.id }
|
||||
|
||||
expect(response).to have_gitlab_http_status(:unauthorized)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'not authenticated' do
|
||||
it 'is forbidden' do
|
||||
get api(path)
|
||||
|
||||
expect(response).to have_gitlab_http_status(:unauthorized)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'DELETE /personal_access_tokens/:id' do
|
||||
let(:path) { "/personal_access_tokens/#{token1.id}" }
|
||||
|
||||
context 'when current_user is an administrator', :enable_admin_mode do
|
||||
let_it_be(:admin_user) { create(:admin) }
|
||||
let_it_be(:admin_token) { create(:personal_access_token, user: admin_user) }
|
||||
let_it_be(:admin_path) { "/personal_access_tokens/#{admin_token.id}" }
|
||||
|
||||
it 'revokes a different users token' do
|
||||
delete api(path, admin_user)
|
||||
|
||||
expect(response).to have_gitlab_http_status(:no_content)
|
||||
expect(token1.reload.revoked?).to be true
|
||||
end
|
||||
|
||||
it 'revokes their own token' do
|
||||
delete api(admin_path, admin_user)
|
||||
|
||||
expect(response).to have_gitlab_http_status(:no_content)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when current_user is not an administrator' do
|
||||
let_it_be(:user_token) { create(:personal_access_token, user: current_user) }
|
||||
let_it_be(:user_token_path) { "/personal_access_tokens/#{user_token.id}" }
|
||||
|
||||
it 'fails revokes a different users token' do
|
||||
delete api(path, current_user)
|
||||
|
||||
expect(response).to have_gitlab_http_status(:bad_request)
|
||||
end
|
||||
|
||||
it 'revokes their own token' do
|
||||
delete api(user_token_path, current_user)
|
||||
|
||||
expect(response).to have_gitlab_http_status(:no_content)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -117,15 +117,10 @@ RSpec.shared_examples 'discussions API' do |parent_type, noteable_type, id_name,
|
|||
expect(response).to have_gitlab_http_status(:unauthorized)
|
||||
end
|
||||
|
||||
it 'tracks a Notes::CreateService event' do
|
||||
expect(Gitlab::Tracking).to receive(:event) do |category, action, data|
|
||||
expect(category).to eq('Notes::CreateService')
|
||||
expect(action).to eq('execute')
|
||||
expect(data[:label]).to eq('note')
|
||||
expect(data[:value]).to be_an(Integer)
|
||||
end
|
||||
|
||||
it 'tracks a Notes::CreateService event', :snowplow do
|
||||
post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/discussions", user), params: { body: 'hi!' }
|
||||
|
||||
expect_snowplow_event(category: 'Notes::CreateService', action: 'execute', label: 'note', value: anything)
|
||||
end
|
||||
|
||||
context 'with notes_create_service_tracking feature flag disabled' do
|
||||
|
|
|
@ -0,0 +1,94 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
RSpec.shared_examples 'multiple and scoped issue boards' do |route_definition|
|
||||
let(:root_url) { route_definition.gsub(":id", board_parent.id.to_s) }
|
||||
|
||||
context 'multiple issue boards' do
|
||||
before do
|
||||
board_parent.add_reporter(user)
|
||||
stub_licensed_features(multiple_group_issue_boards: true)
|
||||
end
|
||||
|
||||
describe "POST #{route_definition}" do
|
||||
it 'creates a board' do
|
||||
post api(root_url, user), params: { name: "new board" }
|
||||
|
||||
expect(response).to have_gitlab_http_status(:created)
|
||||
|
||||
expect(response).to match_response_schema('public_api/v4/board', dir: "ee")
|
||||
end
|
||||
end
|
||||
|
||||
describe "PUT #{route_definition}/:board_id" do
|
||||
let(:url) { "#{root_url}/#{board.id}" }
|
||||
|
||||
it 'updates a board' do
|
||||
put api(url, user), params: { name: 'new name', weight: 4, labels: 'foo, bar' }
|
||||
|
||||
expect(response).to have_gitlab_http_status(:ok)
|
||||
|
||||
expect(response).to match_response_schema('public_api/v4/board', dir: "ee")
|
||||
|
||||
board.reload
|
||||
|
||||
expect(board.name).to eq('new name')
|
||||
expect(board.weight).to eq(4)
|
||||
expect(board.labels.map(&:title)).to contain_exactly('foo', 'bar')
|
||||
end
|
||||
|
||||
it 'does not remove missing attributes from the board' do
|
||||
expect { put api(url, user), params: { name: 'new name' } }
|
||||
.to not_change { board.reload.assignee }
|
||||
.and not_change { board.reload.milestone }
|
||||
.and not_change { board.reload.weight }
|
||||
.and not_change { board.reload.labels.map(&:title).sort }
|
||||
|
||||
expect(response).to have_gitlab_http_status(:ok)
|
||||
expect(response).to match_response_schema('public_api/v4/board', dir: "ee")
|
||||
end
|
||||
|
||||
it 'allows removing optional attributes' do
|
||||
put api(url, user), params: { name: 'new name', assignee_id: nil, milestone_id: nil, weight: nil, labels: nil }
|
||||
|
||||
expect(response).to have_gitlab_http_status(:ok)
|
||||
expect(response).to match_response_schema('public_api/v4/board', dir: "ee")
|
||||
|
||||
board.reload
|
||||
|
||||
expect(board.name).to eq('new name')
|
||||
expect(board.assignee).to be_nil
|
||||
expect(board.milestone).to be_nil
|
||||
expect(board.weight).to be_nil
|
||||
expect(board.labels).to be_empty
|
||||
end
|
||||
end
|
||||
|
||||
describe "DELETE #{route_definition}/:board_id" do
|
||||
let(:url) { "#{root_url}/#{board.id}" }
|
||||
|
||||
it 'deletes a board' do
|
||||
delete api(url, user)
|
||||
|
||||
expect(response).to have_gitlab_http_status(:no_content)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'with the scoped_issue_board-feature available' do
|
||||
it 'returns the milestone when the `scoped_issue_board` feature is enabled' do
|
||||
stub_licensed_features(scoped_issue_board: true)
|
||||
|
||||
get api(root_url, user)
|
||||
|
||||
expect(json_response.first["milestone"]).not_to be_nil
|
||||
end
|
||||
|
||||
it 'hides the milestone when the `scoped_issue_board` feature is disabled' do
|
||||
stub_licensed_features(scoped_issue_board: false)
|
||||
|
||||
get api(root_url, user)
|
||||
|
||||
expect(json_response.first["milestone"]).to be_nil
|
||||
end
|
||||
end
|
||||
end
|
Loading…
Reference in a new issue