Commit 727a2a86 authored by Jarka Košanová's avatar Jarka Košanová

Display only informaton visible to current user

Display only labels and assignees of issues
visible by the currently logged user
Display only issues visible to user in the burndown chart
parent 3132550d
...@@ -53,6 +53,18 @@ module Milestoneish ...@@ -53,6 +53,18 @@ module Milestoneish
end end
end end
def issue_participants_visible_by_user(user)
User.joins(:issue_assignees)
.where('issue_assignees.issue_id' => issues_visible_to_user(user).select(:id))
.distinct
end
def issue_labels_visible_by_user(user)
Label.joins(:label_links)
.where('label_links.target_id' => issues_visible_to_user(user).select(:id), 'label_links.target_type' => 'Issue')
.distinct
end
def sorted_issues(user) def sorted_issues(user)
issues_visible_to_user(user).preload_associations.sort_by_attribute('label_priority') issues_visible_to_user(user).preload_associations.sort_by_attribute('label_priority')
end end
......
...@@ -21,11 +21,11 @@ ...@@ -21,11 +21,11 @@
%li.nav-item %li.nav-item
= link_to '#tab-participants', class: 'nav-link', 'data-toggle' => 'tab', 'data-endpoint': milestone_participants_tab_path(milestone) do = link_to '#tab-participants', class: 'nav-link', 'data-toggle' => 'tab', 'data-endpoint': milestone_participants_tab_path(milestone) do
Participants Participants
%span.badge.badge-pill= milestone.participants.count %span.badge.badge-pill= milestone.issue_participants_visible_by_user(current_user).count
%li.nav-item %li.nav-item
= link_to '#tab-labels', class: 'nav-link', 'data-toggle' => 'tab', 'data-endpoint': milestone_labels_tab_path(milestone) do = link_to '#tab-labels', class: 'nav-link', 'data-toggle' => 'tab', 'data-endpoint': milestone_labels_tab_path(milestone) do
Labels Labels
%span.badge.badge-pill= milestone.labels.count %span.badge.badge-pill= milestone.issue_labels_visible_by_user(current_user).count
- issues = milestone.sorted_issues(current_user) - issues = milestone.sorted_issues(current_user)
- show_project_name = local_assigns.fetch(:show_project_name, false) - show_project_name = local_assigns.fetch(:show_project_name, false)
......
---
title: Display only information visible to current user on the Milestone page
merge_request:
author:
type: security
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
module EE module EE
module MilestonesHelper module MilestonesHelper
def burndown_chart(milestone) def burndown_chart(milestone)
Burndown.new(milestone) if milestone.supports_burndown_charts? Burndown.new(milestone, current_user) if milestone.supports_burndown_charts?
end end
def can_generate_chart?(milestone, burndown) def can_generate_chart?(milestone, burndown)
......
...@@ -17,12 +17,13 @@ class Burndown ...@@ -17,12 +17,13 @@ class Burndown
end end
end end
attr_reader :start_date, :due_date, :end_date, :accurate, :legacy_data, :milestone attr_reader :start_date, :due_date, :end_date, :accurate, :legacy_data, :milestone, :current_user
alias_method :accurate?, :accurate alias_method :accurate?, :accurate
alias_method :empty?, :legacy_data alias_method :empty?, :legacy_data
def initialize(milestone) def initialize(milestone, current_user)
@milestone = milestone @milestone = milestone
@current_user = current_user
@start_date = @milestone.start_date @start_date = @milestone.start_date
@due_date = @milestone.due_date @due_date = @milestone.due_date
@end_date = @milestone.due_date @end_date = @milestone.due_date
...@@ -89,10 +90,10 @@ class Burndown ...@@ -89,10 +90,10 @@ class Burndown
strong_memoize(:opened_issues_grouped_by_date) do strong_memoize(:opened_issues_grouped_by_date) do
issues = issues =
@milestone @milestone
.issues .issues_visible_to_user(current_user)
.where('created_at <= ?', end_date) .where('issues.created_at <= ?', end_date)
.reorder(nil) .reorder(nil)
.order(:created_at).to_a .order('issues.created_at').to_a
issues.group_by do |issue| issues.group_by do |issue|
issue.created_at.to_date issue.created_at.to_date
...@@ -124,9 +125,8 @@ class Burndown ...@@ -124,9 +125,8 @@ class Burndown
# `issues.closed_at` can't be used once it's nullified if the issue is # `issues.closed_at` can't be used once it's nullified if the issue is
# reopened. # reopened.
internal_clause = internal_clause =
::Issue @milestone.issues_visible_to_user(current_user)
.joins("LEFT OUTER JOIN events e ON issues.id = e.target_id AND e.target_type = 'Issue' AND e.action = #{Event::CLOSED}") .joins("LEFT OUTER JOIN events e ON issues.id = e.target_id AND e.target_type = 'Issue' AND e.action = #{Event::CLOSED}")
.where(milestone: @milestone)
.where("state = 'closed' OR (state = 'opened' AND e.action = #{Event::CLOSED})") # rubocop:disable GitlabSecurity/SqlInjection .where("state = 'closed' OR (state = 'opened' AND e.action = #{Event::CLOSED})") # rubocop:disable GitlabSecurity/SqlInjection
rel = rel =
......
...@@ -2,6 +2,7 @@ require 'spec_helper' ...@@ -2,6 +2,7 @@ require 'spec_helper'
describe Burndown do describe Burndown do
set(:user) { create(:user) } set(:user) { create(:user) }
set(:non_member) { create(:user) }
let(:start_date) { "2017-03-01" } let(:start_date) { "2017-03-01" }
let(:due_date) { "2017-03-03" } let(:due_date) { "2017-03-03" }
...@@ -16,13 +17,13 @@ describe Burndown do ...@@ -16,13 +17,13 @@ describe Burndown do
end end
end end
subject { described_class.new(milestone).to_json } subject { described_class.new(milestone, user).to_json }
it "generates an array with date, issue count and weight" do it "generates an array with date, issue count and weight" do
expect(subject).to eq([ expect(subject).to eq([
["2017-03-01", 3, 6], ["2017-03-01", 4, 8],
["2017-03-02", 4, 8], ["2017-03-02", 5, 10],
["2017-03-03", 2, 4] ["2017-03-03", 3, 6]
].to_json) ].to_json)
end end
...@@ -45,7 +46,7 @@ describe Burndown do ...@@ -45,7 +46,7 @@ describe Burndown do
end end
it "sets attribute accurate to true" do it "sets attribute accurate to true" do
burndown = described_class.new(milestone) burndown = described_class.new(milestone, user)
expect(burndown).to be_accurate expect(burndown).to be_accurate
end end
...@@ -57,14 +58,14 @@ describe Burndown do ...@@ -57,14 +58,14 @@ describe Burndown do
it "considers closed_at as milestone start date" do it "considers closed_at as milestone start date" do
expect(subject).to eq([ expect(subject).to eq([
["2017-03-01", 3, 6], ["2017-03-01", 4, 8],
["2017-03-02", 3, 6], ["2017-03-02", 4, 8],
["2017-03-03", 3, 6] ["2017-03-03", 4, 8]
].to_json) ].to_json)
end end
it "sets attribute empty to true" do it "sets attribute empty to true" do
burndown = described_class.new(milestone) burndown = described_class.new(milestone, user)
expect(burndown).to be_empty expect(burndown).to be_empty
end end
...@@ -76,7 +77,7 @@ describe Burndown do ...@@ -76,7 +77,7 @@ describe Burndown do
end end
it "sets attribute accurate to false" do it "sets attribute accurate to false" do
burndown = described_class.new(milestone) burndown = described_class.new(milestone, user)
expect(burndown).not_to be_accurate expect(burndown).not_to be_accurate
end end
...@@ -92,12 +93,26 @@ describe Burndown do ...@@ -92,12 +93,26 @@ describe Burndown do
create(:issue, milestone: milestone, project: project, created_at: creation_date, weight: 3) create(:issue, milestone: milestone, project: project, created_at: creation_date, weight: 3)
expect(subject).to eq([ expect(subject).to eq([
['2017-03-01', 3, 6], ['2017-03-01', 4, 8],
['2017-03-02', 6, 13], ['2017-03-02', 7, 15],
['2017-03-03', 4, 9] ['2017-03-03', 5, 11]
].to_json) ].to_json)
end end
end end
context 'when issues belong to a public project' do
it 'does not include confidential issues for users who are not project members' do
project.update(visibility_level: Gitlab::VisibilityLevel::PUBLIC)
expected_result = [
["2017-03-01", 3, 6],
["2017-03-02", 4, 8],
["2017-03-03", 2, 4]
].to_json
expect(described_class.new(milestone, non_member).to_json).to eq(expected_result)
end
end
end end
describe 'project milestone burndown' do describe 'project milestone burndown' do
...@@ -126,6 +141,10 @@ describe Burndown do ...@@ -126,6 +141,10 @@ describe Burndown do
let(:nested_group_milestone) { create(:milestone, group: nested_group, start_date: start_date, due_date: due_date) } let(:nested_group_milestone) { create(:milestone, group: nested_group, start_date: start_date, due_date: due_date) }
context 'when nested group milestone', :nested_groups do context 'when nested group milestone', :nested_groups do
before do
group.add_developer(user)
end
it_behaves_like 'burndown for milestone' do it_behaves_like 'burndown for milestone' do
let(:milestone) { nested_group_milestone } let(:milestone) { nested_group_milestone }
let(:project) { nested_group_project } let(:project) { nested_group_project }
...@@ -194,6 +213,9 @@ describe Burndown do ...@@ -194,6 +213,9 @@ describe Burndown do
issue_closed_twice = reopened_issues.last issue_closed_twice = reopened_issues.last
close_issue(issue_closed_twice) close_issue(issue_closed_twice)
reopen_issue(issue_closed_twice) reopen_issue(issue_closed_twice)
# create one confidential issue
create(:issue, :confidential, issue_params) if Date.today == milestone.start_date
end end
end end
end end
......
...@@ -9,8 +9,10 @@ describe Milestone, 'Milestoneish' do ...@@ -9,8 +9,10 @@ describe Milestone, 'Milestoneish' do
let(:admin) { create(:admin) } let(:admin) { create(:admin) }
let(:project) { create(:project, :public) } let(:project) { create(:project, :public) }
let(:milestone) { create(:milestone, project: project) } let(:milestone) { create(:milestone, project: project) }
let!(:issue) { create(:issue, project: project, milestone: milestone) } let(:label1) { create(:label, project: project) }
let!(:security_issue_1) { create(:issue, :confidential, project: project, author: author, milestone: milestone) } let(:label2) { create(:label, project: project) }
let!(:issue) { create(:issue, project: project, milestone: milestone, assignees: [member], labels: [label1]) }
let!(:security_issue_1) { create(:issue, :confidential, project: project, author: author, milestone: milestone, labels: [label2]) }
let!(:security_issue_2) { create(:issue, :confidential, project: project, assignees: [assignee], milestone: milestone) } let!(:security_issue_2) { create(:issue, :confidential, project: project, assignees: [assignee], milestone: milestone) }
let!(:closed_issue_1) { create(:issue, :closed, project: project, milestone: milestone) } let!(:closed_issue_1) { create(:issue, :closed, project: project, milestone: milestone) }
let!(:closed_issue_2) { create(:issue, :closed, project: project, milestone: milestone) } let!(:closed_issue_2) { create(:issue, :closed, project: project, milestone: milestone) }
...@@ -42,6 +44,95 @@ describe Milestone, 'Milestoneish' do ...@@ -42,6 +44,95 @@ describe Milestone, 'Milestoneish' do
end end
end end
context 'attributes visibility' do
using RSpec::Parameterized::TableSyntax
let(:users) do
{
anonymous: nil,
non_member: non_member,
guest: guest,
member: member,
assignee: assignee
}
end
let(:project_visibility_levels) do
{
public: Gitlab::VisibilityLevel::PUBLIC,
internal: Gitlab::VisibilityLevel::INTERNAL,
private: Gitlab::VisibilityLevel::PRIVATE
}
end
describe '#issue_participants_visible_by_user' do
where(:visibility, :user_role, :result) do
:public | nil | [:member]
:public | :non_member | [:member]
:public | :guest | [:member]
:public | :member | [:member, :assignee]
:internal | nil | []
:internal | :non_member | [:member]
:internal | :guest | [:member]
:internal | :member | [:member, :assignee]
:private | nil | []
:private | :non_member | []
:private | :guest | [:member]
:private | :member | [:member, :assignee]
end
with_them do
before do
project.update(visibility_level: project_visibility_levels[visibility])
end
it 'returns the proper participants' do
user = users[user_role]
participants = result.map { |role| users[role] }
expect(milestone.issue_participants_visible_by_user(user)).to match_array(participants)
end
end
end
describe '#issue_labels_visible_by_user' do
let(:labels) do
{
label1: label1,
label2: label2
}
end
where(:visibility, :user_role, :result) do
:public | nil | [:label1]
:public | :non_member | [:label1]
:public | :guest | [:label1]
:public | :member | [:label1, :label2]
:internal | nil | []
:internal | :non_member | [:label1]
:internal | :guest | [:label1]
:internal | :member | [:label1, :label2]
:private | nil | []
:private | :non_member | []
:private | :guest | [:label1]
:private | :member | [:label1, :label2]
end
with_them do
before do
project.update(visibility_level: project_visibility_levels[visibility])
end
it 'returns the proper participants' do
user = users[user_role]
expected_labels = result.map { |label| labels[label] }
expect(milestone.issue_labels_visible_by_user(user)).to match_array(expected_labels)
end
end
end
end
describe '#sorted_merge_requests' do describe '#sorted_merge_requests' do
it 'sorts merge requests by label priority' do it 'sorts merge requests by label priority' do
merge_request_1 = create(:labeled_merge_request, labels: [label_2], source_project: project, source_branch: 'branch_1', milestone: milestone) merge_request_1 = create(:labeled_merge_request, labels: [label_2], source_project: project, source_branch: 'branch_1', milestone: milestone)
......
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