Commit 74d5422a authored by Sean McGivern's avatar Sean McGivern

Merge branch '3731-eeu-license' into 'master'

Add epics to EEU license

Closes #3731

See merge request gitlab-org/gitlab-ee!3387
parents 88fd9dcc bbd441bd
- issues = IssuesFinder.new(current_user, group_id: @group.id, state: 'opened').execute
- merge_requests = MergeRequestsFinder.new(current_user, group_id: @group.id, state: 'opened', non_archived: true).execute
- epics = EpicsFinder.new(current_user, group_id: @group.id).execute
- epics_items = ['epics#show', 'epics#index']
- issues_sub_menu_items = ['groups#issues', 'labels#index', 'milestones#index']
- if @group.feature_available?(:group_issue_boards)
- issues_sub_menu_items.push('boards#index', 'boards#show')
......@@ -45,20 +43,8 @@
%span
Contribution Analytics
-# TODO: Add the flag check to only show epics if available
= nav_link(path: epics_items) do
= link_to group_epics_path(@group) do
.nav-icon-container
= sprite_icon('epic')
%span.nav-item-name
Epics
%span.badge.count= number_with_delimiter(epics.count)
%ul.sidebar-sub-level-items.is-fly-out-only
= nav_link(path: epics_items, html_options: { class: "fly-out-top-item" } ) do
= link_to group_epics_path(@group) do
%strong.fly-out-top-item-name
#{ _('Epics') }
%span.badge.count.epic_counter.fly-out-badge= number_with_delimiter(epics.count)
= render "layouts/nav/ee/epic_link", group: @group
= nav_link(path: issues_sub_menu_items) do
= link_to issues_group_path(@group) do
......
---
title: Introduce EEU lincese with epics as the first feature
merge_request:
author:
type: added
class Groups::EpicIssuesController < Groups::EpicsController
include IssuableLinks
before_action :check_epics_available!
skip_before_action :authorize_destroy_issuable!
before_action :authorize_admin_epic!, only: [:create, :destroy]
before_action :authorize_issue_link_association!, only: :destroy
......
......@@ -2,6 +2,7 @@ class Groups::EpicsController < Groups::ApplicationController
include IssuableActions
include IssuableCollections
before_action :check_epics_available!
before_action :epic, except: :index
before_action :set_issuables_index, only: :index
before_action :authorize_update_issuable!, only: :update
......
......@@ -52,7 +52,9 @@ class License < ActiveRecord::Base
commit_committer_check
].freeze
EEU_FEATURES = EEP_FEATURES
EEU_FEATURES = EEP_FEATURES + %i[
epics
]
# List all features available for early adopters,
# i.e. users that started using GitLab.com before
......
......@@ -5,6 +5,7 @@ module EE
prepended do
with_scope :subject
condition(:ldap_synced) { @subject.ldap_synced? }
condition(:epics_disabled) { !@subject.feature_available?(:epics) }
rule { reporter }.policy do
enable :admin_list
......@@ -46,6 +47,14 @@ module EE
rule { ldap_synced & (admin | owner) }.enable :update_group_member
rule { ldap_synced & (admin | (can_owners_manage_ldap & owner)) }.enable :override_group_member
rule { epics_disabled }.policy do
prevent :read_epic
prevent :create_epic
prevent :admin_epic
prevent :update_epic
prevent :destroy_epic
end
end
end
end
......@@ -3,6 +3,8 @@ module EpicIssues
private
def issues
return [] unless issuable&.group&.feature_available?(:epics)
issuable.issues(current_user)
end
......
- return unless group.feature_available?(:epics)
- epics = EpicsFinder.new(current_user, group_id: @group.id).execute
- epics_items = ['epics#show', 'epics#index']
= nav_link(path: epics_items) do
= link_to group_epics_path(group) do
.nav-icon-container
= sprite_icon('epic')
%span.nav-item-name
Epics
%span.badge.count= number_with_delimiter(epics.count)
%ul.sidebar-sub-level-items.is-fly-out-only
= nav_link(path: epics_items, html_options: { class: "fly-out-top-item" } ) do
= link_to group_epics_path(group) do
%strong.fly-out-top-item-name
#{ _('Epics') }
%span.badge.count.epic_counter.fly-out-badge= number_with_delimiter(epics.count)
......@@ -11,134 +11,140 @@ describe Groups::EpicIssuesController do
sign_in(user)
end
describe 'GET #index' do
let!(:epic_issues) { create(:epic_issue, epic: epic, issue: issue) }
context 'when epics feature is enabled' do
before do
group.add_developer(user)
get :index, group_id: group, epic_id: epic.to_param
end
it 'returns status 200' do
expect(response.status).to eq(200)
end
it 'returns the correct json' do
expected_result = [
{
'id' => issue.id,
'title' => issue.title,
'state' => issue.state,
'reference' => "#{project.full_path}##{issue.iid}",
'path' => "/#{project.full_path}/issues/#{issue.iid}",
'destroy_relation_path' => "/groups/#{group.full_path}/-/epics/#{epic.iid}/issues/#{epic_issues.id}"
}
]
expect(JSON.parse(response.body)).to eq(expected_result)
stub_licensed_features(epics: true)
end
end
describe 'POST #create' do
subject do
reference = [issue.to_reference(full: true)]
describe 'GET #index' do
let!(:epic_issues) { create(:epic_issue, epic: epic, issue: issue) }
post :create, group_id: group, epic_id: epic.to_param, issue_references: reference
end
context 'when user has permissions to create requested association' do
before do
group.add_developer(user)
end
it 'returns correct response for the correct issue reference' do
subject
list_service_response = EpicIssues::ListService.new(epic, user).execute
get :index, group_id: group, epic_id: epic.to_param
end
expect(response).to have_gitlab_http_status(200)
expect(json_response).to eq('message' => nil, 'issues' => list_service_response.as_json)
it 'returns status 200' do
expect(response.status).to eq(200)
end
it 'creates a new EpicIssue record' do
expect { subject }.to change { EpicIssue.count }.from(0).to(1)
it 'returns the correct json' do
expected_result = [
{
'id' => issue.id,
'title' => issue.title,
'state' => issue.state,
'reference' => "#{project.full_path}##{issue.iid}",
'path' => "/#{project.full_path}/issues/#{issue.iid}",
'destroy_relation_path' => "/groups/#{group.full_path}/-/epics/#{epic.iid}/issues/#{epic_issues.id}"
}
]
expect(JSON.parse(response.body)).to eq(expected_result)
end
end
context 'when user does not have permissions to create requested association' do
it 'returns correct response for the correct issue reference' do
subject
describe 'POST #create' do
subject do
reference = [issue.to_reference(full: true)]
expect(response).to have_gitlab_http_status(403)
post :create, group_id: group, epic_id: epic.to_param, issue_references: reference
end
it 'does not create a new EpicIssue record' do
expect { subject }.not_to change { EpicIssue.count }.from(0)
end
end
end
context 'when user has permissions to create requested association' do
before do
group.add_developer(user)
end
describe 'DELETE #destroy' do
let!(:epic_issue) { create(:epic_issue, epic: epic, issue: issue) }
it 'returns correct response for the correct issue reference' do
subject
list_service_response = EpicIssues::ListService.new(epic, user).execute
subject do
delete :destroy, group_id: group, epic_id: epic.to_param, id: epic_issue.id
end
expect(response).to have_gitlab_http_status(200)
expect(json_response).to eq('message' => nil, 'issues' => list_service_response.as_json)
end
context 'when user has permissions to detele the link' do
before do
group.add_developer(user)
it 'creates a new EpicIssue record' do
expect { subject }.to change { EpicIssue.count }.from(0).to(1)
end
end
it 'returns status 200' do
subject
context 'when user does not have permissions to create requested association' do
it 'returns correct response for the correct issue reference' do
subject
expect(response.status).to eq(200)
end
expect(response).to have_gitlab_http_status(403)
end
it 'destroys the link' do
expect { subject }.to change { EpicIssue.count }.from(1).to(0)
it 'does not create a new EpicIssue record' do
expect { subject }.not_to change { EpicIssue.count }.from(0)
end
end
end
context 'when user does not have permissions to delete the link' do
it 'returns status 404' do
subject
describe 'DELETE #destroy' do
let!(:epic_issue) { create(:epic_issue, epic: epic, issue: issue) }
expect(response.status).to eq(403)
subject do
delete :destroy, group_id: group, epic_id: epic.to_param, id: epic_issue.id
end
it 'does not destroy the link' do
expect { subject }.not_to change { EpicIssue.count }.from(1)
end
end
context 'when user has permissions to detele the link' do
before do
group.add_developer(user)
end
context 'when the epic from the association does not equal epic from the path' do
subject do
delete :destroy, group_id: group, epic_id: another_epic.to_param, id: epic_issue.id
end
it 'returns status 200' do
subject
let(:another_epic) { create(:epic, group: group) }
expect(response.status).to eq(200)
end
before do
group.add_developer(user)
it 'destroys the link' do
expect { subject }.to change { EpicIssue.count }.from(1).to(0)
end
end
it 'returns status 404' do
subject
context 'when user does not have permissions to delete the link' do
it 'returns status 404' do
subject
expect(response.status).to eq(403)
end
expect(response.status).to eq(404)
it 'does not destroy the link' do
expect { subject }.not_to change { EpicIssue.count }.from(1)
end
end
it 'does not destroy the link' do
expect { subject }.not_to change { EpicIssue.count }.from(1)
context 'when the epic from the association does not equal epic from the path' do
subject do
delete :destroy, group_id: group, epic_id: another_epic.to_param, id: epic_issue.id
end
let(:another_epic) { create(:epic, group: group) }
before do
group.add_developer(user)
end
it 'returns status 404' do
subject
expect(response.status).to eq(404)
end
it 'does not destroy the link' do
expect { subject }.not_to change { EpicIssue.count }.from(1)
end
end
end
context 'when the epic_issue record does not exists' do
it 'returns status 404' do
delete :destroy, group_id: group, epic_id: epic.to_param, id: 9999
context 'when the epic_issue record does not exists' do
it 'returns status 404' do
delete :destroy, group_id: group, epic_id: epic.to_param, id: 9999
expect(response.status).to eq(403)
expect(response.status).to eq(403)
end
end
end
end
......
......@@ -9,138 +9,172 @@ describe Groups::EpicsController do
sign_in(user)
end
describe "GET #index" do
let!(:epic_list) { create_list(:epic, 2, group: group) }
context 'when epics feature is disabled' do
shared_examples '404 status' do
it 'returns 404 status' do
subject
before do
sign_in(user)
group.add_developer(user)
expect(response).to have_gitlab_http_status(404)
end
end
it "returns index" do
get :index, group_id: group
describe 'GET #index' do
subject { get :index, group_id: group }
expect(response).to have_gitlab_http_status(200)
it_behaves_like '404 status'
end
context 'with page param' do
let(:last_page) { group.epics.page.total_pages }
describe 'GET #show' do
subject { get :show, group_id: group, id: epic.to_param }
before do
allow(Kaminari.config).to receive(:default_per_page).and_return(1)
end
it_behaves_like '404 status'
end
describe 'PUT #update' do
subject { put :update, group_id: group, id: epic.to_param }
it_behaves_like '404 status'
end
end
it 'redirects to last_page if page number is larger than number of pages' do
get :index, group_id: group, page: (last_page + 1).to_param
context 'when epics feature is enabled' do
before do
stub_licensed_features(epics: true)
end
expect(response).to redirect_to(group_epics_path(page: last_page, state: controller.params[:state], scope: controller.params[:scope]))
describe "GET #index" do
let!(:epic_list) { create_list(:epic, 2, group: group) }
before do
sign_in(user)
group.add_developer(user)
end
it 'renders the specified page' do
get :index, group_id: group, page: last_page.to_param
it "returns index" do
get :index, group_id: group
expect(assigns(:epics).current_page).to eq(last_page)
expect(response).to have_gitlab_http_status(200)
end
end
end
describe 'GET #show' do
def show_epic(format = :html)
get :show, group_id: group, id: epic.to_param, format: format
end
context 'with page param' do
let(:last_page) { group.epics.page.total_pages }
context 'when format is HTML' do
it 'renders template' do
group.add_developer(user)
show_epic
before do
allow(Kaminari.config).to receive(:default_per_page).and_return(1)
end
it 'redirects to last_page if page number is larger than number of pages' do
get :index, group_id: group, page: (last_page + 1).to_param
expect(response).to redirect_to(group_epics_path(page: last_page, state: controller.params[:state], scope: controller.params[:scope]))
end
expect(response.content_type).to eq 'text/html'
expect(response).to render_template 'groups/epics/show'
it 'renders the specified page' do
get :index, group_id: group, page: last_page.to_param
expect(assigns(:epics).current_page).to eq(last_page)
expect(response).to have_gitlab_http_status(200)
end
end
end
context 'with unauthorized user' do
it 'returns a not found 404 response' do
describe 'GET #show' do
def show_epic(format = :html)
get :show, group_id: group, id: epic.to_param, format: format
end
context 'when format is HTML' do
it 'renders template' do
group.add_developer(user)
show_epic
expect(response).to have_http_status(404)
expect(response.content_type).to eq 'text/html'
expect(response).to render_template 'groups/epics/show'
end
end
end
context 'when format is JSON' do
it 'returns epic' do
group.add_developer(user)
show_epic(:json)
context 'with unauthorized user' do
it 'returns a not found 404 response' do
show_epic
expect(response).to have_http_status(200)
expect(response).to match_response_schema('entities/epic')
expect(response).to have_http_status(404)
expect(response.content_type).to eq 'text/html'
end
end
end
context 'with unauthorized user' do
it 'returns a not found 404 response' do
context 'when format is JSON' do
it 'returns epic' do
group.add_developer(user)
show_epic(:json)
expect(response).to have_http_status(404)
expect(response.content_type).to eq 'application/json'
expect(response).to have_http_status(200)
expect(response).to match_response_schema('entities/epic')
end
end
end
end
describe 'PUT #update' do
before do
group.add_developer(user)
put :update, group_id: group, id: epic.to_param, epic: { title: 'New title' }, format: :json
end
context 'with unauthorized user' do
it 'returns a not found 404 response' do
show_epic(:json)
it 'returns status 200' do
expect(response.status).to eq(200)
expect(response).to have_http_status(404)
expect(response.content_type).to eq 'application/json'
end
end
end
end
it 'updates the epic correctly' do
expect(epic.reload.title).to eq('New title')
end
end
describe 'PUT #update' do
before do
group.add_developer(user)
put :update, group_id: group, id: epic.to_param, epic: { title: 'New title' }, format: :json
end
describe 'GET #realtime_changes' do
subject { get :realtime_changes, group_id: group, id: epic.to_param }
it 'returns epic' do
group.add_developer(user)
subject
it 'returns status 200' do
expect(response.status).to eq(200)
end
expect(response.content_type).to eq 'application/json'
expect(JSON.parse(response.body)).to include('title_text', 'title', 'description', 'description_text')
it 'updates the epic correctly' do
expect(epic.reload.title).to eq('New title')
end
end
context 'with unauthorized user' do
it 'returns a not found 404 response' do
describe 'GET #realtime_changes' do
subject { get :realtime_changes, group_id: group, id: epic.to_param }
it 'returns epic' do
group.add_developer(user)
subject
expect(response).to have_http_status(404)
expect(response.content_type).to eq 'application/json'
expect(JSON.parse(response.body)).to include('title_text', 'title', 'description', 'description_text')
end
end
end
describe "DELETE #destroy" do
before do
sign_in(user)
context 'with unauthorized user' do
it 'returns a not found 404 response' do
subject
expect(response).to have_http_status(404)
end
end
end
it "rejects a developer to destroy an epic" do
group.add_developer(user)
delete :destroy, group_id: group, id: epic.to_param
describe "DELETE #destroy" do
before do
sign_in(user)
end
expect(response).to have_gitlab_http_status(404)
end
it "rejects a developer to destroy an epic" do
group.add_developer(user)
delete :destroy, group_id: group, id: epic.to_param
expect(response).to have_gitlab_http_status(404)
end
it "deletes the epic" do
group.add_owner(user)
delete :destroy, group_id: group, id: epic.to_param
it "deletes the epic" do
group.add_owner(user)
delete :destroy, group_id: group, id: epic.to_param
expect(response).to have_gitlab_http_status(302)
expect(controller).to set_flash[:notice].to(/The epic was successfully deleted\./)
expect(response).to have_gitlab_http_status(302)
expect(controller).to set_flash[:notice].to(/The epic was successfully deleted\./)
end
end
end
end
......@@ -7,6 +7,8 @@ feature 'Delete Epic', :js do
let!(:epic2) { create(:epic, group: group) }
before do
stub_licensed_features(epics: true)
sign_in(user)
end
......
......@@ -17,6 +17,8 @@ describe 'Epic Issues', :js do
end
def visit_epic
stub_licensed_features(epics: true)
sign_in(user)
visit group_epic_path(group, epic)
wait_for_requests
......
......@@ -5,6 +5,8 @@ describe 'epics list', :js do
let(:user) { create(:user) }
before do
stub_licensed_features(epics: true)
sign_in(user)
end
......
......@@ -6,6 +6,8 @@ feature 'Update Epic', :js do
let(:epic) { create(:epic, group: group) }
before do
stub_licensed_features(epics: true)
sign_in(user)
end
......
......@@ -17,56 +17,72 @@ describe EpicsFinder do
described_class.new(search_user, params).execute
end
context 'without param' do
it 'raises an error when group_id param is missing' do
expect { described_class.new(search_user).execute }.to raise_error { ArgumentError }
context 'when epics feature is disabled' do
before do
group.add_developer(search_user)
end
end
context 'when user can not read epics of a group' do
it 'raises an error when group_id param is missing' do
expect { epics }.to raise_error { ArgumentError }
it 'raises an exception' do
expect { described_class.new(search_user).execute }.to raise_error { ArgumentError }
end
end
context 'wtih correct params' do
context 'when epics feature is enabled' do
before do
group.add_developer(search_user)
stub_licensed_features(epics: true)
end
it 'returns all epics that belong to the given group' do
expect(epics).to contain_exactly(epic1, epic2, epic3)
context 'without param' do
it 'raises an error when group_id param is missing' do
expect { described_class.new(search_user).execute }.to raise_error { ArgumentError }
end
end
context 'by created_at' do
it 'returns all epics created before the given date' do
expect(epics(created_before: 2.days.ago)).to contain_exactly(epic1, epic2)
context 'when user can not read epics of a group' do
it 'raises an error when group_id param is missing' do
expect { epics }.to raise_error { ArgumentError }
end
end
it 'returns all epics created after the given date' do
expect(epics(created_after: 2.days.ago)).to contain_exactly(epic3)
context 'wtih correct params' do
before do
group.add_developer(search_user)
end
it 'returns all epics created within the given interval' do
expect(epics(created_after: 5.days.ago, created_before: 1.day.ago)).to contain_exactly(epic2)
it 'returns all epics that belong to the given group' do
expect(epics).to contain_exactly(epic1, epic2, epic3)
end
end
context 'by search' do
it 'returns all epics that match the search' do
expect(epics(search: 'awesome')).to contain_exactly(epic1, epic3)
context 'by created_at' do
it 'returns all epics created before the given date' do
expect(epics(created_before: 2.days.ago)).to contain_exactly(epic1, epic2)
end
it 'returns all epics created after the given date' do
expect(epics(created_after: 2.days.ago)).to contain_exactly(epic3)
end
it 'returns all epics created within the given interval' do
expect(epics(created_after: 5.days.ago, created_before: 1.day.ago)).to contain_exactly(epic2)
end
end
end
context 'by author' do
it 'returns all epics authored by the given user' do
expect(epics(author_id: user.id)).to contain_exactly(epic2)
context 'by search' do
it 'returns all epics that match the search' do
expect(epics(search: 'awesome')).to contain_exactly(epic1, epic3)
end
end
context 'by author' do
it 'returns all epics authored by the given user' do
expect(epics(author_id: user.id)).to contain_exactly(epic2)
end
end
end
context 'by iids' do
it 'returns all epics by the given iids' do
expect(epics(iids: [epic1.iid, epic3.iid])).to contain_exactly(epic1, epic3)
context 'by iids' do
it 'returns all epics by the given iids' do
expect(epics(iids: [epic1.iid, epic3.iid])).to contain_exactly(epic1, epic3)
end
end
end
end
......
......@@ -9,111 +9,128 @@ describe EpicPolicy do
described_class.new(user, epic)
end
context 'when an epic is in a private group' do
let(:group) { create(:group, :private) }
context 'when epics feature is disabled' do
let(:group) { create(:group, :public) }
it 'anonymous user can not read epics' do
expect(permissions(nil, group))
.to be_disallowed(:read_epic, :update_epic, :destroy_epic, :admin_epic, :create_epic)
end
it 'no one can read epics' do
group.add_owner(user)
it 'user who is not a group member can not read epics' do
expect(permissions(user, group))
.to be_disallowed(:read_epic, :update_epic, :destroy_epic, :admin_epic, :create_epic)
end
end
it 'guest group member can only read epics' do
group.add_guest(user)
expect(permissions(user, group)).to be_allowed(:read_epic)
expect(permissions(user, group)).to be_disallowed(:update_epic, :destroy_epic, :admin_epic, :create_epic)
context 'when epics feature is enabled' do
before do
stub_licensed_features(epics: true)
end
it 'reporter group member can manage epics' do
group.add_reporter(user)
context 'when an epic is in a private group' do
let(:group) { create(:group, :private) }
expect(permissions(user, group)).to be_disallowed(:destroy_epic)
expect(permissions(user, group))
.to be_allowed(:read_epic, :update_epic, :admin_epic, :create_epic)
end
it 'anonymous user can not read epics' do
expect(permissions(nil, group))
.to be_disallowed(:read_epic, :update_epic, :destroy_epic, :admin_epic, :create_epic)
end
it 'only group owner can destroy epics' do
group.add_owner(user)
it 'user who is not a group member can not read epics' do
expect(permissions(user, group))
.to be_disallowed(:read_epic, :update_epic, :destroy_epic, :admin_epic, :create_epic)
end
expect(permissions(user, group))
.to be_allowed(:read_epic, :update_epic, :destroy_epic, :admin_epic, :create_epic)
end
end
it 'guest group member can only read epics' do
group.add_guest(user)
context 'when an epic is in an internal group' do
let(:group) { create(:group, :internal) }
expect(permissions(user, group)).to be_allowed(:read_epic)
expect(permissions(user, group)).to be_disallowed(:update_epic, :destroy_epic, :admin_epic, :create_epic)
end
it 'anonymous user can not read epics' do
expect(permissions(nil, group))
.to be_disallowed(:read_epic, :update_epic, :destroy_epic, :admin_epic, :create_epic)
end
it 'reporter group member can manage epics' do
group.add_reporter(user)
it 'user who is not a group member can only read epics' do
expect(permissions(user, group)).to be_allowed(:read_epic)
expect(permissions(user, group)).to be_disallowed(:update_epic, :destroy_epic, :admin_epic, :create_epic)
end
expect(permissions(user, group)).to be_disallowed(:destroy_epic)
expect(permissions(user, group))
.to be_allowed(:read_epic, :update_epic, :admin_epic, :create_epic)
end
it 'guest group member can only read epics' do
group.add_guest(user)
it 'only group owner can destroy epics' do
group.add_owner(user)
expect(permissions(user, group)).to be_allowed(:read_epic)
expect(permissions(user, group)).to be_disallowed(:update_epic, :destroy_epic, :admin_epic, :create_epic)
expect(permissions(user, group))
.to be_allowed(:read_epic, :update_epic, :destroy_epic, :admin_epic, :create_epic)
end
end
it 'reporter group member can manage epics' do
group.add_reporter(user)
context 'when an epic is in an internal group' do
let(:group) { create(:group, :internal) }
expect(permissions(user, group)).to be_disallowed(:destroy_epic)
expect(permissions(user, group))
.to be_allowed(:read_epic, :update_epic, :admin_epic, :create_epic)
end
it 'anonymous user can not read epics' do
expect(permissions(nil, group))
.to be_disallowed(:read_epic, :update_epic, :destroy_epic, :admin_epic, :create_epic)
end
it 'only group owner can destroy epics' do
group.add_owner(user)
it 'user who is not a group member can only read epics' do
expect(permissions(user, group)).to be_allowed(:read_epic)
expect(permissions(user, group)).to be_disallowed(:update_epic, :destroy_epic, :admin_epic, :create_epic)
end
expect(permissions(user, group))
.to be_allowed(:read_epic, :update_epic, :destroy_epic, :admin_epic, :create_epic)
end
end
it 'guest group member can only read epics' do
group.add_guest(user)
context 'when an epic is in a public group' do
let(:group) { create(:group, :public) }
expect(permissions(user, group)).to be_allowed(:read_epic)
expect(permissions(user, group)).to be_disallowed(:update_epic, :destroy_epic, :admin_epic, :create_epic)
end
it 'anonymous user can only read epics' do
expect(permissions(nil, group)).to be_allowed(:read_epic)
expect(permissions(nil, group)).to be_disallowed(:update_epic, :destroy_epic, :admin_epic, :create_epic)
end
it 'reporter group member can manage epics' do
group.add_reporter(user)
it 'user who is not a group member can only read epics' do
expect(permissions(user, group)).to be_allowed(:read_epic)
expect(permissions(user, group)).to be_disallowed(:update_epic, :destroy_epic, :admin_epic, :create_epic)
end
expect(permissions(user, group)).to be_disallowed(:destroy_epic)
expect(permissions(user, group))
.to be_allowed(:read_epic, :update_epic, :admin_epic, :create_epic)
end
it 'guest group member can only read epics' do
group.add_guest(user)
it 'only group owner can destroy epics' do
group.add_owner(user)
expect(permissions(user, group)).to be_allowed(:read_epic)
expect(permissions(user, group)).to be_disallowed(:update_epic, :destroy_epic, :admin_epic, :create_epic)
expect(permissions(user, group))
.to be_allowed(:read_epic, :update_epic, :destroy_epic, :admin_epic, :create_epic)
end
end
it 'reporter group member can manage epics' do
group.add_reporter(user)
context 'when an epic is in a public group' do
let(:group) { create(:group, :public) }
expect(permissions(user, group)).to be_disallowed(:destroy_epic)
expect(permissions(user, group))
.to be_allowed(:read_epic, :update_epic, :admin_epic, :create_epic)
end
it 'anonymous user can only read epics' do
expect(permissions(nil, group)).to be_allowed(:read_epic)
expect(permissions(nil, group)).to be_disallowed(:update_epic, :destroy_epic, :admin_epic, :create_epic)
end
it 'only group owner can destroy epics' do
group.add_owner(user)
it 'user who is not a group member can only read epics' do
expect(permissions(user, group)).to be_allowed(:read_epic)
expect(permissions(user, group)).to be_disallowed(:update_epic, :destroy_epic, :admin_epic, :create_epic)
end
expect(permissions(user, group))
.to be_allowed(:read_epic, :update_epic, :destroy_epic, :admin_epic, :create_epic)
it 'guest group member can only read epics' do
group.add_guest(user)
expect(permissions(user, group)).to be_allowed(:read_epic)
expect(permissions(user, group)).to be_disallowed(:update_epic, :destroy_epic, :admin_epic, :create_epic)
end
it 'reporter group member can manage epics' do
group.add_reporter(user)
expect(permissions(user, group)).to be_disallowed(:destroy_epic)
expect(permissions(user, group))
.to be_allowed(:read_epic, :update_epic, :admin_epic, :create_epic)
end
it 'only group owner can destroy epics' do
group.add_owner(user)
expect(permissions(user, group))
.to be_allowed(:read_epic, :update_epic, :destroy_epic, :admin_epic, :create_epic)
end
end
end
end
......@@ -20,6 +20,22 @@ describe GroupPolicy do
subject { described_class.new(current_user, group) }
context 'when epics feature is disabled' do
let(:current_user) { owner }
it { is_expected.to be_disallowed(:read_epic, :create_epic, :admin_epic, :destroy_epic) }
end
context 'when epics feature is enabled' do
before do
stub_licensed_features(epics: true)
end
let(:current_user) { owner }
it { is_expected.to be_allowed(:read_epic, :create_epic, :admin_epic, :destroy_epic) }
end
context 'when LDAP sync is not enabled' do
context 'owner' do
let(:current_user) { owner }
......
......@@ -37,98 +37,110 @@ describe EpicIssues::CreateService do
end
end
context 'when user has permissions to link the issue' do
context 'when epics feature is disabled' do
subject { assign_issue([valid_reference]) }
include_examples 'returns an error'
end
context 'when epics feature is enabled' do
before do
group.add_developer(user)
stub_licensed_features(epics: true)
end
context 'when the reference list is empty' do
it 'returns an error' do
expect(assign_issue([])).to eq(message: 'No Issue found for given params', status: :error, http_status: 404)
context 'when user has permissions to link the issue' do
before do
group.add_developer(user)
end
end
context 'when there is an issue to relate' do
context 'when shortcut for Issue is given' do
subject { assign_issue([issue.to_reference]) }
include_examples 'returns an error'
context 'when the reference list is empty' do
it 'returns an error' do
expect(assign_issue([])).to eq(message: 'No Issue found for given params', status: :error, http_status: 404)
end
end
context 'when a full reference is given' do
subject { assign_issue([valid_reference]) }
context 'when there is an issue to relate' do
context 'when shortcut for Issue is given' do
subject { assign_issue([issue.to_reference]) }
include_examples 'returns an error'
end
context 'when a full reference is given' do
subject { assign_issue([valid_reference]) }
include_examples 'returns success'
include_examples 'returns success'
it 'does not perofrm N + 1 queries' do
params = { issue_references: [valid_reference] }
control_count = ActiveRecord::QueryRecorder.new { described_class.new(epic, user, params).execute }.count
it 'does not perofrm N + 1 queries' do
params = { issue_references: [valid_reference] }
control_count = ActiveRecord::QueryRecorder.new { described_class.new(epic, user, params).execute }.count
user = create(:user)
group = create(:group)
project = create(:project, group: group)
issues = create_list(:issue, 5, project: project)
epic = create(:epic, group: group)
group.add_developer(user)
user = create(:user)
group = create(:group)
project = create(:project, group: group)
issues = create_list(:issue, 5, project: project)
epic = create(:epic, group: group)
group.add_developer(user)
params = { issue_references: issues.map { |i| i.to_reference(full: true) } }
params = { issue_references: issues.map { |i| i.to_reference(full: true) } }
expect { described_class.new(epic, user, params).execute }.not_to exceed_query_limit(control_count)
expect { described_class.new(epic, user, params).execute }.not_to exceed_query_limit(control_count)
end
end
end
context 'when an issue links is given' do
subject { assign_issue([IssuesHelper.url_for_issue(issue.iid, issue.project)]) }
context 'when an issue links is given' do
subject { assign_issue([IssuesHelper.url_for_issue(issue.iid, issue.project)]) }
include_examples 'returns success'
include_examples 'returns success'
end
end
end
end
context 'when user does not have permissions to link the issue' do
subject { assign_issue([valid_reference]) }
include_examples 'returns an error'
end
context 'when user does not have permissions to link the issue' do
subject { assign_issue([valid_reference]) }
context 'when an issue is already assigned to another epic' do
before do
group.add_developer(user)
create(:epic_issue, epic: epic, issue: issue)
include_examples 'returns an error'
end
let(:another_epic) { create(:epic, group: group) }
context 'when an issue is already assigned to another epic' do
before do
group.add_developer(user)
create(:epic_issue, epic: epic, issue: issue)
end
subject do
params = { issue_references: [valid_reference] }
let(:another_epic) { create(:epic, group: group) }
described_class.new(another_epic, user, params).execute
end
subject do
params = { issue_references: [valid_reference] }
it 'does not create a new association' do
expect { subject }.not_to change(EpicIssue, :count).from(1)
end
described_class.new(another_epic, user, params).execute
end
it 'updates the existing association' do
expect { subject }.to change { EpicIssue.last.epic }.from(epic).to(another_epic)
end
it 'does not create a new association' do
expect { subject }.not_to change(EpicIssue, :count).from(1)
end
it 'returns success status' do
is_expected.to eq(status: :success)
it 'updates the existing association' do
expect { subject }.to change { EpicIssue.last.epic }.from(epic).to(another_epic)
end
it 'returns success status' do
is_expected.to eq(status: :success)
end
end
end
context 'when issue from non group project is given' do
subject { assign_issue([another_issue.to_reference(full: true)]) }
context 'when issue from non group project is given' do
subject { assign_issue([another_issue.to_reference(full: true)]) }
let(:another_issue) { create :issue }
let(:another_issue) { create :issue }
before do
group.add_developer(user)
another_issue.project.add_developer(user)
end
before do
group.add_developer(user)
another_issue.project.add_developer(user)
end
include_examples 'returns an error'
include_examples 'returns an error'
end
end
end
end
......@@ -11,27 +11,43 @@ describe EpicIssues::DestroyService do
subject { described_class.new(epic_issue, user).execute }
context 'when user has permissions to remove associations' do
context 'when epics feature is disabled' do
before do
group.add_reporter(user)
end
it 'removes related issue' do
expect { subject }.to change { EpicIssue.count }.from(1).to(0)
it 'returns an error' do
is_expected.to eq(message: 'No Issue Link found', status: :error, http_status: 404)
end
end
it 'returns success message' do
is_expected.to eq(message: 'Relation was removed', status: :success)
context 'when epics feature is enabled' do
before do
stub_licensed_features(epics: true)
end
end
context 'user does not have permissions to remove associations' do
it 'does not remove relation' do
expect { subject }.not_to change { EpicIssue.count }.from(1)
context 'when user has permissions to remove associations' do
before do
group.add_reporter(user)
end
it 'removes related issue' do
expect { subject }.to change { EpicIssue.count }.from(1).to(0)
end
it 'returns success message' do
is_expected.to eq(message: 'Relation was removed', status: :success)
end
end
it 'returns error message' do
is_expected.to eq(message: 'No Issue Link found', status: :error, http_status: 404)
context 'user does not have permissions to remove associations' do
it 'does not remove relation' do
expect { subject }.not_to change { EpicIssue.count }.from(1)
end
it 'returns error message' do
is_expected.to eq(message: 'No Issue Link found', status: :error, http_status: 404)
end
end
end
end
......
......@@ -18,69 +18,82 @@ describe EpicIssues::ListService do
describe '#execute' do
subject { described_class.new(epic, user).execute }
context 'user can see all issues and destroy their associations' do
before do
context 'when epics feature is disabled' do
it 'returns an empty array' do
group.add_developer(user)
end
it 'returns related issues JSON' do
expected_result = [
{
id: issue1.id,
title: issue1.title,
state: issue1.state,
reference: issue1.to_reference(full: true),
path: "/#{project.full_path}/issues/#{issue1.iid}",
destroy_relation_path: "/groups/#{group.full_path}/-/epics/#{epic.iid}/issues/#{epic_issue1.id}"
},
{
id: issue2.id,
title: issue2.title,
state: issue2.state,
reference: issue2.to_reference(full: true),
path: "/#{project.full_path}/issues/#{issue2.iid}",
destroy_relation_path: "/groups/#{group.full_path}/-/epics/#{epic.iid}/issues/#{epic_issue2.id}"
},
{
id: issue3.id,
title: issue3.title,
state: issue3.state,
reference: issue3.to_reference(full: true),
path: "/#{other_project.full_path}/issues/#{issue3.iid}",
destroy_relation_path: "/groups/#{group.full_path}/-/epics/#{epic.iid}/issues/#{epic_issue3.id}"
}
]
expect(subject).to match_array(expected_result)
expect(subject).to be_empty
end
end
context 'user can see only some issues' do
context 'when epics feature is enabled' do
before do
project.add_developer(user)
stub_licensed_features(epics: true)
end
it 'returns related issues JSON' do
expected_result = [
{
id: issue1.id,
title: issue1.title,
state: issue1.state,
reference: issue1.to_reference(full: true),
path: "/#{project.full_path}/issues/#{issue1.iid}",
destroy_relation_path: nil
},
{
id: issue2.id,
title: issue2.title,
state: issue2.state,
reference: issue2.to_reference(full: true),
path: "/#{project.full_path}/issues/#{issue2.iid}",
destroy_relation_path: nil
}
]
context 'owner can see all issues and destroy their associations' do
before do
group.add_developer(user)
end
it 'returns related issues JSON' do
expected_result = [
{
id: issue1.id,
title: issue1.title,
state: issue1.state,
reference: issue1.to_reference(full: true),
path: "/#{project.full_path}/issues/#{issue1.iid}",
destroy_relation_path: "/groups/#{group.full_path}/-/epics/#{epic.iid}/issues/#{epic_issue1.id}"
},
{
id: issue2.id,
title: issue2.title,
state: issue2.state,
reference: issue2.to_reference(full: true),
path: "/#{project.full_path}/issues/#{issue2.iid}",
destroy_relation_path: "/groups/#{group.full_path}/-/epics/#{epic.iid}/issues/#{epic_issue2.id}"
},
{
id: issue3.id,
title: issue3.title,
state: issue3.state,
reference: issue3.to_reference(full: true),
path: "/#{other_project.full_path}/issues/#{issue3.iid}",
destroy_relation_path: "/groups/#{group.full_path}/-/epics/#{epic.iid}/issues/#{epic_issue3.id}"
}
]
expect(subject).to match_array(expected_result)
end
end
context 'user can see only some issues' do
before do
project.add_developer(user)
end
it 'returns related issues JSON' do
expected_result = [
{
id: issue1.id,
title: issue1.title,
state: issue1.state,
reference: issue1.to_reference(full: true),
path: "/#{project.full_path}/issues/#{issue1.iid}",
destroy_relation_path: nil
},
{
id: issue2.id,
title: issue2.title,
state: issue2.state,
reference: issue2.to_reference(full: true),
path: "/#{project.full_path}/issues/#{issue2.iid}",
destroy_relation_path: nil
}
]
expect(subject).to match_array(expected_result)
expect(subject).to match_array(expected_result)
end
end
end
end
......
......@@ -10,7 +10,7 @@ describe GroupPolicy do
let(:admin) { create(:admin) }
let(:group) { create(:group) }
let(:reporter_permissions) { [:admin_label, :create_epic, :admin_epic] }
let(:reporter_permissions) { [:admin_label] }
let(:developer_permissions) { [:admin_milestones] }
......@@ -26,7 +26,6 @@ describe GroupPolicy do
:admin_namespace,
:admin_group_member,
:change_visibility_level,
:destroy_epic,
(Gitlab::Database.postgresql? ? :create_subgroup : nil)
].compact
end
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment