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
].freeze
EXPORTABLE_FEATURES =
(FEATURES - [:security_and_compliance, :pages]).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::PRIVATE, Featurable::PUBLIC, Featurable::STRING_OPTIONS

Constants inherited from ApplicationRecord

ApplicationRecord::MAX_PLUCK

Constants included from ResetOnUnionError

ResetOnUnionError::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, declarative_enum, default_select_columns, id_in, id_not_in, iid_in, pluck_primary_key, 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 SensitiveSerializableHash

#serializable_hash

Class Method Details

.required_minimum_access_level(feature) ⇒ Object



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

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.



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

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.



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

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



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

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)


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

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

#private_pages?Boolean

Returns:

  • (Boolean)


160
161
162
# File 'app/models/project_feature.rb', line 160

def private_pages?
  !public_pages?
end

#public_packages?Boolean

Returns:

  • (Boolean)


170
171
172
173
174
# File 'app/models/project_feature.rb', line 170

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

  package_registry_access_level == PUBLIC || project.public?
end

#public_pages?Boolean

Returns:

  • (Boolean)


152
153
154
155
156
157
158
# File 'app/models/project_feature.rb', line 152

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