Commit 13fc0efa authored by Felipe Artur's avatar Felipe Artur Committed by Michael Kozono

Let project reporters create issue from group boards

The current state of group issue boards does not show the "Add issues"
button on the UI for users that are reporters of group child projects.
parent 24de5d65
......@@ -114,7 +114,7 @@ export default {
name="issue_title"
autocomplete="off"
/>
<project-select v-if="groupId" :group-id="groupId" />
<project-select v-if="groupId" :group-id="groupId" :list="list" />
<div class="clearfix prepend-top-10">
<gl-button
ref="submit-button"
......
......@@ -6,6 +6,7 @@ import Icon from '~/vue_shared/components/icon.vue';
import { GlLoadingIcon } from '@gitlab/ui';
import eventHub from '../eventhub';
import Api from '../../api';
import { featureAccessLevel } from '~/pages/projects/shared/permissions/constants';
export default {
name: 'BoardProjectSelect',
......@@ -19,6 +20,10 @@ export default {
required: true,
default: 0,
},
list: {
type: Object,
required: true,
},
},
data() {
return {
......@@ -49,6 +54,12 @@ export default {
selectable: true,
data: (term, callback) => {
this.loading = true;
const additionalAttrs = {};
if (this.list.type && this.list.type !== 'backlog') {
additionalAttrs.min_access_level = featureAccessLevel.EVERYONE;
}
return Api.groupProjects(
this.groupId,
term,
......@@ -56,6 +67,7 @@ export default {
with_issues_enabled: true,
with_shared: false,
include_subgroups: true,
...additionalAttrs,
},
projects => {
this.loading = false;
......
......@@ -16,7 +16,7 @@ export const visibilityLevelDescriptions = {
),
};
const featureAccessLevel = {
export const featureAccessLevel = {
NOT_ENABLED: 0,
PROJECT_MEMBERS: 10,
EVERYONE: 20,
......
......@@ -10,7 +10,7 @@ module BoardsHelper
boards_endpoint: @boards_endpoint,
lists_endpoint: board_lists_path(board),
board_id: board.id,
disabled: "#{!can?(current_user, :admin_list, current_board_parent)}",
disabled: (!can?(current_user, :create_non_backlog_issues, board)).to_s,
issue_link_base: build_issue_link_base,
root_path: root_path,
bulk_update_path: @bulk_issues_path,
......
# frozen_string_literal: true
class BoardPolicy < BasePolicy
include FindGroupProjects
delegate { @subject.parent }
condition(:is_group_board) { @subject.group_board? }
......@@ -13,4 +15,20 @@ class BoardPolicy < BasePolicy
enable :read_milestone
enable :read_issue
end
condition(:reporter_of_group_projects) do
next unless @user
group_projects_for(user: @user, group: @subject.parent)
.visible_to_user_and_access_level(@user, ::Gitlab::Access::REPORTER)
.exists?
end
rule { is_group_board & reporter_of_group_projects }.policy do
enable :create_non_backlog_issues
end
rule { is_project_board & can?(:admin_issue) }.policy do
enable :create_non_backlog_issues
end
end
# frozen_string_literal: true
module FindGroupProjects
extend ActiveSupport::Concern
def group_projects_for(user:, group:)
GroupProjectsFinder.new(
group: group,
current_user: user,
options: { include_subgroups: true, only_owned: true }
).execute
end
end
# frozen_string_literal: true
class GroupPolicy < BasePolicy
include FindGroupProjects
desc "Group is public"
with_options scope: :subject, score: 0
condition(:public_group) { @subject.public? }
......@@ -22,7 +24,7 @@ class GroupPolicy < BasePolicy
condition(:can_change_parent_share_with_group_lock) { can?(:change_share_with_group_lock, @subject.parent) }
condition(:has_projects) do
GroupProjectsFinder.new(group: @subject, current_user: @user, options: { include_subgroups: true, only_owned: true }).execute.any?
group_projects_for(user: @user, group: @subject).any?
end
with_options scope: :subject, score: 0
......
---
title: Let project reporters create issue from group boards
merge_request: 29866
author:
type: fixed
......@@ -157,6 +157,7 @@ Parameters:
| `with_merge_requests_enabled` | boolean | no | Limit by projects with merge requests feature enabled. Default is `false` |
| `with_shared` | boolean | no | Include projects shared to this group. Default is `true` |
| `include_subgroups` | boolean | no | Include projects in subgroups of this group. Default is `false` |
| `min_access_level` | integer | no | Limit to projects where current user has at least this [access level](members.md) |
| `with_custom_attributes` | boolean | no | Include [custom attributes](custom_attributes.md) in response (admins only) |
| `with_security_reports` | boolean | no | **(ULTIMATE)** Return only projects that have security reports artifacts present in any of their builds. This means "projects with security reports enabled". Default is `false` |
......
......@@ -75,6 +75,7 @@ module API
).execute
projects = projects.with_issues_available_for_user(current_user) if params[:with_issues_enabled]
projects = projects.with_merge_requests_enabled if params[:with_merge_requests_enabled]
projects = projects.visible_to_user_and_access_level(current_user, params[:min_access_level]) if params[:min_access_level]
projects = reorder_projects(projects)
paginate(projects)
end
......@@ -213,6 +214,7 @@ module API
optional :with_merge_requests_enabled, type: Boolean, default: false, desc: 'Limit by enabled merge requests feature'
optional :with_shared, type: Boolean, default: true, desc: 'Include projects shared to this group'
optional :include_subgroups, type: Boolean, default: false, desc: 'Includes projects in subgroups of this group'
optional :min_access_level, type: Integer, values: Gitlab::Access.all_values, desc: 'Limit by minimum access level of authenticated user on projects'
use :pagination
use :with_custom_attributes
......
......@@ -127,4 +127,44 @@ describe 'Issue Boards new issue', :js do
end
end
end
context 'group boards' do
set(:group) { create(:group, :public) }
set(:project) { create(:project, namespace: group) }
set(:group_board) { create(:board, group: group) }
set(:list) { create(:list, board: group_board, position: 0) }
context 'for unauthorized users' do
before do
sign_in(user)
visit group_board_path(group, group_board)
wait_for_requests
end
it 'displays new issue button in open list' do
expect(first('.board')).to have_selector('.issue-count-badge-add-button', count: 1)
end
it 'does not display new issue button in label list' do
page.within('.board.is-draggable') do
expect(page).not_to have_selector('.issue-count-badge-add-button')
end
end
end
context 'for authorized users' do
it 'display new issue button in label list' do
project = create(:project, namespace: group)
project.add_reporter(user)
sign_in(user)
visit group_board_path(group, group_board)
wait_for_requests
page.within('.board.is-draggable') do
expect(page).to have_selector('.issue-count-badge-add-button')
end
end
end
end
end
......@@ -40,7 +40,7 @@ describe BoardsHelper do
assign(:project, project)
allow(helper).to receive(:current_user) { user }
allow(helper).to receive(:can?).with(user, :admin_list, project).and_return(true)
allow(helper).to receive(:can?).with(user, :create_non_backlog_issues, board).and_return(true)
end
it 'returns a board_lists_path as lists_endpoint' do
......
......@@ -56,4 +56,57 @@ describe BoardPolicy do
end
end
end
context 'create_non_backlog_issues' do
context 'for project boards' do
let!(:current_user) { create(:user) }
subject { described_class.new(current_user, project_board) }
context 'when user can admin project issues' do
it 'allows to add non backlog issues from issue board' do
project.add_reporter(current_user)
expect_allowed(:create_non_backlog_issues)
end
end
context 'when user cannot admin project issues' do
it 'does not allow to add non backlog issues from issue board' do
project.add_guest(current_user)
expect_disallowed(:create_non_backlog_issues)
end
end
end
context 'for group boards' do
let!(:current_user) { create(:user) }
let!(:project_1) { create(:project, namespace: group) }
let!(:project_2) { create(:project, namespace: group) }
let!(:group_board) { create(:board, group: group) }
subject { described_class.new(current_user, group_board) }
before do
project_1.add_guest(current_user)
end
context 'when user is at least reporter in one of the child projects' do
it 'allows to add non backlog issues from issue board' do
project_2.add_reporter(current_user)
expect_allowed(:create_non_backlog_issues)
end
end
context 'when user is not a reporter from any child projects' do
it 'does not allow to add non backlog issues from issue board' do
project_2.add_guest(current_user)
expect_disallowed(:create_non_backlog_issues)
end
end
end
end
end
......@@ -483,6 +483,22 @@ describe API::Groups do
describe "GET /groups/:id/projects" do
context "when authenticated as user" do
context 'with min access level' do
it 'returns projects with min access level or higher' do
group_guest = create(:user)
group1.add_guest(group_guest)
project4 = create(:project, group: group1)
project1.add_guest(group_guest)
project3.add_reporter(group_guest)
project4.add_developer(group_guest)
get api("/groups/#{group1.id}/projects", group_guest), params: { min_access_level: Gitlab::Access::REPORTER }
project_ids = json_response.map { |proj| proj['id'] }
expect(project_ids).to match_array([project3.id, project4.id])
end
end
it "returns the group's projects" do
get api("/groups/#{group1.id}/projects", user1)
......
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