Commit 2ccf14d9 authored by GitLab Bot's avatar GitLab Bot

Automatic merge of gitlab-org/gitlab-ce master

parents 17094a2e 87dce571
...@@ -76,8 +76,8 @@ schedule:review-build-cng: ...@@ -76,8 +76,8 @@ schedule:review-build-cng:
.review-deploy-base: &review-deploy-base .review-deploy-base: &review-deploy-base
<<: *review-base <<: *review-base
allow_failure: true
stage: review stage: review
retry: 2
variables: variables:
HOST_SUFFIX: "${CI_ENVIRONMENT_SLUG}" HOST_SUFFIX: "${CI_ENVIRONMENT_SLUG}"
DOMAIN: "-${CI_ENVIRONMENT_SLUG}.${REVIEW_APPS_DOMAIN}" DOMAIN: "-${CI_ENVIRONMENT_SLUG}.${REVIEW_APPS_DOMAIN}"
...@@ -128,6 +128,7 @@ review-stop: ...@@ -128,6 +128,7 @@ review-stop:
.review-qa-base: &review-qa-base .review-qa-base: &review-qa-base
<<: *review-docker <<: *review-docker
allow_failure: true
stage: qa stage: qa
variables: variables:
<<: *review-docker-variables <<: *review-docker-variables
...@@ -157,7 +158,6 @@ review-stop: ...@@ -157,7 +158,6 @@ review-stop:
review-qa-smoke: review-qa-smoke:
<<: *review-qa-base <<: *review-qa-base
retry: 2
script: script:
- gitlab-qa Test::Instance::Smoke "${QA_IMAGE}" "${CI_ENVIRONMENT_URL}" - gitlab-qa Test::Instance::Smoke "${QA_IMAGE}" "${CI_ENVIRONMENT_URL}"
......
...@@ -6,6 +6,19 @@ ...@@ -6,6 +6,19 @@
position: relative; position: relative;
z-index: 1; z-index: 1;
.flash-notice,
.flash-alert,
.flash-success,
.flash-warning {
border-radius: $border-radius-default;
color: $white-light;
.container-fluid,
.container-fluid.container-limited {
background: transparent;
}
}
.flash-notice { .flash-notice {
@extend .alert; @extend .alert;
background-color: $blue-500; background-color: $blue-500;
...@@ -28,7 +41,8 @@ ...@@ -28,7 +41,8 @@
.flash-warning { .flash-warning {
@extend .alert; @extend .alert;
background-color: $orange-500; background-color: $orange-100;
color: $orange-900;
margin: 0; margin: 0;
} }
...@@ -60,19 +74,6 @@ ...@@ -60,19 +74,6 @@
margin: 0; margin: 0;
} }
.flash-notice,
.flash-alert,
.flash-success,
.flash-warning {
border-radius: $border-radius-default;
color: $white-light;
.container-fluid,
.container-fluid.container-limited {
background: transparent;
}
}
&.flash-container-page { &.flash-container-page {
margin-bottom: 0; margin-bottom: 0;
......
...@@ -38,7 +38,9 @@ class Todo < ApplicationRecord ...@@ -38,7 +38,9 @@ class Todo < ApplicationRecord
self self
end end
}, polymorphic: true, touch: true # rubocop:disable Cop/PolymorphicAssociations }, polymorphic: true, touch: true # rubocop:disable Cop/PolymorphicAssociations
belongs_to :user belongs_to :user
belongs_to :issue, -> { where("target_type = 'Issue'") }, foreign_key: :target_id
delegate :name, :email, to: :author, prefix: true, allow_nil: true delegate :name, :email, to: :author, prefix: true, allow_nil: true
...@@ -59,6 +61,7 @@ class Todo < ApplicationRecord ...@@ -59,6 +61,7 @@ class Todo < ApplicationRecord
scope :for_target, -> (id) { where(target_id: id) } scope :for_target, -> (id) { where(target_id: id) }
scope :for_commit, -> (id) { where(commit_id: id) } scope :for_commit, -> (id) { where(commit_id: id) }
scope :with_api_entity_associations, -> { preload(:target, :author, :note, group: :route, project: [:route, { namespace: :route }]) } scope :with_api_entity_associations, -> { preload(:target, :author, :note, group: :route, project: [:route, { namespace: :route }]) }
scope :joins_issue_and_assignees, -> { left_joins(issue: :assignees) }
state_machine :state, initial: :pending do state_machine :state, initial: :pending do
event :done do event :done do
......
...@@ -64,6 +64,7 @@ module Projects ...@@ -64,6 +64,7 @@ module Projects
if project.previous_changes.include?(:visibility_level) && project.private? if project.previous_changes.include?(:visibility_level) && project.private?
# don't enqueue immediately to prevent todos removal in case of a mistake # don't enqueue immediately to prevent todos removal in case of a mistake
TodosDestroyer::ConfidentialIssueWorker.perform_in(Todo::WAIT_FOR_DELETE, nil, project.id)
TodosDestroyer::ProjectPrivateWorker.perform_in(Todo::WAIT_FOR_DELETE, project.id) TodosDestroyer::ProjectPrivateWorker.perform_in(Todo::WAIT_FOR_DELETE, project.id)
elsif (project_changed_feature_keys & todos_features_changes).present? elsif (project_changed_feature_keys & todos_features_changes).present?
TodosDestroyer::PrivateFeaturesWorker.perform_in(Todo::WAIT_FOR_DELETE, project.id) TodosDestroyer::PrivateFeaturesWorker.perform_in(Todo::WAIT_FOR_DELETE, project.id)
......
...@@ -13,7 +13,7 @@ module Todos ...@@ -13,7 +13,7 @@ module Todos
# rubocop: disable CodeReuse/ActiveRecord # rubocop: disable CodeReuse/ActiveRecord
def without_authorized(items) def without_authorized(items)
items.where('user_id NOT IN (?)', authorized_users) items.where('todos.user_id NOT IN (?)', authorized_users)
end end
# rubocop: enable CodeReuse/ActiveRecord # rubocop: enable CodeReuse/ActiveRecord
......
...@@ -2,36 +2,55 @@ ...@@ -2,36 +2,55 @@
module Todos module Todos
module Destroy module Destroy
# Service class for deleting todos that belongs to confidential issues.
# It deletes todos for users that are not at least reporters, issue author or assignee.
#
# Accepts issue_id or project_id as argument.
# When issue_id is passed it deletes matching todos for one confidential issue.
# When project_id is passed it deletes matching todos for all confidential issues of the project.
class ConfidentialIssueService < ::Todos::Destroy::BaseService class ConfidentialIssueService < ::Todos::Destroy::BaseService
extend ::Gitlab::Utils::Override extend ::Gitlab::Utils::Override
attr_reader :issue attr_reader :issues
# rubocop: disable CodeReuse/ActiveRecord # rubocop: disable CodeReuse/ActiveRecord
def initialize(issue_id) def initialize(issue_id: nil, project_id: nil)
@issue = Issue.find_by(id: issue_id) @issues =
if issue_id
Issue.where(id: issue_id)
elsif project_id
project_confidential_issues(project_id)
end
end end
# rubocop: enable CodeReuse/ActiveRecord # rubocop: enable CodeReuse/ActiveRecord
private private
def project_confidential_issues(project_id)
project = Project.find(project_id)
project.issues.confidential_only
end
override :todos override :todos
# rubocop: disable CodeReuse/ActiveRecord # rubocop: disable CodeReuse/ActiveRecord
def todos def todos
Todo.where(target: issue) Todo.joins_issue_and_assignees
.where('user_id != ?', issue.author_id) .where(target: issues)
.where('user_id NOT IN (?)', issue.assignees.select(:id)) .where('issues.confidential = ?', true)
.where('todos.user_id != issues.author_id')
.where('todos.user_id != issue_assignees.user_id')
end end
# rubocop: enable CodeReuse/ActiveRecord # rubocop: enable CodeReuse/ActiveRecord
override :todos_to_remove? override :todos_to_remove?
def todos_to_remove? def todos_to_remove?
issue&.confidential? issues&.any?(&:confidential?)
end end
override :project_ids override :project_ids
def project_ids def project_ids
issue.project_id issues&.distinct&.select(:project_id)
end end
override :authorized_users override :authorized_users
......
...@@ -5,8 +5,8 @@ module TodosDestroyer ...@@ -5,8 +5,8 @@ module TodosDestroyer
include ApplicationWorker include ApplicationWorker
include TodosDestroyerQueue include TodosDestroyerQueue
def perform(issue_id) def perform(issue_id = nil, project_id = nil)
::Todos::Destroy::ConfidentialIssueService.new(issue_id).execute ::Todos::Destroy::ConfidentialIssueService.new(issue_id: issue_id, project_id: project_id).execute
end end
end end
end end
---
title: "Rebrush of flash-warning according to the new design (brighter background and darker font)"
merge_request: 28916
author: Michel Engelen
type: changed
---
title: Delete unauthorized Todos when project is made private
merge_request: 28560
author:
type: fixed
...@@ -45,6 +45,7 @@ describe Projects::UpdateService do ...@@ -45,6 +45,7 @@ describe Projects::UpdateService do
it 'updates the project to private' do it 'updates the project to private' do
expect(TodosDestroyer::ProjectPrivateWorker).to receive(:perform_in).with(Todo::WAIT_FOR_DELETE, project.id) expect(TodosDestroyer::ProjectPrivateWorker).to receive(:perform_in).with(Todo::WAIT_FOR_DELETE, project.id)
expect(TodosDestroyer::ConfidentialIssueWorker).to receive(:perform_in).with(Todo::WAIT_FOR_DELETE, nil, project.id)
result = update_project(project, user, visibility_level: Gitlab::VisibilityLevel::PRIVATE) result = update_project(project, user, visibility_level: Gitlab::VisibilityLevel::PRIVATE)
......
...@@ -9,36 +9,60 @@ describe Todos::Destroy::ConfidentialIssueService do ...@@ -9,36 +9,60 @@ describe Todos::Destroy::ConfidentialIssueService do
let(:assignee) { create(:user) } let(:assignee) { create(:user) }
let(:guest) { create(:user) } let(:guest) { create(:user) }
let(:project_member) { create(:user) } let(:project_member) { create(:user) }
let(:issue) { create(:issue, project: project, author: author, assignees: [assignee]) } let(:issue_1) { create(:issue, :confidential, project: project, author: author, assignees: [assignee]) }
let!(:todo_issue_non_member) { create(:todo, user: user, target: issue, project: project) }
let!(:todo_issue_member) { create(:todo, user: project_member, target: issue, project: project) }
let!(:todo_issue_author) { create(:todo, user: author, target: issue, project: project) }
let!(:todo_issue_asignee) { create(:todo, user: assignee, target: issue, project: project) }
let!(:todo_issue_guest) { create(:todo, user: guest, target: issue, project: project) }
let!(:todo_another_non_member) { create(:todo, user: user, project: project) }
describe '#execute' do describe '#execute' do
before do before do
project.add_developer(project_member) project.add_developer(project_member)
project.add_guest(guest) project.add_guest(guest)
# todos not to be deleted
create(:todo, user: project_member, target: issue_1, project: project)
create(:todo, user: author, target: issue_1, project: project)
create(:todo, user: assignee, target: issue_1, project: project)
create(:todo, user: user, project: project)
# Todos to be deleted
create(:todo, user: guest, target: issue_1, project: project)
create(:todo, user: user, target: issue_1, project: project)
end end
subject { described_class.new(issue.id).execute } subject { described_class.new(issue_id: issue_1.id).execute }
context 'when provided issue is confidential' do context 'when issue_id parameter is present' do
before do context 'when provided issue is confidential' do
issue.update!(confidential: true) it 'removes issue todos for users who can not access the confidential issue' do
expect { subject }.to change { Todo.count }.from(6).to(4)
end
end end
it 'removes issue todos for users who can not access the confidential issue' do context 'when provided issue is not confidential' do
expect { subject }.to change { Todo.count }.from(6).to(4) it 'does not remove any todos' do
issue_1.update(confidential: false)
expect { subject }.not_to change { Todo.count }
end
end end
end end
context 'when provided issue is not confidential' do context 'when project_id parameter is present' do
it 'does not remove any todos' do subject { described_class.new(issue_id: nil, project_id: project.id).execute }
expect { subject }.not_to change { Todo.count }
it 'removes issues todos for users that cannot access confidential issues' do
issue_2 = create(:issue, :confidential, project: project)
issue_3 = create(:issue, :confidential, project: project, author: author, assignees: [assignee])
issue_4 = create(:issue, project: project)
# Todos not to be deleted
create(:todo, user: guest, target: issue_1, project: project)
create(:todo, user: assignee, target: issue_1, project: project)
create(:todo, user: project_member, target: issue_2, project: project)
create(:todo, user: author, target: issue_3, project: project)
create(:todo, user: user, target: issue_4, project: project)
create(:todo, user: user, project: project)
# Todos to be deleted
create(:todo, user: user, target: issue_1, project: project)
create(:todo, user: guest, target: issue_2, project: project)
expect { subject }.to change { Todo.count }.from(14).to(10)
end end
end end
end end
......
...@@ -3,12 +3,19 @@ ...@@ -3,12 +3,19 @@
require 'spec_helper' require 'spec_helper'
describe TodosDestroyer::ConfidentialIssueWorker do describe TodosDestroyer::ConfidentialIssueWorker do
it "calls the Todos::Destroy::ConfidentialIssueService with the params it was given" do let(:service) { double }
service = double
expect(::Todos::Destroy::ConfidentialIssueService).to receive(:new).with(100).and_return(service) it "calls the Todos::Destroy::ConfidentialIssueService with issue_id parameter" do
expect(::Todos::Destroy::ConfidentialIssueService).to receive(:new).with(issue_id: 100, project_id: nil).and_return(service)
expect(service).to receive(:execute) expect(service).to receive(:execute)
described_class.new.perform(100) described_class.new.perform(100)
end end
it "calls the Todos::Destroy::ConfidentialIssueService with project_id parameter" do
expect(::Todos::Destroy::ConfidentialIssueService).to receive(:new).with(issue_id: nil, project_id: 100).and_return(service)
expect(service).to receive(:execute)
described_class.new.perform(nil, 100)
end
end 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