Class: ProjectFeature

Inherits:
ApplicationRecord show all
Extended by:
Gitlab::ConfigHelper, Gitlab::Utils::Override
Includes:
Featurable
Defined in:
app/models/project_feature.rb

Constant Summary collapse

FEATURES =

When updating this array, make sure to update rubocop/cop/gitlab/feature_available_usage.rb as well.

%i[
  issues
  forking
  merge_requests
  wiki
  snippets
  builds
  repository
  pages
  metrics_dashboard
  analytics
  monitor
  operations
  security_and_compliance
  container_registry
  package_registry
  environments
  feature_flags
  releases
  infrastructure
  model_experiments
  model_registry
].freeze
EXPORTABLE_FEATURES =
(FEATURES - [:security_and_compliance, :pages, :metrics_dashboard]).freeze
PRIVATE_FEATURES_MIN_ACCESS_LEVEL =
{
  merge_requests: Gitlab::Access::REPORTER,
  metrics_dashboard: Gitlab::Access::REPORTER,
  container_registry: Gitlab::Access::REPORTER,
  package_registry: Gitlab::Access::REPORTER,
  environments: Gitlab::Access::REPORTER
}.freeze
PRIVATE_FEATURES_MIN_ACCESS_LEVEL_FOR_PRIVATE_PROJECT =
{ repository: Gitlab::Access::REPORTER }.freeze

Constants included from Featurable

Featurable::DISABLED, Featurable::ENABLED, Featurable::PAGES_ACCESS_LEVELS_BY_PROJECT_VISIBILITY, Featurable::PRIVATE, Featurable::PUBLIC, Featurable::STRING_OPTIONS

Constants inherited from ApplicationRecord

ApplicationRecord::MAX_PLUCK

Constants included from HasCheckConstraints

HasCheckConstraints::NOT_NULL_CHECK_PATTERN

Constants included from ResetOnColumnErrors

ResetOnColumnErrors::MAX_RESET_PERIOD

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Gitlab::ConfigHelper

gitlab_config, gitlab_config_features

Methods included from Gitlab::Utils::Override

extended, extensions, included, method_added, override, prepended, queue_verification, verify!

Methods included from Featurable

#access_level, #feature_available?, #string_access_level

Methods inherited from ApplicationRecord

===, cached_column_list, #create_or_load_association, current_transaction, declarative_enum, default_select_columns, delete_all_returning, #deleted_from_database?, id_in, id_not_in, iid_in, nullable_column?, primary_key_in, #readable_by?, safe_ensure_unique, safe_find_or_create_by, safe_find_or_create_by!, #to_ability_name, underscore, where_exists, where_not_exists, with_fast_read_statement_timeout, without_order

Methods included from Organizations::Sharding

#sharding_organization

Methods included from ResetOnColumnErrors

#reset_on_union_error, #reset_on_unknown_attribute_error

Methods included from Gitlab::SensitiveSerializableHash

#serializable_hash

Class Method Details

.required_minimum_access_level(feature) ⇒ Object



47
48
49
50
51
# File 'app/models/project_feature.rb', line 47

def required_minimum_access_level(feature)
  feature = ensure_feature!(feature)

  PRIVATE_FEATURES_MIN_ACCESS_LEVEL.fetch(feature, Gitlab::Access::GUEST)
end

.required_minimum_access_level_for_private_project(feature) ⇒ Object

Guest users can perform certain features on public and internal projects, but not private projects.



54
55
56
57
58
59
60
# File 'app/models/project_feature.rb', line 54

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

.with_feature_available_for_user(feature, user) ⇒ Object

project features may be “disabled”, “internal”, “enabled” or “public”. If “internal”, they are only available to team members. This scope returns features where the feature is either public, enabled, or internal with permission for the user. Note: this scope doesn’t enforce that the user has access to the projects, it just checks that the user has access to the feature. It’s important to use this scope with others that checks project authorizations first (e.g. filter_by_feature_visibility).

This method uses an optimized version of with_feature_access_level for logged in users to more efficiently get private projects with the given feature.



130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
# File 'app/models/project_feature.rb', line 130

def self.with_feature_available_for_user(feature, user)
  visible = [ENABLED, PUBLIC]

  if user&.can_read_all_resources?
    with_feature_enabled(feature)
  elsif user
    min_access_level = required_minimum_access_level(feature)
    column = quoted_access_level_column(feature)

    where(
      "#{column} IS NULL OR #{column} IN (:public_visible) OR (#{column} = :private_visible AND EXISTS (:authorizations))",
      {
        public_visible: visible,
        private_visible: PRIVATE,
        authorizations: user.authorizations_for_projects(min_access_level: min_access_level, related_project_column: 'project_features.project_id')
      }
    )
  else
    # This has to be added to include features whose value is nil in the db
    visible << nil
    with_feature_access_level(feature, visible)
  end
end

Instance Method Details

#package_registry_access_level=(value) ⇒ Object



168
169
170
171
172
# File 'app/models/project_feature.rb', line 168

def package_registry_access_level=(value)
  super(value).tap do
    project.packages_enabled = self.package_registry_access_level != DISABLED if project
  end
end

#private?(feature) ⇒ Boolean

Returns:

  • (Boolean)


180
181
182
# File 'app/models/project_feature.rb', line 180

def private?(feature)
  access_level(feature) == PRIVATE
end

#private_pages?Boolean

Returns:

  • (Boolean)


164
165
166
# File 'app/models/project_feature.rb', line 164

def private_pages?
  !public_pages?
end

#public_packages?Boolean

Returns:

  • (Boolean)


174
175
176
177
178
# File 'app/models/project_feature.rb', line 174

def public_packages?
  return false unless Gitlab.config.packages.enabled

  package_registry_access_level == PUBLIC || project.public?
end

#public_pages?Boolean

This method checks whether access control is enabled on project level, to include the access setting from ancestors, use project.public_pages?

Returns:

  • (Boolean)


156
157
158
159
160
161
162
# File 'app/models/project_feature.rb', line 156

def public_pages?
  return true unless Gitlab.config.pages.access_control

  return false if ::Gitlab::Pages.access_control_is_forced?

  pages_access_level == PUBLIC || (pages_access_level == ENABLED && project.public?)
end