2019-04-15 06:17:05 -04:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
2018-05-22 11:22:51 -04:00
|
|
|
require 'spec_helper'
|
2015-07-18 01:54:04 -04:00
|
|
|
|
2020-06-03 14:08:28 -04:00
|
|
|
RSpec.describe Projects::IssuesController do
|
2019-06-19 04:56:17 -04:00
|
|
|
include ProjectForksHelper
|
2020-04-21 11:21:10 -04:00
|
|
|
include_context 'includes Spam constants'
|
2019-06-19 04:56:17 -04:00
|
|
|
|
2017-08-09 09:41:45 -04:00
|
|
|
let(:project) { create(:project) }
|
2016-02-26 03:55:43 -05:00
|
|
|
let(:user) { create(:user) }
|
|
|
|
let(:issue) { create(:issue, project: project) }
|
2015-07-18 01:54:04 -04:00
|
|
|
|
2016-02-26 03:55:43 -05:00
|
|
|
describe "GET #index" do
|
2016-08-01 19:59:44 -04:00
|
|
|
context 'external issue tracker' do
|
2017-06-13 04:25:25 -04:00
|
|
|
before do
|
|
|
|
sign_in(user)
|
|
|
|
project.add_developer(user)
|
|
|
|
create(:jira_service, project: project)
|
2017-07-17 14:56:35 -04:00
|
|
|
end
|
|
|
|
|
2017-06-13 04:25:25 -04:00
|
|
|
context 'when GitLab issues disabled' do
|
|
|
|
it 'returns 404 status' do
|
|
|
|
project.issues_enabled = false
|
|
|
|
project.save!
|
2015-07-18 01:54:04 -04:00
|
|
|
|
2018-12-17 17:52:17 -05:00
|
|
|
get :index, params: { namespace_id: project.namespace, project_id: project }
|
2015-07-18 01:54:04 -04:00
|
|
|
|
2020-01-28 07:08:44 -05:00
|
|
|
expect(response).to have_gitlab_http_status(:not_found)
|
2017-06-13 04:25:25 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'when GitLab issues enabled' do
|
|
|
|
it 'renders the "index" template' do
|
2018-12-17 17:52:17 -05:00
|
|
|
get :index, params: { namespace_id: project.namespace, project_id: project }
|
2017-06-13 04:25:25 -04:00
|
|
|
|
2020-01-28 07:08:44 -05:00
|
|
|
expect(response).to have_gitlab_http_status(:ok)
|
2017-06-13 04:25:25 -04:00
|
|
|
expect(response).to render_template(:index)
|
|
|
|
end
|
2016-08-01 19:59:44 -04:00
|
|
|
end
|
2019-09-16 05:06:25 -04:00
|
|
|
|
|
|
|
context 'when project has moved' do
|
|
|
|
let(:new_project) { create(:project) }
|
|
|
|
let(:issue) { create(:issue, project: new_project) }
|
|
|
|
|
|
|
|
before do
|
|
|
|
project.route.destroy
|
|
|
|
new_project.redirect_routes.create!(path: project.full_path)
|
|
|
|
new_project.add_developer(user)
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'redirects to the new issue tracker from the old one' do
|
|
|
|
get :index, params: { namespace_id: project.namespace, project_id: project }
|
|
|
|
|
|
|
|
expect(response).to redirect_to(project_issues_path(new_project))
|
2020-01-28 07:08:44 -05:00
|
|
|
expect(response).to have_gitlab_http_status(:found)
|
2019-09-16 05:06:25 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
it 'redirects from an old issue correctly' do
|
|
|
|
get :show, params: { namespace_id: project.namespace, project_id: project, id: issue }
|
|
|
|
|
|
|
|
expect(response).to redirect_to(project_issue_path(new_project, issue))
|
2020-01-28 07:08:44 -05:00
|
|
|
expect(response).to have_gitlab_http_status(:found)
|
2019-09-16 05:06:25 -04:00
|
|
|
end
|
|
|
|
end
|
2015-07-18 01:54:04 -04:00
|
|
|
end
|
|
|
|
|
2016-08-01 19:59:44 -04:00
|
|
|
context 'internal issue tracker' do
|
|
|
|
before do
|
|
|
|
sign_in(user)
|
2017-12-22 03:18:28 -05:00
|
|
|
project.add_developer(user)
|
2016-08-01 19:59:44 -04:00
|
|
|
end
|
2015-09-17 09:56:16 -04:00
|
|
|
|
2017-01-23 15:40:25 -05:00
|
|
|
it_behaves_like "issuables list meta-data", :issue
|
|
|
|
|
2019-01-06 19:00:48 -05:00
|
|
|
it_behaves_like 'set sort order from user preference' do
|
|
|
|
let(:sorting_param) { 'updated_asc' }
|
|
|
|
end
|
2018-12-12 11:15:58 -05:00
|
|
|
|
2016-08-01 19:59:44 -04:00
|
|
|
it "returns index" do
|
2018-12-17 17:52:17 -05:00
|
|
|
get :index, params: { namespace_id: project.namespace, project_id: project }
|
2015-09-17 09:56:16 -04:00
|
|
|
|
2020-01-28 07:08:44 -05:00
|
|
|
expect(response).to have_gitlab_http_status(:ok)
|
2016-08-01 19:59:44 -04:00
|
|
|
end
|
2015-07-18 01:54:04 -04:00
|
|
|
|
2016-07-25 14:16:19 -04:00
|
|
|
it "returns 301 if request path doesn't match project path" do
|
2018-12-17 17:52:17 -05:00
|
|
|
get :index, params: { namespace_id: project.namespace, project_id: project.path.upcase }
|
2016-08-01 19:59:44 -04:00
|
|
|
|
2017-06-29 13:06:35 -04:00
|
|
|
expect(response).to redirect_to(project_issues_path(project))
|
2016-08-01 19:59:44 -04:00
|
|
|
end
|
2015-07-18 01:54:04 -04:00
|
|
|
|
2016-08-01 19:59:44 -04:00
|
|
|
it "returns 404 when issues are disabled" do
|
|
|
|
project.issues_enabled = false
|
2017-06-13 04:25:25 -04:00
|
|
|
project.save!
|
2016-08-01 19:59:44 -04:00
|
|
|
|
2018-12-17 17:52:17 -05:00
|
|
|
get :index, params: { namespace_id: project.namespace, project_id: project }
|
2020-01-28 07:08:44 -05:00
|
|
|
expect(response).to have_gitlab_http_status(:not_found)
|
2016-08-01 21:23:12 -04:00
|
|
|
end
|
|
|
|
end
|
2016-12-20 13:52:09 -05:00
|
|
|
|
2019-09-03 13:45:00 -04:00
|
|
|
it_behaves_like 'paginated collection' do
|
2016-12-21 10:02:05 -05:00
|
|
|
let!(:issue_list) { create_list(:issue, 2, project: project) }
|
2019-09-03 13:45:00 -04:00
|
|
|
let(:collection) { project.issues }
|
|
|
|
let(:params) do
|
|
|
|
{
|
|
|
|
namespace_id: project.namespace.to_param,
|
|
|
|
project_id: project,
|
|
|
|
state: 'opened'
|
|
|
|
}
|
|
|
|
end
|
2016-12-20 13:52:09 -05:00
|
|
|
|
|
|
|
before do
|
|
|
|
sign_in(user)
|
2017-12-22 03:18:28 -05:00
|
|
|
project.add_developer(user)
|
2016-12-21 10:02:05 -05:00
|
|
|
allow(Kaminari.config).to receive(:default_per_page).and_return(1)
|
2016-12-20 13:52:09 -05:00
|
|
|
end
|
|
|
|
|
2018-01-29 10:22:58 -05:00
|
|
|
it 'does not use pagination if disabled' do
|
|
|
|
allow(controller).to receive(:pagination_disabled?).and_return(true)
|
|
|
|
|
2019-09-03 13:45:00 -04:00
|
|
|
get :index, params: params.merge(page: last_page + 1)
|
2018-01-29 10:22:58 -05:00
|
|
|
|
2020-01-28 07:08:44 -05:00
|
|
|
expect(response).to have_gitlab_http_status(:ok)
|
2018-01-29 10:22:58 -05:00
|
|
|
expect(assigns(:issues).size).to eq(2)
|
|
|
|
end
|
2016-12-20 13:52:09 -05:00
|
|
|
end
|
2019-04-09 11:38:58 -04:00
|
|
|
|
2019-05-21 18:46:12 -04:00
|
|
|
context 'with relative_position sorting' do
|
|
|
|
let!(:issue_list) { create_list(:issue, 2, project: project) }
|
|
|
|
|
|
|
|
before do
|
|
|
|
sign_in(user)
|
|
|
|
project.add_developer(user)
|
|
|
|
allow(Kaminari.config).to receive(:default_per_page).and_return(1)
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'overrides the number allowed on the page' do
|
|
|
|
get :index,
|
|
|
|
params: {
|
|
|
|
namespace_id: project.namespace.to_param,
|
|
|
|
project_id: project,
|
|
|
|
sort: 'relative_position'
|
|
|
|
}
|
|
|
|
|
|
|
|
expect(assigns(:issues).count).to eq 2
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'allows the default number on the page' do
|
|
|
|
get :index,
|
|
|
|
params: {
|
|
|
|
namespace_id: project.namespace.to_param,
|
|
|
|
project_id: project
|
|
|
|
}
|
|
|
|
|
|
|
|
expect(assigns(:issues).count).to eq 1
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2019-04-09 11:38:58 -04:00
|
|
|
context 'external authorization' do
|
|
|
|
before do
|
|
|
|
sign_in user
|
|
|
|
project.add_developer(user)
|
|
|
|
end
|
|
|
|
|
|
|
|
it_behaves_like 'unauthorized when external service denies access' do
|
|
|
|
subject { get :index, params: { namespace_id: project.namespace, project_id: project } }
|
|
|
|
end
|
|
|
|
end
|
2016-08-01 21:23:12 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
describe 'GET #new' do
|
2017-03-06 15:18:39 -05:00
|
|
|
it 'redirects to signin if not logged in' do
|
2018-12-17 17:52:17 -05:00
|
|
|
get :new, params: { namespace_id: project.namespace, project_id: project }
|
2017-03-06 15:18:39 -05:00
|
|
|
|
2019-12-12 07:07:33 -05:00
|
|
|
expect(flash[:alert]).to eq I18n.t('devise.failure.unauthenticated')
|
2017-03-06 15:18:39 -05:00
|
|
|
expect(response).to redirect_to(new_user_session_path)
|
|
|
|
end
|
|
|
|
|
2016-10-26 17:21:50 -04:00
|
|
|
context 'internal issue tracker' do
|
|
|
|
before do
|
|
|
|
sign_in(user)
|
2017-12-22 03:18:28 -05:00
|
|
|
project.add_developer(user)
|
2016-10-26 17:21:50 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
it 'builds a new issue' do
|
2018-12-17 17:52:17 -05:00
|
|
|
get :new, params: { namespace_id: project.namespace, project_id: project }
|
2016-10-26 17:21:50 -04:00
|
|
|
|
|
|
|
expect(assigns(:issue)).to be_a_new(Issue)
|
|
|
|
end
|
|
|
|
|
2020-05-08 05:09:39 -04:00
|
|
|
where(:conf_value, :conf_result) do
|
|
|
|
[
|
|
|
|
[true, true],
|
|
|
|
['true', true],
|
|
|
|
['TRUE', true],
|
|
|
|
[false, false],
|
|
|
|
['false', false],
|
|
|
|
['FALSE', false]
|
|
|
|
]
|
|
|
|
end
|
|
|
|
|
|
|
|
with_them do
|
|
|
|
it 'sets the confidential flag to the expected value' do
|
|
|
|
get :new, params: {
|
|
|
|
namespace_id: project.namespace,
|
|
|
|
project_id: project,
|
|
|
|
issue: {
|
|
|
|
confidential: conf_value
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
assigned_issue = assigns(:issue)
|
|
|
|
expect(assigned_issue).to be_a_new(Issue)
|
|
|
|
expect(assigned_issue.confidential).to eq conf_result
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2016-10-26 17:21:50 -04:00
|
|
|
it 'fills in an issue for a merge request' do
|
2017-01-25 16:44:33 -05:00
|
|
|
project_with_repository = create(:project, :repository)
|
2017-12-22 03:18:28 -05:00
|
|
|
project_with_repository.add_developer(user)
|
2016-10-26 17:21:50 -04:00
|
|
|
mr = create(:merge_request_with_diff_notes, source_project: project_with_repository)
|
|
|
|
|
2018-12-17 17:52:17 -05:00
|
|
|
get :new, params: { namespace_id: project_with_repository.namespace, project_id: project_with_repository, merge_request_to_resolve_discussions_of: mr.iid }
|
2016-10-26 17:21:50 -04:00
|
|
|
|
|
|
|
expect(assigns(:issue).title).not_to be_empty
|
|
|
|
expect(assigns(:issue).description).not_to be_empty
|
|
|
|
end
|
2016-12-22 07:31:12 -05:00
|
|
|
|
|
|
|
it 'fills in an issue for a discussion' do
|
|
|
|
note = create(:note_on_merge_request, project: project)
|
|
|
|
|
2018-12-17 17:52:17 -05:00
|
|
|
get :new, params: { namespace_id: project.namespace.path, project_id: project, merge_request_to_resolve_discussions_of: note.noteable.iid, discussion_to_resolve: note.discussion_id }
|
2016-12-22 07:31:12 -05:00
|
|
|
|
|
|
|
expect(assigns(:issue).title).not_to be_empty
|
|
|
|
expect(assigns(:issue).description).not_to be_empty
|
|
|
|
end
|
2016-10-26 17:21:50 -04:00
|
|
|
end
|
|
|
|
|
2016-08-01 21:23:12 -04:00
|
|
|
context 'external issue tracker' do
|
2017-07-17 14:56:35 -04:00
|
|
|
let!(:service) do
|
2020-06-22 08:08:47 -04:00
|
|
|
create(:custom_issue_tracker_service, project: project, new_issue_url: 'http://test.com')
|
2017-07-17 14:56:35 -04:00
|
|
|
end
|
|
|
|
|
2017-03-06 15:18:39 -05:00
|
|
|
before do
|
|
|
|
sign_in(user)
|
2017-12-22 03:18:28 -05:00
|
|
|
project.add_developer(user)
|
2017-06-13 04:25:25 -04:00
|
|
|
|
|
|
|
external = double
|
|
|
|
allow(project).to receive(:external_issue_tracker).and_return(external)
|
2017-03-06 15:18:39 -05:00
|
|
|
end
|
|
|
|
|
2017-06-13 04:25:25 -04:00
|
|
|
context 'when GitLab issues disabled' do
|
|
|
|
it 'returns 404 status' do
|
|
|
|
project.issues_enabled = false
|
|
|
|
project.save!
|
2016-08-01 21:23:12 -04:00
|
|
|
|
2018-12-17 17:52:17 -05:00
|
|
|
get :new, params: { namespace_id: project.namespace, project_id: project }
|
2017-06-13 04:25:25 -04:00
|
|
|
|
2020-01-28 07:08:44 -05:00
|
|
|
expect(response).to have_gitlab_http_status(:not_found)
|
2017-06-13 04:25:25 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'when GitLab issues enabled' do
|
|
|
|
it 'renders the "new" template' do
|
2018-12-17 17:52:17 -05:00
|
|
|
get :new, params: { namespace_id: project.namespace, project_id: project }
|
2016-08-01 21:23:12 -04:00
|
|
|
|
2020-01-28 07:08:44 -05:00
|
|
|
expect(response).to have_gitlab_http_status(:ok)
|
2017-06-13 04:25:25 -04:00
|
|
|
expect(response).to render_template(:new)
|
|
|
|
end
|
2016-08-01 19:59:44 -04:00
|
|
|
end
|
2015-07-18 01:54:04 -04:00
|
|
|
end
|
2016-03-17 15:38:51 -04:00
|
|
|
end
|
|
|
|
|
2020-05-04 02:10:10 -04:00
|
|
|
describe '#related_branches' do
|
|
|
|
subject { get :related_branches, params: params, format: :json }
|
|
|
|
|
|
|
|
before do
|
|
|
|
sign_in(user)
|
|
|
|
project.add_developer(developer)
|
|
|
|
end
|
|
|
|
|
|
|
|
let(:developer) { user }
|
|
|
|
let(:params) do
|
|
|
|
{
|
|
|
|
namespace_id: project.namespace,
|
|
|
|
project_id: project,
|
|
|
|
id: issue.iid
|
|
|
|
}
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'the current user cannot download code' do
|
|
|
|
it 'prevents access' do
|
|
|
|
allow(controller).to receive(:can?).with(any_args).and_return(true)
|
|
|
|
allow(controller).to receive(:can?).with(user, :download_code, project).and_return(false)
|
|
|
|
|
|
|
|
subject
|
|
|
|
|
|
|
|
expect(response).to have_gitlab_http_status(:not_found)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'there are no related branches' do
|
|
|
|
it 'assigns empty arrays', :aggregate_failures do
|
|
|
|
subject
|
|
|
|
|
|
|
|
expect(response).to have_gitlab_http_status(:ok)
|
|
|
|
expect(assigns(:related_branches)).to be_empty
|
|
|
|
expect(response).to render_template('projects/issues/_related_branches')
|
|
|
|
expect(json_response).to eq('html' => '')
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'there are related branches' do
|
|
|
|
let(:missing_branch) { "#{issue.to_branch_name}-missing" }
|
|
|
|
let(:unreadable_branch) { "#{issue.to_branch_name}-unreadable" }
|
|
|
|
let(:pipeline) { build(:ci_pipeline, :success, project: project) }
|
|
|
|
let(:master_branch) { 'master' }
|
|
|
|
|
|
|
|
let(:related_branches) do
|
|
|
|
[
|
|
|
|
branch_info(issue.to_branch_name, pipeline.detailed_status(user)),
|
|
|
|
branch_info(missing_branch, nil),
|
|
|
|
branch_info(unreadable_branch, nil)
|
|
|
|
]
|
|
|
|
end
|
|
|
|
|
|
|
|
def branch_info(name, status)
|
|
|
|
{
|
|
|
|
name: name,
|
|
|
|
link: controller.project_compare_path(project, from: master_branch, to: name),
|
|
|
|
pipeline_status: status
|
|
|
|
}
|
|
|
|
end
|
|
|
|
|
|
|
|
before do
|
2020-06-01 20:08:07 -04:00
|
|
|
allow(controller).to receive(:find_routable!).and_return(project)
|
2020-05-04 02:10:10 -04:00
|
|
|
allow(project).to receive(:default_branch).and_return(master_branch)
|
|
|
|
allow_next_instance_of(Issues::RelatedBranchesService) do |service|
|
|
|
|
allow(service).to receive(:execute).and_return(related_branches)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'finds and assigns the appropriate branch information', :aggregate_failures do
|
|
|
|
subject
|
|
|
|
|
|
|
|
expect(response).to have_gitlab_http_status(:ok)
|
|
|
|
expect(assigns(:related_branches)).to contain_exactly(
|
|
|
|
branch_info(issue.to_branch_name, an_instance_of(Gitlab::Ci::Status::Success)),
|
|
|
|
branch_info(missing_branch, be_nil),
|
|
|
|
branch_info(unreadable_branch, be_nil)
|
|
|
|
)
|
|
|
|
expect(response).to render_template('projects/issues/_related_branches')
|
|
|
|
expect(json_response).to match('html' => String)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2019-07-24 21:35:45 -04:00
|
|
|
# This spec runs as a request-style spec in order to invoke the
|
|
|
|
# Rails router. A controller-style spec matches the wrong route, and
|
|
|
|
# session['user_return_to'] becomes incorrect.
|
|
|
|
describe 'Redirect after sign in', type: :request do
|
2017-05-19 14:35:08 -04:00
|
|
|
context 'with an AJAX request' do
|
|
|
|
it 'does not store the visited URL' do
|
2019-07-24 21:35:45 -04:00
|
|
|
get project_issue_path(project, issue), xhr: true
|
2017-05-19 14:35:08 -04:00
|
|
|
|
|
|
|
expect(session['user_return_to']).to be_blank
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'without an AJAX request' do
|
|
|
|
it 'stores the visited URL' do
|
2019-07-24 21:35:45 -04:00
|
|
|
get project_issue_path(project, issue)
|
2017-05-19 14:35:08 -04:00
|
|
|
|
2019-07-24 21:35:45 -04:00
|
|
|
expect(session['user_return_to']).to eq(project_issue_path(project, issue))
|
2017-05-19 14:35:08 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2017-08-14 03:26:19 -04:00
|
|
|
describe 'POST #move' do
|
|
|
|
before do
|
|
|
|
sign_in(user)
|
|
|
|
project.add_developer(user)
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'when moving issue to another private project' do
|
|
|
|
let(:another_project) { create(:project, :private) }
|
|
|
|
|
|
|
|
context 'when user has access to move issue' do
|
|
|
|
before do
|
|
|
|
another_project.add_reporter(user)
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'moves issue to another project' do
|
|
|
|
move_issue
|
|
|
|
|
2017-10-19 14:28:19 -04:00
|
|
|
expect(response).to have_gitlab_http_status :ok
|
2017-08-14 03:26:19 -04:00
|
|
|
expect(another_project.issues).not_to be_empty
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'when user does not have access to move issue' do
|
|
|
|
it 'responds with 404' do
|
|
|
|
move_issue
|
|
|
|
|
2017-10-19 14:28:19 -04:00
|
|
|
expect(response).to have_gitlab_http_status :not_found
|
2017-08-14 03:26:19 -04:00
|
|
|
end
|
|
|
|
end
|
2017-02-14 14:07:11 -05:00
|
|
|
|
2016-04-30 15:14:40 -04:00
|
|
|
def move_issue
|
2017-08-14 03:26:19 -04:00
|
|
|
post :move,
|
2018-12-17 17:52:17 -05:00
|
|
|
params: {
|
|
|
|
namespace_id: project.namespace.to_param,
|
|
|
|
project_id: project,
|
|
|
|
id: issue.iid,
|
|
|
|
move_to_project_id: another_project.id
|
|
|
|
},
|
|
|
|
format: :json
|
2016-04-30 15:14:40 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2019-05-31 21:19:08 -04:00
|
|
|
describe 'PUT #reorder' do
|
|
|
|
let(:group) { create(:group, projects: [project]) }
|
|
|
|
let!(:issue1) { create(:issue, project: project, relative_position: 10) }
|
|
|
|
let!(:issue2) { create(:issue, project: project, relative_position: 20) }
|
|
|
|
let!(:issue3) { create(:issue, project: project, relative_position: 30) }
|
|
|
|
|
|
|
|
before do
|
|
|
|
sign_in(user)
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'when user has access' do
|
|
|
|
before do
|
|
|
|
project.add_developer(user)
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'with valid params' do
|
|
|
|
it 'reorders issues and returns a successful 200 response' do
|
|
|
|
reorder_issue(issue1,
|
|
|
|
move_after_id: issue2.id,
|
|
|
|
move_before_id: issue3.id,
|
|
|
|
group_full_path: group.full_path)
|
|
|
|
|
|
|
|
[issue1, issue2, issue3].map(&:reload)
|
|
|
|
|
2020-01-28 07:08:44 -05:00
|
|
|
expect(response).to have_gitlab_http_status(:ok)
|
2019-05-31 21:19:08 -04:00
|
|
|
expect(issue1.relative_position)
|
|
|
|
.to be_between(issue2.relative_position, issue3.relative_position)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'with invalid params' do
|
|
|
|
it 'returns a unprocessable entity 422 response for invalid move ids' do
|
2020-04-01 11:07:45 -04:00
|
|
|
reorder_issue(issue1, move_after_id: 99, move_before_id: non_existing_record_id)
|
2019-05-31 21:19:08 -04:00
|
|
|
|
2020-01-28 07:08:44 -05:00
|
|
|
expect(response).to have_gitlab_http_status(:unprocessable_entity)
|
2019-05-31 21:19:08 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
it 'returns a not found 404 response for invalid issue id' do
|
2020-04-01 11:07:45 -04:00
|
|
|
reorder_issue(object_double(issue1, iid: non_existing_record_iid),
|
2019-05-31 21:19:08 -04:00
|
|
|
move_after_id: issue2.id,
|
|
|
|
move_before_id: issue3.id)
|
|
|
|
|
2020-01-28 07:08:44 -05:00
|
|
|
expect(response).to have_gitlab_http_status(:not_found)
|
2019-05-31 21:19:08 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
it 'returns a unprocessable entity 422 response for issues not in group' do
|
|
|
|
another_group = create(:group)
|
|
|
|
|
|
|
|
reorder_issue(issue1,
|
|
|
|
move_after_id: issue2.id,
|
|
|
|
move_before_id: issue3.id,
|
|
|
|
group_full_path: another_group.full_path)
|
|
|
|
|
2020-01-28 07:08:44 -05:00
|
|
|
expect(response).to have_gitlab_http_status(:unprocessable_entity)
|
2019-05-31 21:19:08 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'with unauthorized user' do
|
|
|
|
before do
|
|
|
|
project.add_guest(user)
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'responds with 404' do
|
|
|
|
reorder_issue(issue1, move_after_id: issue2.id, move_before_id: issue3.id)
|
|
|
|
|
|
|
|
expect(response).to have_gitlab_http_status(:not_found)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def reorder_issue(issue, move_after_id: nil, move_before_id: nil, group_full_path: nil)
|
|
|
|
put :reorder,
|
|
|
|
params: {
|
|
|
|
namespace_id: project.namespace.to_param,
|
|
|
|
project_id: project,
|
|
|
|
id: issue.iid,
|
|
|
|
move_after_id: move_after_id,
|
|
|
|
move_before_id: move_before_id,
|
|
|
|
group_full_path: group_full_path
|
|
|
|
},
|
|
|
|
format: :json
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2017-11-01 13:35:14 -04:00
|
|
|
describe 'PUT #update' do
|
|
|
|
subject do
|
|
|
|
put :update,
|
2018-12-17 17:52:17 -05:00
|
|
|
params: {
|
|
|
|
namespace_id: project.namespace,
|
|
|
|
project_id: project,
|
|
|
|
id: issue.to_param,
|
|
|
|
issue: { title: 'New title' }
|
|
|
|
},
|
|
|
|
format: :json
|
2017-11-01 13:35:14 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
before do
|
|
|
|
sign_in(user)
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'when user has access to update issue' do
|
|
|
|
before do
|
2019-09-24 23:06:21 -04:00
|
|
|
project.update!(visibility_level: Gitlab::VisibilityLevel::PUBLIC)
|
2017-11-01 13:35:14 -04:00
|
|
|
project.add_developer(user)
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'updates the issue' do
|
|
|
|
subject
|
|
|
|
|
2020-01-28 07:08:44 -05:00
|
|
|
expect(response).to have_gitlab_http_status(:ok)
|
2017-11-01 13:35:14 -04:00
|
|
|
expect(issue.reload.title).to eq('New title')
|
|
|
|
end
|
2017-12-08 07:26:39 -05:00
|
|
|
|
2020-04-21 11:21:10 -04:00
|
|
|
context 'when the SpamVerdictService disallows' do
|
2017-12-08 07:26:39 -05:00
|
|
|
before do
|
|
|
|
stub_application_setting(recaptcha_enabled: true)
|
2020-04-21 11:21:10 -04:00
|
|
|
expect_next_instance_of(Spam::SpamVerdictService) do |verdict_service|
|
2020-05-25 23:08:02 -04:00
|
|
|
expect(verdict_service).to receive(:execute).and_return(CONDITIONAL_ALLOW)
|
2019-09-24 23:06:21 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'when allow_possible_spam feature flag is false' do
|
|
|
|
before do
|
|
|
|
stub_feature_flags(allow_possible_spam: false)
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'renders json with recaptcha_html' do
|
|
|
|
subject
|
|
|
|
|
|
|
|
expect(json_response).to have_key('recaptcha_html')
|
|
|
|
end
|
2017-12-08 07:26:39 -05:00
|
|
|
end
|
|
|
|
|
2019-09-24 23:06:21 -04:00
|
|
|
context 'when allow_possible_spam feature flag is true' do
|
|
|
|
it 'updates the issue' do
|
|
|
|
subject
|
2017-12-08 07:26:39 -05:00
|
|
|
|
2020-01-28 07:08:44 -05:00
|
|
|
expect(response).to have_gitlab_http_status(:ok)
|
2019-09-24 23:06:21 -04:00
|
|
|
expect(issue.reload.title).to eq('New title')
|
|
|
|
end
|
2017-12-08 07:26:39 -05:00
|
|
|
end
|
|
|
|
end
|
2017-11-01 13:35:14 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
context 'when user does not have access to update issue' do
|
|
|
|
before do
|
|
|
|
project.add_guest(user)
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'responds with 404' do
|
|
|
|
subject
|
|
|
|
|
2020-01-28 07:08:44 -05:00
|
|
|
expect(response).to have_gitlab_http_status(:not_found)
|
2017-11-01 13:35:14 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2018-01-11 11:22:00 -05:00
|
|
|
describe 'GET #realtime_changes' do
|
|
|
|
def go(id:)
|
|
|
|
get :realtime_changes,
|
2018-12-17 17:52:17 -05:00
|
|
|
params: {
|
|
|
|
namespace_id: project.namespace.to_param,
|
|
|
|
project_id: project,
|
|
|
|
id: id
|
|
|
|
}
|
2018-01-11 11:22:00 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
context 'when an issue was edited' do
|
|
|
|
before do
|
|
|
|
project.add_developer(user)
|
|
|
|
|
|
|
|
issue.update!(last_edited_by: user, last_edited_at: issue.created_at + 1.minute)
|
|
|
|
|
|
|
|
sign_in(user)
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'returns last edited time' do
|
|
|
|
go(id: issue.iid)
|
|
|
|
|
2019-07-16 04:03:49 -04:00
|
|
|
expect(json_response).to include('updated_at')
|
|
|
|
expect(json_response['updated_at']).to eq(issue.last_edited_at.to_time.iso8601)
|
2018-01-11 11:22:00 -05:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'when an issue was edited by a deleted user' do
|
|
|
|
let(:deleted_user) { create(:user) }
|
|
|
|
|
|
|
|
before do
|
|
|
|
project.add_developer(user)
|
|
|
|
|
2020-05-13 20:07:47 -04:00
|
|
|
issue.update!(last_edited_by: deleted_user, last_edited_at: Time.current)
|
2018-01-11 11:22:00 -05:00
|
|
|
|
|
|
|
deleted_user.destroy
|
|
|
|
sign_in(user)
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'returns 200' do
|
|
|
|
go(id: issue.iid)
|
|
|
|
|
2020-01-28 07:08:44 -05:00
|
|
|
expect(response).to have_gitlab_http_status(:ok)
|
2018-01-11 11:22:00 -05:00
|
|
|
end
|
|
|
|
end
|
2019-01-23 16:58:46 -05:00
|
|
|
|
|
|
|
context 'when getting the changes' do
|
|
|
|
before do
|
|
|
|
project.add_developer(user)
|
|
|
|
|
|
|
|
sign_in(user)
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'returns the necessary data' do
|
|
|
|
go(id: issue.iid)
|
|
|
|
|
2019-07-16 04:03:49 -04:00
|
|
|
expect(json_response).to include('title_text', 'description', 'description_text')
|
|
|
|
expect(json_response).to include('task_status', 'lock_version')
|
2019-01-23 16:58:46 -05:00
|
|
|
end
|
|
|
|
end
|
2018-01-11 11:22:00 -05:00
|
|
|
end
|
|
|
|
|
2016-03-17 15:38:51 -04:00
|
|
|
describe 'Confidential Issues' do
|
2016-03-19 10:35:24 -04:00
|
|
|
let(:project) { create(:project_empty_repo, :public) }
|
2016-03-17 15:38:51 -04:00
|
|
|
let(:assignee) { create(:assignee) }
|
|
|
|
let(:author) { create(:user) }
|
|
|
|
let(:non_member) { create(:user) }
|
|
|
|
let(:member) { create(:user) }
|
|
|
|
let(:admin) { create(:admin) }
|
|
|
|
let!(:issue) { create(:issue, project: project) }
|
|
|
|
let!(:unescaped_parameter_value) { create(:issue, :confidential, project: project, author: author) }
|
2017-05-04 08:11:15 -04:00
|
|
|
let!(:request_forgery_timing_attack) { create(:issue, :confidential, project: project, assignees: [assignee]) }
|
2016-03-17 15:38:51 -04:00
|
|
|
|
|
|
|
describe 'GET #index' do
|
2016-07-25 14:16:19 -04:00
|
|
|
it 'does not list confidential issues for guests' do
|
2016-03-17 15:38:51 -04:00
|
|
|
sign_out(:user)
|
|
|
|
get_issues
|
|
|
|
|
|
|
|
expect(assigns(:issues)).to eq [issue]
|
|
|
|
end
|
|
|
|
|
2016-07-25 14:16:19 -04:00
|
|
|
it 'does not list confidential issues for non project members' do
|
2016-03-17 15:38:51 -04:00
|
|
|
sign_in(non_member)
|
|
|
|
get_issues
|
|
|
|
|
|
|
|
expect(assigns(:issues)).to eq [issue]
|
|
|
|
end
|
|
|
|
|
2016-07-25 14:16:19 -04:00
|
|
|
it 'does not list confidential issues for project members with guest role' do
|
2016-06-06 15:13:31 -04:00
|
|
|
sign_in(member)
|
2017-12-22 03:18:28 -05:00
|
|
|
project.add_guest(member)
|
2016-06-06 15:13:31 -04:00
|
|
|
|
|
|
|
get_issues
|
|
|
|
|
|
|
|
expect(assigns(:issues)).to eq [issue]
|
|
|
|
end
|
|
|
|
|
2016-07-25 14:16:19 -04:00
|
|
|
it 'lists confidential issues for author' do
|
2016-03-17 15:38:51 -04:00
|
|
|
sign_in(author)
|
|
|
|
get_issues
|
|
|
|
|
|
|
|
expect(assigns(:issues)).to include unescaped_parameter_value
|
|
|
|
expect(assigns(:issues)).not_to include request_forgery_timing_attack
|
|
|
|
end
|
|
|
|
|
2016-07-25 14:16:19 -04:00
|
|
|
it 'lists confidential issues for assignee' do
|
2016-03-17 15:38:51 -04:00
|
|
|
sign_in(assignee)
|
|
|
|
get_issues
|
|
|
|
|
|
|
|
expect(assigns(:issues)).not_to include unescaped_parameter_value
|
|
|
|
expect(assigns(:issues)).to include request_forgery_timing_attack
|
|
|
|
end
|
|
|
|
|
2016-07-25 14:16:19 -04:00
|
|
|
it 'lists confidential issues for project members' do
|
2016-03-17 15:38:51 -04:00
|
|
|
sign_in(member)
|
2017-12-22 03:18:28 -05:00
|
|
|
project.add_developer(member)
|
2016-03-17 15:38:51 -04:00
|
|
|
|
|
|
|
get_issues
|
|
|
|
|
|
|
|
expect(assigns(:issues)).to include unescaped_parameter_value
|
|
|
|
expect(assigns(:issues)).to include request_forgery_timing_attack
|
|
|
|
end
|
|
|
|
|
2020-04-14 14:09:54 -04:00
|
|
|
context 'when admin mode is enabled', :enable_admin_mode do
|
|
|
|
it 'lists confidential issues for admin' do
|
|
|
|
sign_in(admin)
|
|
|
|
get_issues
|
2016-03-17 15:38:51 -04:00
|
|
|
|
2020-04-14 14:09:54 -04:00
|
|
|
expect(assigns(:issues)).to include unescaped_parameter_value
|
|
|
|
expect(assigns(:issues)).to include request_forgery_timing_attack
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'when admin mode is disabled' do
|
|
|
|
it 'does not list confidential issues for admin' do
|
|
|
|
sign_in(admin)
|
|
|
|
get_issues
|
|
|
|
|
|
|
|
expect(assigns(:issues)).to eq [issue]
|
|
|
|
end
|
2016-03-17 15:38:51 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
def get_issues
|
|
|
|
get :index,
|
2018-12-17 17:52:17 -05:00
|
|
|
params: {
|
|
|
|
namespace_id: project.namespace.to_param,
|
|
|
|
project_id: project
|
|
|
|
}
|
2016-03-17 15:38:51 -04:00
|
|
|
end
|
|
|
|
end
|
2015-07-18 01:54:04 -04:00
|
|
|
|
2016-03-17 15:38:51 -04:00
|
|
|
shared_examples_for 'restricted action' do |http_status|
|
|
|
|
it 'returns 404 for guests' do
|
2016-06-06 15:13:31 -04:00
|
|
|
sign_out(:user)
|
2016-03-17 15:38:51 -04:00
|
|
|
go(id: unescaped_parameter_value.to_param)
|
|
|
|
|
2017-10-19 14:28:19 -04:00
|
|
|
expect(response).to have_gitlab_http_status :not_found
|
2016-03-17 15:38:51 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
it 'returns 404 for non project members' do
|
|
|
|
sign_in(non_member)
|
|
|
|
go(id: unescaped_parameter_value.to_param)
|
|
|
|
|
2017-10-19 14:28:19 -04:00
|
|
|
expect(response).to have_gitlab_http_status :not_found
|
2016-06-06 15:13:31 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
it 'returns 404 for project members with guest role' do
|
|
|
|
sign_in(member)
|
2017-12-22 03:18:28 -05:00
|
|
|
project.add_guest(member)
|
2016-06-06 15:13:31 -04:00
|
|
|
go(id: unescaped_parameter_value.to_param)
|
|
|
|
|
2017-10-19 14:28:19 -04:00
|
|
|
expect(response).to have_gitlab_http_status :not_found
|
2016-03-17 15:38:51 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
it "returns #{http_status[:success]} for author" do
|
|
|
|
sign_in(author)
|
|
|
|
go(id: unescaped_parameter_value.to_param)
|
|
|
|
|
2017-10-19 14:28:19 -04:00
|
|
|
expect(response).to have_gitlab_http_status http_status[:success]
|
2016-03-17 15:38:51 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
it "returns #{http_status[:success]} for assignee" do
|
|
|
|
sign_in(assignee)
|
|
|
|
go(id: request_forgery_timing_attack.to_param)
|
|
|
|
|
2017-10-19 14:28:19 -04:00
|
|
|
expect(response).to have_gitlab_http_status http_status[:success]
|
2016-03-17 15:38:51 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
it "returns #{http_status[:success]} for project members" do
|
|
|
|
sign_in(member)
|
2017-12-22 03:18:28 -05:00
|
|
|
project.add_developer(member)
|
2016-03-17 15:38:51 -04:00
|
|
|
go(id: unescaped_parameter_value.to_param)
|
|
|
|
|
2017-10-19 14:28:19 -04:00
|
|
|
expect(response).to have_gitlab_http_status http_status[:success]
|
2016-03-17 15:38:51 -04:00
|
|
|
end
|
|
|
|
|
2020-04-14 14:09:54 -04:00
|
|
|
context 'when admin mode is enabled', :enable_admin_mode do
|
|
|
|
it "returns #{http_status[:success]} for admin" do
|
|
|
|
sign_in(admin)
|
|
|
|
go(id: unescaped_parameter_value.to_param)
|
2016-03-17 15:38:51 -04:00
|
|
|
|
2020-04-14 14:09:54 -04:00
|
|
|
expect(response).to have_gitlab_http_status http_status[:success]
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'when admin mode is disabled' do
|
|
|
|
xit 'returns 404 for admin' do
|
|
|
|
sign_in(admin)
|
|
|
|
go(id: unescaped_parameter_value.to_param)
|
|
|
|
|
|
|
|
expect(response).to have_gitlab_http_status :not_found
|
|
|
|
end
|
2016-03-17 15:38:51 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2017-10-03 05:28:42 -04:00
|
|
|
describe 'PUT #update' do
|
|
|
|
def update_issue(issue_params: {}, additional_params: {}, id: nil)
|
|
|
|
id ||= issue.iid
|
|
|
|
params = {
|
|
|
|
namespace_id: project.namespace.to_param,
|
|
|
|
project_id: project,
|
|
|
|
id: id,
|
|
|
|
issue: { title: 'New title' }.merge(issue_params),
|
|
|
|
format: :json
|
|
|
|
}.merge(additional_params)
|
|
|
|
|
2018-12-17 17:52:17 -05:00
|
|
|
put :update, params: params
|
2017-10-03 05:28:42 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
def go(id:)
|
|
|
|
update_issue(id: id)
|
|
|
|
end
|
|
|
|
|
|
|
|
before do
|
|
|
|
sign_in(user)
|
2017-12-22 03:18:28 -05:00
|
|
|
project.add_developer(user)
|
2017-10-03 05:28:42 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
it_behaves_like 'restricted action', success: 200
|
|
|
|
it_behaves_like 'update invalid issuable', Issue
|
|
|
|
|
|
|
|
context 'changing the assignee' do
|
|
|
|
it 'limits the attributes exposed on the assignee' do
|
|
|
|
assignee = create(:user)
|
|
|
|
project.add_developer(assignee)
|
|
|
|
|
|
|
|
update_issue(issue_params: { assignee_ids: [assignee.id] })
|
|
|
|
|
2019-07-16 04:03:49 -04:00
|
|
|
expect(json_response['assignees'].first.keys)
|
2020-05-12 08:09:47 -04:00
|
|
|
.to include(*%w(id name username avatar_url state web_url))
|
2017-10-03 05:28:42 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2020-04-21 11:21:10 -04:00
|
|
|
context 'Recaptcha is enabled' do
|
2017-10-03 05:28:42 -04:00
|
|
|
before do
|
|
|
|
project.update!(visibility_level: Gitlab::VisibilityLevel::PUBLIC)
|
|
|
|
stub_application_setting(recaptcha_enabled: true)
|
|
|
|
end
|
|
|
|
|
2020-04-21 11:21:10 -04:00
|
|
|
context 'when SpamVerdictService allows the issue' do
|
2017-10-03 05:28:42 -04:00
|
|
|
before do
|
2020-04-21 11:21:10 -04:00
|
|
|
expect_next_instance_of(Spam::SpamVerdictService) do |verdict_service|
|
|
|
|
expect(verdict_service).to receive(:execute).and_return(ALLOW)
|
2019-09-24 23:06:21 -04:00
|
|
|
end
|
2017-10-03 05:28:42 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
it 'normally updates the issue' do
|
|
|
|
expect { update_issue(issue_params: { title: 'Foo' }) }.to change { issue.reload.title }.to('Foo')
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'when an issue is identified as spam' do
|
2020-04-21 11:21:10 -04:00
|
|
|
context 'when recaptcha is not verified' do
|
2017-10-03 05:28:42 -04:00
|
|
|
before do
|
2020-04-21 11:21:10 -04:00
|
|
|
expect_next_instance_of(Spam::SpamVerdictService) do |verdict_service|
|
2020-05-25 23:08:02 -04:00
|
|
|
expect(verdict_service).to receive(:execute).and_return(CONDITIONAL_ALLOW)
|
2019-09-24 23:06:21 -04:00
|
|
|
end
|
2017-10-03 05:28:42 -04:00
|
|
|
end
|
|
|
|
|
2019-09-24 23:06:21 -04:00
|
|
|
context 'when allow_possible_spam feature flag is false' do
|
|
|
|
before do
|
|
|
|
stub_feature_flags(allow_possible_spam: false)
|
|
|
|
end
|
2017-10-03 05:28:42 -04:00
|
|
|
|
2020-04-06 23:09:15 -04:00
|
|
|
it 'rejects an issue recognized as spam' do
|
2019-09-24 23:06:21 -04:00
|
|
|
expect { update_issue }.not_to change { issue.reload.title }
|
|
|
|
end
|
2017-10-03 05:28:42 -04:00
|
|
|
|
2020-04-21 14:09:31 -04:00
|
|
|
it 'rejects an issue recognized as a spam when reCAPTCHA disabled' do
|
2019-09-24 23:06:21 -04:00
|
|
|
stub_application_setting(recaptcha_enabled: false)
|
2017-10-03 05:28:42 -04:00
|
|
|
|
2019-09-24 23:06:21 -04:00
|
|
|
expect { update_issue }.not_to change { issue.reload.title }
|
|
|
|
end
|
2017-10-03 05:28:42 -04:00
|
|
|
|
2019-09-24 23:06:21 -04:00
|
|
|
it 'creates a spam log' do
|
|
|
|
expect { update_issue(issue_params: { title: 'Spam title' }) }
|
|
|
|
.to log_spam(title: 'Spam title', noteable_type: 'Issue')
|
|
|
|
end
|
2017-10-03 05:28:42 -04:00
|
|
|
|
2020-02-27 07:09:12 -05:00
|
|
|
context 'renders properly' do
|
|
|
|
render_views
|
2017-10-03 05:28:42 -04:00
|
|
|
|
2020-02-27 07:09:12 -05:00
|
|
|
it 'renders recaptcha_html json response' do
|
|
|
|
update_issue
|
2017-10-03 05:28:42 -04:00
|
|
|
|
2020-02-27 07:09:12 -05:00
|
|
|
expect(response).to have_gitlab_http_status(:ok)
|
|
|
|
expect(json_response).to have_key('recaptcha_html')
|
|
|
|
expect(json_response['recaptcha_html']).not_to be_empty
|
|
|
|
end
|
2019-09-24 23:06:21 -04:00
|
|
|
end
|
2017-10-03 05:28:42 -04:00
|
|
|
end
|
|
|
|
|
2019-09-24 23:06:21 -04:00
|
|
|
context 'when allow_possible_spam feature flag is true' do
|
|
|
|
it 'updates the issue recognized as spam' do
|
|
|
|
expect { update_issue }.to change { issue.reload.title }
|
|
|
|
end
|
2017-10-03 05:28:42 -04:00
|
|
|
|
2019-09-24 23:06:21 -04:00
|
|
|
it 'creates a spam log' do
|
|
|
|
expect { update_issue(issue_params: { title: 'Spam title' }) }
|
|
|
|
.to log_spam(
|
|
|
|
title: 'Spam title', description: issue.description,
|
|
|
|
noteable_type: 'Issue', recaptcha_verified: false
|
|
|
|
)
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'returns 200 status' do
|
|
|
|
update_issue
|
|
|
|
|
2020-01-28 07:08:44 -05:00
|
|
|
expect(response).to have_gitlab_http_status(:ok)
|
2019-09-24 23:06:21 -04:00
|
|
|
end
|
2017-10-03 05:28:42 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2020-04-21 11:21:10 -04:00
|
|
|
context 'when recaptcha is verified' do
|
2017-10-03 05:28:42 -04:00
|
|
|
let(:spammy_title) { 'Whatever' }
|
|
|
|
let!(:spam_logs) { create_list(:spam_log, 2, user: user, title: spammy_title) }
|
|
|
|
|
|
|
|
def update_verified_issue
|
|
|
|
update_issue(
|
|
|
|
issue_params: { title: spammy_title },
|
|
|
|
additional_params: { spam_log_id: spam_logs.last.id, recaptcha_verification: true })
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'returns 200 status' do
|
2020-01-28 07:08:44 -05:00
|
|
|
expect(response).to have_gitlab_http_status(:ok)
|
2017-10-03 05:28:42 -04:00
|
|
|
end
|
|
|
|
|
2020-04-21 14:09:31 -04:00
|
|
|
it 'accepts an issue after reCAPTCHA is verified' do
|
2017-10-03 05:28:42 -04:00
|
|
|
expect { update_verified_issue }.to change { issue.reload.title }.to(spammy_title)
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'marks spam log as recaptcha_verified' do
|
|
|
|
expect { update_verified_issue }.to change { SpamLog.last.recaptcha_verified }.from(false).to(true)
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'does not mark spam log as recaptcha_verified when it does not belong to current_user' do
|
|
|
|
spam_log = create(:spam_log)
|
|
|
|
|
|
|
|
expect { update_issue(issue_params: { spam_log_id: spam_log.id, recaptcha_verification: true }) }
|
|
|
|
.not_to change { SpamLog.last.recaptcha_verified }
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2016-03-17 15:38:51 -04:00
|
|
|
describe 'GET #show' do
|
|
|
|
it_behaves_like 'restricted action', success: 200
|
|
|
|
|
|
|
|
def go(id:)
|
|
|
|
get :show,
|
2018-12-17 17:52:17 -05:00
|
|
|
params: {
|
|
|
|
namespace_id: project.namespace.to_param,
|
|
|
|
project_id: project,
|
|
|
|
id: id
|
|
|
|
}
|
2016-03-17 15:38:51 -04:00
|
|
|
end
|
2018-10-02 22:56:51 -04:00
|
|
|
|
2018-10-05 06:35:20 -04:00
|
|
|
it 'avoids (most) N+1s loading labels', :request_store do
|
2018-10-02 22:56:51 -04:00
|
|
|
label = create(:label, project: project).to_reference
|
|
|
|
labels = create_list(:label, 10, project: project).map(&:to_reference)
|
|
|
|
issue = create(:issue, project: project, description: 'Test issue')
|
|
|
|
|
|
|
|
control_count = ActiveRecord::QueryRecorder.new { issue.update(description: [issue.description, label].join(' ')) }.count
|
|
|
|
|
2019-09-18 10:02:45 -04:00
|
|
|
# Follow-up to get rid of this `2 * label.count` requirement: https://gitlab.com/gitlab-org/gitlab-foss/issues/52230
|
2018-10-02 22:56:51 -04:00
|
|
|
expect { issue.update(description: [issue.description, labels].join(' ')) }
|
|
|
|
.not_to exceed_query_limit(control_count + 2 * labels.count)
|
|
|
|
end
|
2016-03-17 15:38:51 -04:00
|
|
|
end
|
|
|
|
|
2017-07-17 10:38:43 -04:00
|
|
|
describe 'GET #realtime_changes' do
|
|
|
|
it_behaves_like 'restricted action', success: 200
|
|
|
|
|
|
|
|
def go(id:)
|
|
|
|
get :realtime_changes,
|
2018-12-17 17:52:17 -05:00
|
|
|
params: {
|
|
|
|
namespace_id: project.namespace.to_param,
|
|
|
|
project_id: project,
|
|
|
|
id: id
|
|
|
|
}
|
2017-07-17 10:38:43 -04:00
|
|
|
end
|
|
|
|
end
|
2017-10-26 07:04:07 -04:00
|
|
|
|
|
|
|
describe 'GET #edit' do
|
|
|
|
it_behaves_like 'restricted action', success: 200
|
|
|
|
|
|
|
|
def go(id:)
|
|
|
|
get :edit,
|
2018-12-17 17:52:17 -05:00
|
|
|
params: {
|
|
|
|
namespace_id: project.namespace.to_param,
|
|
|
|
project_id: project,
|
|
|
|
id: id
|
|
|
|
}
|
2017-10-26 07:04:07 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
describe 'PUT #update' do
|
|
|
|
it_behaves_like 'restricted action', success: 302
|
|
|
|
|
|
|
|
def go(id:)
|
|
|
|
put :update,
|
2018-12-17 17:52:17 -05:00
|
|
|
params: {
|
|
|
|
namespace_id: project.namespace.to_param,
|
|
|
|
project_id: project,
|
|
|
|
id: id,
|
|
|
|
issue: { title: 'New title' }
|
|
|
|
}
|
2017-10-26 07:04:07 -04:00
|
|
|
end
|
|
|
|
end
|
2015-07-18 01:54:04 -04:00
|
|
|
end
|
2016-02-26 03:55:43 -05:00
|
|
|
|
2016-07-16 12:42:44 -04:00
|
|
|
describe 'POST #create' do
|
2017-01-27 11:25:39 -05:00
|
|
|
def post_new_issue(issue_attrs = {}, additional_params = {})
|
2016-12-23 00:44:02 -05:00
|
|
|
sign_in(user)
|
2017-08-02 15:55:11 -04:00
|
|
|
project = create(:project, :public)
|
2017-12-22 03:18:28 -05:00
|
|
|
project.add_developer(user)
|
2016-12-23 00:44:02 -05:00
|
|
|
|
2018-12-17 17:52:17 -05:00
|
|
|
post :create, params: {
|
2016-12-23 00:44:02 -05:00
|
|
|
namespace_id: project.namespace.to_param,
|
2017-02-23 18:55:01 -05:00
|
|
|
project_id: project,
|
2017-01-27 11:25:39 -05:00
|
|
|
issue: { title: 'Title', description: 'Description' }.merge(issue_attrs)
|
|
|
|
}.merge(additional_params)
|
2016-12-23 00:44:02 -05:00
|
|
|
|
|
|
|
project.issues.first
|
|
|
|
end
|
|
|
|
|
2016-10-26 17:21:50 -04:00
|
|
|
context 'resolving discussions in MergeRequest' do
|
2017-03-09 20:29:11 -05:00
|
|
|
let(:discussion) { create(:diff_note_on_merge_request).to_discussion }
|
2016-10-26 17:21:50 -04:00
|
|
|
let(:merge_request) { discussion.noteable }
|
|
|
|
let(:project) { merge_request.source_project }
|
|
|
|
|
|
|
|
before do
|
2018-07-11 10:36:08 -04:00
|
|
|
project.add_maintainer(user)
|
2016-10-26 17:21:50 -04:00
|
|
|
sign_in user
|
|
|
|
end
|
|
|
|
|
|
|
|
let(:merge_request_params) do
|
2017-03-10 03:19:12 -05:00
|
|
|
{ merge_request_to_resolve_discussions_of: merge_request.iid }
|
2016-10-26 17:21:50 -04:00
|
|
|
end
|
|
|
|
|
2017-02-27 04:23:36 -05:00
|
|
|
def post_issue(issue_params, other_params: {})
|
2018-12-17 17:52:17 -05:00
|
|
|
post :create, params: { namespace_id: project.namespace.to_param, project_id: project, issue: issue_params, merge_request_to_resolve_discussions_of: merge_request.iid }.merge(other_params)
|
2016-10-26 17:21:50 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
it 'creates an issue for the project' do
|
|
|
|
expect { post_issue({ title: 'Hello' }) }.to change { project.issues.reload.size }.by(1)
|
|
|
|
end
|
|
|
|
|
|
|
|
it "doesn't overwrite given params" do
|
|
|
|
post_issue(description: 'Manually entered description')
|
|
|
|
|
|
|
|
expect(assigns(:issue).description).to eq('Manually entered description')
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'resolves the discussion in the merge_request' do
|
|
|
|
post_issue(title: 'Hello')
|
|
|
|
discussion.first_note.reload
|
|
|
|
|
|
|
|
expect(discussion.resolved?).to eq(true)
|
|
|
|
end
|
2017-02-27 04:23:36 -05:00
|
|
|
|
2017-03-08 14:16:17 -05:00
|
|
|
it 'sets a flash message' do
|
|
|
|
post_issue(title: 'Hello')
|
|
|
|
|
2019-12-12 07:07:33 -05:00
|
|
|
expect(flash[:notice]).to eq(_('Resolved all discussions.'))
|
2017-03-08 14:16:17 -05:00
|
|
|
end
|
|
|
|
|
2017-03-09 08:25:54 -05:00
|
|
|
describe "resolving a single discussion" do
|
|
|
|
before do
|
|
|
|
post_issue({ title: 'Hello' }, other_params: { discussion_to_resolve: discussion.id })
|
|
|
|
end
|
|
|
|
it 'resolves a single discussion' do
|
|
|
|
discussion.first_note.reload
|
2017-03-08 14:16:17 -05:00
|
|
|
|
2017-03-09 08:25:54 -05:00
|
|
|
expect(discussion.resolved?).to eq(true)
|
|
|
|
end
|
2017-02-27 04:23:36 -05:00
|
|
|
|
2017-03-09 08:25:54 -05:00
|
|
|
it 'sets a flash message that one discussion was resolved' do
|
2019-12-12 07:07:33 -05:00
|
|
|
expect(flash[:notice]).to eq(_('Resolved 1 discussion.'))
|
2017-03-09 08:25:54 -05:00
|
|
|
end
|
2017-02-27 04:23:36 -05:00
|
|
|
end
|
2016-10-26 17:21:50 -04:00
|
|
|
end
|
|
|
|
|
2020-04-21 11:21:10 -04:00
|
|
|
context 'Recaptcha is enabled' do
|
2016-07-16 12:42:44 -04:00
|
|
|
before do
|
2017-01-27 11:25:39 -05:00
|
|
|
stub_application_setting(recaptcha_enabled: true)
|
2016-07-16 12:42:44 -04:00
|
|
|
end
|
|
|
|
|
2020-04-21 11:21:10 -04:00
|
|
|
context 'when SpamVerdictService allows the issue' do
|
2017-01-27 11:25:39 -05:00
|
|
|
before do
|
2019-09-24 23:06:21 -04:00
|
|
|
stub_feature_flags(allow_possible_spam: false)
|
|
|
|
|
2020-04-21 11:21:10 -04:00
|
|
|
expect_next_instance_of(Spam::SpamVerdictService) do |verdict_service|
|
|
|
|
expect(verdict_service).to receive(:execute).and_return(ALLOW)
|
2019-09-24 23:06:21 -04:00
|
|
|
end
|
2017-01-27 11:25:39 -05:00
|
|
|
end
|
2016-07-16 12:42:44 -04:00
|
|
|
|
2019-09-24 23:06:21 -04:00
|
|
|
it 'creates an issue' do
|
|
|
|
expect { post_new_issue(title: 'Some title') }.to change(Issue, :count)
|
2017-01-27 11:25:39 -05:00
|
|
|
end
|
2016-07-16 12:42:44 -04:00
|
|
|
end
|
|
|
|
|
2020-04-21 11:21:10 -04:00
|
|
|
context 'when SpamVerdictService requires recaptcha' do
|
2017-01-27 11:25:39 -05:00
|
|
|
context 'when captcha is not verified' do
|
2017-06-14 14:18:56 -04:00
|
|
|
before do
|
2020-04-21 11:21:10 -04:00
|
|
|
expect_next_instance_of(Spam::SpamVerdictService) do |verdict_service|
|
2020-05-25 23:08:02 -04:00
|
|
|
expect(verdict_service).to receive(:execute).and_return(CONDITIONAL_ALLOW)
|
2019-09-24 23:06:21 -04:00
|
|
|
end
|
2017-06-14 14:18:56 -04:00
|
|
|
end
|
2017-01-27 11:25:39 -05:00
|
|
|
|
2020-04-21 11:21:10 -04:00
|
|
|
def post_spam_issue
|
|
|
|
post_new_issue(title: 'Spam Title', description: 'Spam lives here')
|
|
|
|
end
|
|
|
|
|
2019-09-24 23:06:21 -04:00
|
|
|
context 'when allow_possible_spam feature flag is false' do
|
|
|
|
before do
|
|
|
|
stub_feature_flags(allow_possible_spam: false)
|
|
|
|
end
|
2017-01-27 11:25:39 -05:00
|
|
|
|
2020-04-06 23:09:15 -04:00
|
|
|
it 'rejects an issue recognized as spam' do
|
2019-09-24 23:06:21 -04:00
|
|
|
expect { post_spam_issue }.not_to change(Issue, :count)
|
|
|
|
end
|
2017-01-27 11:25:39 -05:00
|
|
|
|
2019-09-24 23:06:21 -04:00
|
|
|
it 'creates a spam log' do
|
|
|
|
expect { post_spam_issue }
|
|
|
|
.to log_spam(title: 'Spam Title', noteable_type: 'Issue', recaptcha_verified: false)
|
|
|
|
end
|
2017-01-27 11:25:39 -05:00
|
|
|
|
2019-09-24 23:06:21 -04:00
|
|
|
it 'does not create an issue when it is not valid' do
|
|
|
|
expect { post_new_issue(title: '') }.not_to change(Issue, :count)
|
|
|
|
end
|
|
|
|
|
2020-04-21 14:09:31 -04:00
|
|
|
it 'does not create an issue when reCAPTCHA is not enabled' do
|
2019-09-24 23:06:21 -04:00
|
|
|
stub_application_setting(recaptcha_enabled: false)
|
|
|
|
|
|
|
|
expect { post_spam_issue }.not_to change(Issue, :count)
|
|
|
|
end
|
2017-01-27 11:25:39 -05:00
|
|
|
end
|
|
|
|
|
2019-09-24 23:06:21 -04:00
|
|
|
context 'when allow_possible_spam feature flag is true' do
|
|
|
|
it 'creates an issue recognized as spam' do
|
|
|
|
expect { post_spam_issue }.to change(Issue, :count)
|
|
|
|
end
|
2017-01-27 11:25:39 -05:00
|
|
|
|
2019-09-24 23:06:21 -04:00
|
|
|
it 'creates a spam log' do
|
|
|
|
expect { post_spam_issue }
|
|
|
|
.to log_spam(title: 'Spam Title', noteable_type: 'Issue', recaptcha_verified: false)
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'does not create an issue when it is not valid' do
|
|
|
|
expect { post_new_issue(title: '') }.not_to change(Issue, :count)
|
|
|
|
end
|
2017-01-27 11:25:39 -05:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2020-04-21 11:21:10 -04:00
|
|
|
context 'when Recaptcha is verified' do
|
2017-01-27 11:25:39 -05:00
|
|
|
let!(:spam_logs) { create_list(:spam_log, 2, user: user, title: 'Title') }
|
2020-04-21 11:21:10 -04:00
|
|
|
let!(:last_spam_log) { spam_logs.last }
|
2017-01-27 11:25:39 -05:00
|
|
|
|
|
|
|
def post_verified_issue
|
2020-04-21 11:21:10 -04:00
|
|
|
post_new_issue({}, { spam_log_id: last_spam_log.id, recaptcha_verification: true } )
|
2017-01-27 11:25:39 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
before do
|
2019-09-24 23:06:21 -04:00
|
|
|
expect(controller).to receive_messages(verify_recaptcha: true)
|
2017-01-27 11:25:39 -05:00
|
|
|
end
|
|
|
|
|
2020-04-21 14:09:31 -04:00
|
|
|
it 'accepts an issue after reCAPTCHA is verified' do
|
2017-01-27 11:25:39 -05:00
|
|
|
expect { post_verified_issue }.to change(Issue, :count)
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'marks spam log as recaptcha_verified' do
|
2020-04-21 11:21:10 -04:00
|
|
|
expect { post_verified_issue }.to change { last_spam_log.reload.recaptcha_verified }.from(false).to(true)
|
2017-01-27 11:25:39 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
it 'does not mark spam log as recaptcha_verified when it does not belong to current_user' do
|
|
|
|
spam_log = create(:spam_log)
|
|
|
|
|
2017-06-21 09:48:12 -04:00
|
|
|
expect { post_new_issue({}, { spam_log_id: spam_log.id, recaptcha_verification: true } ) }
|
2020-04-21 11:21:10 -04:00
|
|
|
.not_to change { last_spam_log.recaptcha_verified }
|
2017-01-27 11:25:39 -05:00
|
|
|
end
|
|
|
|
end
|
2016-07-16 12:42:44 -04:00
|
|
|
end
|
|
|
|
end
|
2016-07-27 20:03:06 -04:00
|
|
|
|
|
|
|
context 'user agent details are saved' do
|
|
|
|
before do
|
|
|
|
request.env['action_dispatch.remote_ip'] = '127.0.0.1'
|
|
|
|
end
|
|
|
|
|
2016-12-23 00:44:02 -05:00
|
|
|
it 'creates a user agent detail' do
|
2017-01-27 11:25:39 -05:00
|
|
|
expect { post_new_issue }.to change(UserAgentDetail, :count).by(1)
|
2016-12-23 00:44:02 -05:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2017-05-31 01:50:53 -04:00
|
|
|
context 'when description has quick actions' do
|
2016-12-23 00:44:02 -05:00
|
|
|
before do
|
2016-07-27 20:03:06 -04:00
|
|
|
sign_in(user)
|
|
|
|
end
|
|
|
|
|
2016-12-23 00:44:02 -05:00
|
|
|
it 'can add spent time' do
|
|
|
|
issue = post_new_issue(description: '/spend 1h')
|
|
|
|
|
|
|
|
expect(issue.total_time_spent).to eq(3600)
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'can set the time estimate' do
|
|
|
|
issue = post_new_issue(description: '/estimate 2h')
|
|
|
|
|
|
|
|
expect(issue.time_estimate).to eq(7200)
|
2016-07-27 20:03:06 -04:00
|
|
|
end
|
|
|
|
end
|
2019-12-12 22:07:50 -05:00
|
|
|
|
|
|
|
context 'when created from sentry error' do
|
|
|
|
subject { post_new_issue(sentry_issue_attributes: { sentry_issue_identifier: 1234567 }) }
|
|
|
|
|
|
|
|
it 'creates an issue' do
|
|
|
|
expect { subject }.to change(Issue, :count)
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'creates a sentry issue' do
|
|
|
|
expect { subject }.to change(SentryIssue, :count)
|
|
|
|
end
|
|
|
|
end
|
2020-04-14 11:09:44 -04:00
|
|
|
|
|
|
|
context 'when the endpoint receives requests above the limit' do
|
|
|
|
before do
|
|
|
|
stub_application_setting(issues_create_limit: 5)
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'prevents from creating more issues', :request_store do
|
|
|
|
5.times { post_new_issue }
|
|
|
|
|
|
|
|
expect { post_new_issue }
|
|
|
|
.to change { Gitlab::GitalyClient.get_request_count }.by(1) # creates 1 projects and 0 issues
|
|
|
|
|
|
|
|
post_new_issue
|
|
|
|
expect(response.body).to eq(_('This endpoint has been requested too many times. Try again later.'))
|
|
|
|
expect(response).to have_gitlab_http_status(:too_many_requests)
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'logs the event on auth.log' do
|
|
|
|
attributes = {
|
|
|
|
message: 'Application_Rate_Limiter_Request',
|
|
|
|
env: :issues_create_request_limit,
|
|
|
|
remote_ip: '0.0.0.0',
|
|
|
|
request_method: 'POST',
|
|
|
|
path: "/#{project.full_path}/-/issues",
|
|
|
|
user_id: user.id,
|
|
|
|
username: user.username
|
|
|
|
}
|
|
|
|
|
|
|
|
expect(Gitlab::AuthLogger).to receive(:error).with(attributes).once
|
|
|
|
|
|
|
|
project.add_developer(user)
|
|
|
|
sign_in(user)
|
|
|
|
|
|
|
|
6.times do
|
|
|
|
post :create, params: {
|
|
|
|
namespace_id: project.namespace.to_param,
|
|
|
|
project_id: project,
|
|
|
|
issue: { title: 'Title', description: 'Description' }
|
|
|
|
}
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2016-07-16 12:42:44 -04:00
|
|
|
end
|
|
|
|
|
2016-08-02 17:21:57 -04:00
|
|
|
describe 'POST #mark_as_spam' do
|
|
|
|
context 'properly submits to Akismet' do
|
|
|
|
before do
|
2020-01-30 10:09:15 -05:00
|
|
|
expect_next_instance_of(Spam::AkismetService) do |akismet_service|
|
2019-09-24 23:06:21 -04:00
|
|
|
expect(akismet_service).to receive_messages(submit_spam: true)
|
|
|
|
end
|
|
|
|
expect_next_instance_of(ApplicationSetting) do |setting|
|
|
|
|
expect(setting).to receive_messages(akismet_enabled: true)
|
|
|
|
end
|
2016-08-02 17:21:57 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
def post_spam
|
|
|
|
admin = create(:admin)
|
|
|
|
create(:user_agent_detail, subject: issue)
|
2018-07-11 10:36:08 -04:00
|
|
|
project.add_maintainer(admin)
|
2016-08-02 17:21:57 -04:00
|
|
|
sign_in(admin)
|
2018-12-17 17:52:17 -05:00
|
|
|
post :mark_as_spam, params: {
|
2017-02-23 18:55:01 -05:00
|
|
|
namespace_id: project.namespace,
|
|
|
|
project_id: project,
|
2016-08-02 17:21:57 -04:00
|
|
|
id: issue.iid
|
|
|
|
}
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'updates issue' do
|
|
|
|
post_spam
|
2016-08-09 13:43:47 -04:00
|
|
|
expect(issue.submittable_as_spam?).to be_falsey
|
2016-08-02 17:21:57 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2016-02-26 03:55:43 -05:00
|
|
|
describe "DELETE #destroy" do
|
2016-03-21 09:12:52 -04:00
|
|
|
context "when the user is a developer" do
|
2017-06-14 14:18:56 -04:00
|
|
|
before do
|
|
|
|
sign_in(user)
|
|
|
|
end
|
|
|
|
|
2020-01-28 13:08:35 -05:00
|
|
|
it "does not delete the issue, returning :not_found" do
|
2018-12-17 17:52:17 -05:00
|
|
|
delete :destroy, params: { namespace_id: project.namespace, project_id: project, id: issue.iid }
|
2020-01-28 13:08:35 -05:00
|
|
|
|
2020-01-28 07:08:44 -05:00
|
|
|
expect(response).to have_gitlab_http_status(:not_found)
|
2016-03-21 09:12:52 -04:00
|
|
|
end
|
2016-02-26 03:55:43 -05:00
|
|
|
end
|
|
|
|
|
2016-03-21 09:12:52 -04:00
|
|
|
context "when the user is owner" do
|
|
|
|
let(:owner) { create(:user) }
|
|
|
|
let(:namespace) { create(:namespace, owner: owner) }
|
2017-08-02 15:55:11 -04:00
|
|
|
let(:project) { create(:project, namespace: namespace) }
|
2016-03-21 09:12:52 -04:00
|
|
|
|
2017-06-14 14:18:56 -04:00
|
|
|
before do
|
|
|
|
sign_in(owner)
|
|
|
|
end
|
2016-02-26 03:55:43 -05:00
|
|
|
|
2016-03-21 09:12:52 -04:00
|
|
|
it "deletes the issue" do
|
2019-08-29 00:57:54 -04:00
|
|
|
delete :destroy, params: { namespace_id: project.namespace, project_id: project, id: issue.iid, destroy_confirm: true }
|
2016-02-26 03:55:43 -05:00
|
|
|
|
2020-01-28 07:08:44 -05:00
|
|
|
expect(response).to have_gitlab_http_status(:found)
|
2017-07-24 08:21:16 -04:00
|
|
|
expect(controller).to set_flash[:notice].to(/The issue was successfully deleted\./)
|
2016-02-26 03:55:43 -05:00
|
|
|
end
|
2016-09-01 18:12:05 -04:00
|
|
|
|
2019-08-29 00:57:54 -04:00
|
|
|
it "prevents deletion if destroy_confirm is not set" do
|
2019-12-16 07:07:43 -05:00
|
|
|
expect(Gitlab::ErrorTracking).to receive(:track_exception).and_call_original
|
2019-08-29 00:57:54 -04:00
|
|
|
|
|
|
|
delete :destroy, params: { namespace_id: project.namespace, project_id: project, id: issue.iid }
|
|
|
|
|
2020-01-28 07:08:44 -05:00
|
|
|
expect(response).to have_gitlab_http_status(:found)
|
2019-08-29 00:57:54 -04:00
|
|
|
expect(controller).to set_flash[:notice].to('Destroy confirmation not provided for issue')
|
|
|
|
end
|
|
|
|
|
|
|
|
it "prevents deletion in JSON format if destroy_confirm is not set" do
|
2019-12-16 07:07:43 -05:00
|
|
|
expect(Gitlab::ErrorTracking).to receive(:track_exception).and_call_original
|
2019-08-29 00:57:54 -04:00
|
|
|
|
|
|
|
delete :destroy, params: { namespace_id: project.namespace, project_id: project, id: issue.iid, format: 'json' }
|
|
|
|
|
2020-01-28 07:08:44 -05:00
|
|
|
expect(response).to have_gitlab_http_status(:unprocessable_entity)
|
2019-08-29 00:57:54 -04:00
|
|
|
expect(json_response).to eq({ 'errors' => 'Destroy confirmation not provided for issue' })
|
|
|
|
end
|
|
|
|
|
2016-09-01 18:12:05 -04:00
|
|
|
it 'delegates the update of the todos count cache to TodoService' do
|
2017-12-08 07:17:22 -05:00
|
|
|
expect_any_instance_of(TodoService).to receive(:destroy_target).with(issue).once
|
2016-09-01 18:12:05 -04:00
|
|
|
|
2019-08-29 00:57:54 -04:00
|
|
|
delete :destroy, params: { namespace_id: project.namespace, project_id: project, id: issue.iid, destroy_confirm: true }
|
2016-09-01 18:12:05 -04:00
|
|
|
end
|
2016-02-26 03:55:43 -05:00
|
|
|
end
|
|
|
|
end
|
2016-04-25 14:10:20 -04:00
|
|
|
|
|
|
|
describe 'POST #toggle_award_emoji' do
|
|
|
|
before do
|
|
|
|
sign_in(user)
|
2017-08-10 11:53:55 -04:00
|
|
|
project.add_developer(user)
|
2016-04-25 14:10:20 -04:00
|
|
|
end
|
|
|
|
|
2019-07-08 21:58:57 -04:00
|
|
|
subject do
|
|
|
|
post(:toggle_award_emoji, params: {
|
|
|
|
namespace_id: project.namespace,
|
|
|
|
project_id: project,
|
|
|
|
id: issue.iid,
|
|
|
|
name: emoji_name
|
|
|
|
})
|
|
|
|
end
|
2019-10-18 07:11:44 -04:00
|
|
|
|
2019-07-08 21:58:57 -04:00
|
|
|
let(:emoji_name) { 'thumbsup' }
|
|
|
|
|
2016-05-11 16:43:58 -04:00
|
|
|
it "toggles the award emoji" do
|
2016-06-01 05:23:09 -04:00
|
|
|
expect do
|
2019-07-08 21:58:57 -04:00
|
|
|
subject
|
2016-06-01 05:23:09 -04:00
|
|
|
end.to change { issue.award_emoji.count }.by(1)
|
2016-04-25 14:10:20 -04:00
|
|
|
|
2020-01-28 07:08:44 -05:00
|
|
|
expect(response).to have_gitlab_http_status(:ok)
|
2016-04-25 14:10:20 -04:00
|
|
|
end
|
2019-07-08 21:58:57 -04:00
|
|
|
|
|
|
|
it "removes the already awarded emoji" do
|
|
|
|
create(:award_emoji, awardable: issue, name: emoji_name, user: user)
|
|
|
|
|
|
|
|
expect { subject }.to change { AwardEmoji.count }.by(-1)
|
|
|
|
|
2020-01-28 07:08:44 -05:00
|
|
|
expect(response).to have_gitlab_http_status(:ok)
|
2019-07-08 21:58:57 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
it 'marks Todos on the Issue as done' do
|
|
|
|
todo = create(:todo, target: issue, project: project, user: user)
|
|
|
|
|
|
|
|
subject
|
|
|
|
|
|
|
|
expect(todo.reload).to be_done
|
|
|
|
end
|
2016-04-25 14:10:20 -04:00
|
|
|
end
|
2017-05-04 04:09:21 -04:00
|
|
|
|
|
|
|
describe 'POST create_merge_request' do
|
2019-06-19 04:56:17 -04:00
|
|
|
let(:target_project_id) { nil }
|
2018-04-06 13:58:53 -04:00
|
|
|
let(:project) { create(:project, :repository, :public) }
|
2017-08-11 08:10:43 -04:00
|
|
|
|
2017-05-04 04:09:21 -04:00
|
|
|
before do
|
|
|
|
project.add_developer(user)
|
|
|
|
sign_in(user)
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'creates a new merge request' do
|
|
|
|
expect { create_merge_request }.to change(project.merge_requests, :count).by(1)
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'render merge request as json' do
|
|
|
|
create_merge_request
|
|
|
|
|
2020-05-12 08:09:47 -04:00
|
|
|
expect(response).to have_gitlab_http_status(:ok)
|
2017-05-04 04:09:21 -04:00
|
|
|
expect(response).to match_response_schema('merge_request')
|
|
|
|
end
|
|
|
|
|
2018-04-06 13:58:53 -04:00
|
|
|
it 'is not available when the project is archived' do
|
2018-04-11 17:14:02 -04:00
|
|
|
project.update!(archived: true)
|
2018-04-06 13:58:53 -04:00
|
|
|
|
|
|
|
create_merge_request
|
|
|
|
|
2020-01-28 07:08:44 -05:00
|
|
|
expect(response).to have_gitlab_http_status(:not_found)
|
2018-04-06 13:58:53 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
it 'is not available for users who cannot create merge requests' do
|
|
|
|
sign_in(create(:user))
|
|
|
|
|
|
|
|
create_merge_request
|
|
|
|
|
2020-01-28 07:08:44 -05:00
|
|
|
expect(response).to have_gitlab_http_status(:not_found)
|
2018-04-06 13:58:53 -04:00
|
|
|
end
|
|
|
|
|
2020-04-02 08:08:18 -04:00
|
|
|
context 'invalid branch name' do
|
|
|
|
it 'is unprocessable' do
|
|
|
|
post(
|
|
|
|
:create_merge_request,
|
|
|
|
params: {
|
|
|
|
target_project_id: nil,
|
|
|
|
branch_name: 'master',
|
|
|
|
ref: 'master',
|
|
|
|
namespace_id: project.namespace.to_param,
|
|
|
|
project_id: project.to_param,
|
|
|
|
id: issue.to_param
|
|
|
|
},
|
|
|
|
format: :json
|
|
|
|
)
|
|
|
|
|
|
|
|
expect(response.body).to eq('Branch already exists')
|
|
|
|
expect(response).to have_gitlab_http_status(:unprocessable_entity)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2019-06-19 04:56:17 -04:00
|
|
|
context 'target_project_id is set' do
|
|
|
|
let(:target_project) { fork_project(project, user, repository: true) }
|
|
|
|
let(:target_project_id) { target_project.id }
|
|
|
|
|
2020-05-14 05:07:53 -04:00
|
|
|
it 'creates a new merge request', :sidekiq_might_not_need_inline do
|
|
|
|
expect { create_merge_request }.to change(target_project.merge_requests, :count).by(1)
|
2019-06-19 04:56:17 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2017-05-04 04:09:21 -04:00
|
|
|
def create_merge_request
|
2019-06-19 04:56:17 -04:00
|
|
|
post(
|
|
|
|
:create_merge_request,
|
|
|
|
params: {
|
|
|
|
namespace_id: project.namespace.to_param,
|
|
|
|
project_id: project.to_param,
|
|
|
|
id: issue.to_param,
|
|
|
|
target_project_id: target_project_id
|
|
|
|
},
|
|
|
|
format: :json
|
|
|
|
)
|
2017-05-04 04:09:21 -04:00
|
|
|
end
|
|
|
|
end
|
2017-08-11 12:48:06 -04:00
|
|
|
|
2018-12-05 19:51:30 -05:00
|
|
|
describe 'POST #import_csv' do
|
|
|
|
let(:project) { create(:project, :public) }
|
|
|
|
let(:file) { fixture_file_upload('spec/fixtures/csv_comma.csv') }
|
|
|
|
|
|
|
|
context 'unauthorized' do
|
|
|
|
it 'returns 404 for guests' do
|
|
|
|
sign_out(:user)
|
|
|
|
|
|
|
|
import_csv
|
|
|
|
|
|
|
|
expect(response).to have_gitlab_http_status :not_found
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'returns 404 for project members with reporter role' do
|
|
|
|
sign_in(user)
|
|
|
|
project.add_reporter(user)
|
|
|
|
|
|
|
|
import_csv
|
|
|
|
|
|
|
|
expect(response).to have_gitlab_http_status :not_found
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'authorized' do
|
|
|
|
before do
|
|
|
|
sign_in(user)
|
|
|
|
project.add_developer(user)
|
|
|
|
end
|
|
|
|
|
|
|
|
it "returns 302 for project members with developer role" do
|
|
|
|
import_csv
|
|
|
|
|
2019-12-12 07:07:33 -05:00
|
|
|
expect(flash[:notice]).to eq(_("Your issues are being imported. Once finished, you'll get a confirmation email."))
|
2018-12-05 19:51:30 -05:00
|
|
|
expect(response).to redirect_to(project_issues_path(project))
|
|
|
|
end
|
|
|
|
|
|
|
|
it "shows error when upload fails" do
|
2019-09-24 23:06:21 -04:00
|
|
|
expect_next_instance_of(UploadService) do |upload_service|
|
|
|
|
expect(upload_service).to receive(:execute).and_return(nil)
|
|
|
|
end
|
2018-12-05 19:51:30 -05:00
|
|
|
|
|
|
|
import_csv
|
|
|
|
|
2019-12-12 07:07:33 -05:00
|
|
|
expect(flash[:alert]).to include(_('File upload error.'))
|
2018-12-05 19:51:30 -05:00
|
|
|
expect(response).to redirect_to(project_issues_path(project))
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def import_csv
|
2019-01-11 15:10:55 -05:00
|
|
|
post :import_csv, params: { namespace_id: project.namespace.to_param,
|
|
|
|
project_id: project.to_param,
|
|
|
|
file: file }
|
2018-12-05 19:51:30 -05:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2020-04-21 11:21:10 -04:00
|
|
|
describe 'POST export_csv' do
|
|
|
|
let(:viewer) { user }
|
|
|
|
let(:issue) { create(:issue, project: project) }
|
|
|
|
|
|
|
|
before do
|
|
|
|
project.add_developer(user)
|
|
|
|
end
|
|
|
|
|
|
|
|
def request_csv
|
|
|
|
post :export_csv, params: { namespace_id: project.namespace.to_param, project_id: project.to_param }
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'when logged in' do
|
|
|
|
before do
|
|
|
|
sign_in(viewer)
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'allows CSV export' do
|
|
|
|
expect(ExportCsvWorker).to receive(:perform_async).with(viewer.id, project.id, anything)
|
|
|
|
|
|
|
|
request_csv
|
|
|
|
|
|
|
|
expect(response).to redirect_to(project_issues_path(project))
|
|
|
|
expect(response.flash[:notice]).to match(/\AYour CSV export has started/i)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'when not logged in' do
|
|
|
|
let(:project) { create(:project_empty_repo, :public) }
|
|
|
|
|
|
|
|
it 'redirects to the sign in page' do
|
|
|
|
request_csv
|
|
|
|
|
|
|
|
expect(ExportCsvWorker).not_to receive(:perform_async)
|
|
|
|
expect(response).to redirect_to(new_user_session_path)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2017-08-11 12:48:06 -04:00
|
|
|
describe 'GET #discussions' do
|
|
|
|
let!(:discussion) { create(:discussion_note_on_issue, noteable: issue, project: issue.project) }
|
2019-12-18 19:08:01 -05:00
|
|
|
|
2017-10-17 06:12:24 -04:00
|
|
|
context 'when authenticated' do
|
2017-09-17 02:25:34 -04:00
|
|
|
before do
|
2017-10-17 06:12:24 -04:00
|
|
|
project.add_developer(user)
|
|
|
|
sign_in(user)
|
2017-09-17 02:25:34 -04:00
|
|
|
end
|
|
|
|
|
2019-07-30 14:25:49 -04:00
|
|
|
context do
|
|
|
|
it_behaves_like 'discussions provider' do
|
|
|
|
let!(:author) { create(:user) }
|
|
|
|
let!(:project) { create(:project) }
|
|
|
|
|
|
|
|
let!(:issue) { create(:issue, project: project, author: user) }
|
|
|
|
|
|
|
|
let!(:note_on_issue1) { create(:discussion_note_on_issue, noteable: issue, project: issue.project, author: create(:user)) }
|
|
|
|
let!(:note_on_issue2) { create(:discussion_note_on_issue, noteable: issue, project: issue.project, author: create(:user)) }
|
|
|
|
|
|
|
|
let(:requested_iid) { issue.iid }
|
|
|
|
let(:expected_discussion_count) { 3 }
|
|
|
|
let(:expected_discussion_ids) do
|
|
|
|
[
|
|
|
|
issue.notes.first.discussion_id,
|
|
|
|
note_on_issue1.discussion_id,
|
|
|
|
note_on_issue2.discussion_id
|
|
|
|
]
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2017-10-17 06:12:24 -04:00
|
|
|
it 'returns discussion json' do
|
2018-12-17 17:52:17 -05:00
|
|
|
get :discussions, params: { namespace_id: project.namespace, project_id: project, id: issue.iid }
|
2017-09-17 02:25:34 -04:00
|
|
|
|
2020-03-30 14:08:07 -04:00
|
|
|
expect(json_response.first.keys).to match_array(%w[id reply_id expanded notes diff_discussion discussion_path individual_note resolvable resolved resolved_at resolved_by resolved_by_push commit_id for_commit project_id confidential])
|
2017-09-17 02:25:34 -04:00
|
|
|
end
|
|
|
|
|
2018-07-16 12:18:52 -04:00
|
|
|
it 'renders the author status html if there is a status' do
|
|
|
|
create(:user_status, user: discussion.author)
|
|
|
|
|
2018-12-17 17:52:17 -05:00
|
|
|
get :discussions, params: { namespace_id: project.namespace, project_id: project, id: issue.iid }
|
2018-07-16 12:18:52 -04:00
|
|
|
|
|
|
|
note_json = json_response.first['notes'].first
|
|
|
|
|
|
|
|
expect(note_json['author']['status_tooltip_html']).to be_present
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'does not cause an extra query for the status' do
|
|
|
|
control = ActiveRecord::QueryRecorder.new do
|
2018-12-17 17:52:17 -05:00
|
|
|
get :discussions, params: { namespace_id: project.namespace, project_id: project, id: issue.iid }
|
2018-07-16 12:18:52 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
create(:user_status, user: discussion.author)
|
|
|
|
second_discussion = create(:discussion_note_on_issue, noteable: issue, project: issue.project, author: create(:user))
|
|
|
|
create(:user_status, user: second_discussion.author)
|
|
|
|
|
2018-12-17 17:52:17 -05:00
|
|
|
expect { get :discussions, params: { namespace_id: project.namespace, project_id: project, id: issue.iid } }
|
2018-07-16 12:18:52 -04:00
|
|
|
.not_to exceed_query_limit(control)
|
|
|
|
end
|
|
|
|
|
2018-10-23 05:49:45 -04:00
|
|
|
context 'when user is setting notes filters' do
|
|
|
|
let(:issuable) { issue }
|
2019-01-14 14:20:11 -05:00
|
|
|
let(:issuable_parent) { project }
|
2018-10-23 05:49:45 -04:00
|
|
|
let!(:discussion_note) { create(:discussion_note_on_issue, :system, noteable: issuable, project: project) }
|
|
|
|
|
|
|
|
it_behaves_like 'issuable notes filter'
|
|
|
|
end
|
|
|
|
|
2017-10-17 06:12:24 -04:00
|
|
|
context 'with cross-reference system note', :request_store do
|
|
|
|
let(:new_issue) { create(:issue) }
|
|
|
|
let(:cross_reference) { "mentioned in #{new_issue.to_reference(issue.project)}" }
|
2017-09-17 02:25:34 -04:00
|
|
|
|
2017-10-17 06:12:24 -04:00
|
|
|
before do
|
|
|
|
create(:discussion_note_on_issue, :system, noteable: issue, project: issue.project, note: cross_reference)
|
|
|
|
end
|
2017-09-17 02:25:34 -04:00
|
|
|
|
2017-10-17 06:12:24 -04:00
|
|
|
it 'filters notes that the user should not see' do
|
2018-12-17 17:52:17 -05:00
|
|
|
get :discussions, params: { namespace_id: project.namespace, project_id: project, id: issue.iid }
|
2017-09-17 02:25:34 -04:00
|
|
|
|
2019-07-16 04:03:49 -04:00
|
|
|
expect(json_response.count).to eq(1)
|
2017-10-17 06:12:24 -04:00
|
|
|
end
|
2017-09-17 02:25:34 -04:00
|
|
|
|
2017-10-17 06:12:24 -04:00
|
|
|
it 'does not result in N+1 queries' do
|
|
|
|
# Instantiate the controller variables to ensure QueryRecorder has an accurate base count
|
2018-12-17 17:52:17 -05:00
|
|
|
get :discussions, params: { namespace_id: project.namespace, project_id: project, id: issue.iid }
|
2017-09-17 02:25:34 -04:00
|
|
|
|
2017-10-17 06:12:24 -04:00
|
|
|
RequestStore.clear!
|
|
|
|
|
|
|
|
control_count = ActiveRecord::QueryRecorder.new do
|
2018-12-17 17:52:17 -05:00
|
|
|
get :discussions, params: { namespace_id: project.namespace, project_id: project, id: issue.iid }
|
2017-10-17 06:12:24 -04:00
|
|
|
end.count
|
|
|
|
|
|
|
|
RequestStore.clear!
|
|
|
|
|
|
|
|
create_list(:discussion_note_on_issue, 2, :system, noteable: issue, project: issue.project, note: cross_reference)
|
|
|
|
|
2018-12-17 17:52:17 -05:00
|
|
|
expect { get :discussions, params: { namespace_id: project.namespace, project_id: project, id: issue.iid } }.not_to exceed_query_limit(control_count)
|
2017-10-17 06:12:24 -04:00
|
|
|
end
|
2017-09-17 02:25:34 -04:00
|
|
|
end
|
2019-10-25 08:46:40 -04:00
|
|
|
|
|
|
|
context 'private project' do
|
|
|
|
let!(:branch_note) { create(:discussion_note_on_issue, :system, noteable: issue, project: project) }
|
|
|
|
let!(:commit_note) { create(:discussion_note_on_issue, :system, noteable: issue, project: project) }
|
|
|
|
let!(:branch_note_meta) { create(:system_note_metadata, note: branch_note, action: "branch") }
|
|
|
|
let!(:commit_note_meta) { create(:system_note_metadata, note: commit_note, action: "commit") }
|
|
|
|
|
|
|
|
context 'user is allowed access' do
|
|
|
|
before do
|
|
|
|
project.add_user(user, :maintainer)
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'displays all available notes' do
|
|
|
|
get :discussions, params: { namespace_id: project.namespace, project_id: project, id: issue.iid }
|
|
|
|
|
|
|
|
expect(json_response.length).to eq(3)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'user is a guest' do
|
|
|
|
let(:json_response_note_ids) do
|
|
|
|
json_response.collect { |discussion| discussion["notes"] }.flatten
|
|
|
|
.collect { |note| note["id"].to_i }
|
|
|
|
end
|
|
|
|
|
|
|
|
before do
|
|
|
|
project.add_guest(user)
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'does not display notes w/type listed in TYPES_RESTRICTED_BY_ACCESS_LEVEL' do
|
|
|
|
get :discussions, params: { namespace_id: project.namespace, project_id: project, id: issue.iid }
|
|
|
|
|
|
|
|
expect(json_response.length).to eq(2)
|
|
|
|
expect(json_response_note_ids).not_to include(branch_note.id)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2017-09-17 02:25:34 -04:00
|
|
|
end
|
2017-08-11 12:48:06 -04:00
|
|
|
end
|
2018-11-28 14:06:02 -05:00
|
|
|
|
2020-05-11 05:09:45 -04:00
|
|
|
describe 'GET #designs' do
|
|
|
|
context 'when project has moved' do
|
|
|
|
let(:new_project) { create(:project) }
|
|
|
|
let(:issue) { create(:issue, project: new_project) }
|
|
|
|
|
|
|
|
before do
|
|
|
|
sign_in(user)
|
|
|
|
|
|
|
|
project.route.destroy
|
|
|
|
new_project.redirect_routes.create!(path: project.full_path)
|
|
|
|
new_project.add_developer(user)
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'redirects from an old issue/designs correctly' do
|
|
|
|
get :designs,
|
|
|
|
params: {
|
|
|
|
namespace_id: project.namespace,
|
|
|
|
project_id: project,
|
|
|
|
id: issue
|
|
|
|
}
|
|
|
|
|
|
|
|
expect(response).to redirect_to(designs_project_issue_path(new_project, issue))
|
|
|
|
expect(response).to have_gitlab_http_status(:found)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2018-11-28 14:06:02 -05:00
|
|
|
context 'private project with token authentication' do
|
|
|
|
let(:private_project) { create(:project, :private) }
|
|
|
|
|
2019-11-08 10:06:21 -05:00
|
|
|
it_behaves_like 'authenticates sessionless user', :index, :atom, ignore_incrementing: true do
|
2018-11-28 14:06:02 -05:00
|
|
|
before do
|
|
|
|
default_params.merge!(project_id: private_project, namespace_id: private_project.namespace)
|
|
|
|
|
|
|
|
private_project.add_maintainer(user)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2019-11-08 10:06:21 -05:00
|
|
|
it_behaves_like 'authenticates sessionless user', :calendar, :ics, ignore_incrementing: true do
|
2018-11-28 14:06:02 -05:00
|
|
|
before do
|
|
|
|
default_params.merge!(project_id: private_project, namespace_id: private_project.namespace)
|
|
|
|
|
|
|
|
private_project.add_maintainer(user)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'public project with token authentication' do
|
|
|
|
let(:public_project) { create(:project, :public) }
|
|
|
|
|
|
|
|
it_behaves_like 'authenticates sessionless user', :index, :atom, public: true do
|
|
|
|
before do
|
|
|
|
default_params.merge!(project_id: public_project, namespace_id: public_project.namespace)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
it_behaves_like 'authenticates sessionless user', :calendar, :ics, public: true do
|
|
|
|
before do
|
|
|
|
default_params.merge!(project_id: public_project, namespace_id: public_project.namespace)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2015-07-18 01:54:04 -04:00
|
|
|
end
|