Internalize private project minimum access level
Some feature allows GUEST to access only if project is not private. This method returns access level when targeting private projects.
This commit is contained in:
parent
03c0e9ba65
commit
2858452b68
3 changed files with 39 additions and 14 deletions
|
@ -517,13 +517,11 @@ class Project < ApplicationRecord
|
||||||
|
|
||||||
# This scope returns projects where user has access to both the project and the feature.
|
# This scope returns projects where user has access to both the project and the feature.
|
||||||
def self.filter_by_feature_visibility(feature, user)
|
def self.filter_by_feature_visibility(feature, user)
|
||||||
scope = with_feature_available_for_user(feature, user)
|
with_feature_available_for_user(feature, user)
|
||||||
|
.public_or_visible_to_user(
|
||||||
if ProjectFeature.guest_allowed_on_private_project?(feature)
|
user,
|
||||||
scope.public_or_visible_to_user(user)
|
ProjectFeature.required_minimum_access_level_for_private_project(feature)
|
||||||
else
|
)
|
||||||
scope.public_or_visible_to_user(user, Gitlab::Access::REPORTER)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
scope :active, -> { joins(:issues, :notes, :merge_requests).order('issues.created_at, notes.created_at, merge_requests.created_at DESC') }
|
scope :active, -> { joins(:issues, :notes, :merge_requests).order('issues.created_at, notes.created_at, merge_requests.created_at DESC') }
|
||||||
|
|
|
@ -24,7 +24,7 @@ class ProjectFeature < ApplicationRecord
|
||||||
|
|
||||||
FEATURES = %i(issues merge_requests wiki snippets builds repository pages).freeze
|
FEATURES = %i(issues merge_requests wiki snippets builds repository pages).freeze
|
||||||
PRIVATE_FEATURES_MIN_ACCESS_LEVEL = { merge_requests: Gitlab::Access::REPORTER }.freeze
|
PRIVATE_FEATURES_MIN_ACCESS_LEVEL = { merge_requests: Gitlab::Access::REPORTER }.freeze
|
||||||
FEATURES_ALLOWED_BY_GUEST_ON_PRIVATE_PROJECT = %i(issues wiki).freeze
|
PRIVATE_FEATURES_MIN_ACCESS_LEVEL_FOR_PRIVATE_PROJECT = { repository: Gitlab::Access::REPORTER }.freeze
|
||||||
STRING_OPTIONS = HashWithIndifferentAccess.new({
|
STRING_OPTIONS = HashWithIndifferentAccess.new({
|
||||||
'disabled' => DISABLED,
|
'disabled' => DISABLED,
|
||||||
'private' => PRIVATE,
|
'private' => PRIVATE,
|
||||||
|
@ -46,18 +46,21 @@ class ProjectFeature < ApplicationRecord
|
||||||
"#{table}.#{attribute}"
|
"#{table}.#{attribute}"
|
||||||
end
|
end
|
||||||
|
|
||||||
def guest_allowed_on_private_project?(feature)
|
|
||||||
feature = ensure_feature!(feature)
|
|
||||||
|
|
||||||
FEATURES_ALLOWED_BY_GUEST_ON_PRIVATE_PROJECT.include?(feature)
|
|
||||||
end
|
|
||||||
|
|
||||||
def required_minimum_access_level(feature)
|
def required_minimum_access_level(feature)
|
||||||
feature = ensure_feature!(feature)
|
feature = ensure_feature!(feature)
|
||||||
|
|
||||||
PRIVATE_FEATURES_MIN_ACCESS_LEVEL.fetch(feature, Gitlab::Access::GUEST)
|
PRIVATE_FEATURES_MIN_ACCESS_LEVEL.fetch(feature, Gitlab::Access::GUEST)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Guest users can perform certain features on public and internal projects, but not private projects.
|
||||||
|
def required_minimum_access_level_for_private_project(feature)
|
||||||
|
feature = ensure_feature!(feature)
|
||||||
|
|
||||||
|
PRIVATE_FEATURES_MIN_ACCESS_LEVEL_FOR_PRIVATE_PROJECT.fetch(feature) do
|
||||||
|
required_minimum_access_level(feature)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def access_level_from_str(level)
|
def access_level_from_str(level)
|
||||||
STRING_OPTIONS.fetch(level)
|
STRING_OPTIONS.fetch(level)
|
||||||
end
|
end
|
||||||
|
|
|
@ -6,6 +6,16 @@ describe ProjectFeature do
|
||||||
let(:project) { create(:project) }
|
let(:project) { create(:project) }
|
||||||
let(:user) { create(:user) }
|
let(:user) { create(:user) }
|
||||||
|
|
||||||
|
describe 'PRIVATE_FEATURES_MIN_ACCESS_LEVEL_FOR_PRIVATE_PROJECT' do
|
||||||
|
it 'has higher level than that of PRIVATE_FEATURES_MIN_ACCESS_LEVEL' do
|
||||||
|
described_class::PRIVATE_FEATURES_MIN_ACCESS_LEVEL_FOR_PRIVATE_PROJECT.each do |feature, level|
|
||||||
|
if generic_level = described_class::PRIVATE_FEATURES_MIN_ACCESS_LEVEL[feature]
|
||||||
|
expect(level).to be >= generic_level
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
describe '.quoted_access_level_column' do
|
describe '.quoted_access_level_column' do
|
||||||
it 'returns the table name and quoted column name for a feature' do
|
it 'returns the table name and quoted column name for a feature' do
|
||||||
expected = '"project_features"."issues_access_level"'
|
expected = '"project_features"."issues_access_level"'
|
||||||
|
@ -246,10 +256,24 @@ describe ProjectFeature do
|
||||||
expect(described_class.required_minimum_access_level('merge_requests')).to eq(Gitlab::Access::REPORTER)
|
expect(described_class.required_minimum_access_level('merge_requests')).to eq(Gitlab::Access::REPORTER)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it 'handles repository' do
|
||||||
|
expect(described_class.required_minimum_access_level(:repository)).to eq(Gitlab::Access::GUEST)
|
||||||
|
end
|
||||||
|
|
||||||
it 'raises error if feature is invalid' do
|
it 'raises error if feature is invalid' do
|
||||||
expect do
|
expect do
|
||||||
described_class.required_minimum_access_level(:foos)
|
described_class.required_minimum_access_level(:foos)
|
||||||
end.to raise_error
|
end.to raise_error
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe '.required_minimum_access_level_for_private_project' do
|
||||||
|
it 'returns higher permission for repository' do
|
||||||
|
expect(described_class.required_minimum_access_level_for_private_project(:repository)).to eq(Gitlab::Access::REPORTER)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns normal permission for issues' do
|
||||||
|
expect(described_class.required_minimum_access_level_for_private_project(:issues)).to eq(Gitlab::Access::GUEST)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue