summaryrefslogtreecommitdiff
path: root/app/models/concerns
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2021-10-20 08:43:02 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2021-10-20 08:43:02 +0000
commitd9ab72d6080f594d0b3cae15f14b3ef2c6c638cb (patch)
tree2341ef426af70ad1e289c38036737e04b0aa5007 /app/models/concerns
parentd6e514dd13db8947884cd58fe2a9c2a063400a9b (diff)
downloadgitlab-ce-d9ab72d6080f594d0b3cae15f14b3ef2c6c638cb.tar.gz
Add latest changes from gitlab-org/gitlab@14-4-stable-eev14.4.0-rc42
Diffstat (limited to 'app/models/concerns')
-rw-r--r--app/models/concerns/analytics/cycle_analytics/stage.rb3
-rw-r--r--app/models/concerns/analytics/cycle_analytics/stage_event_model.rb54
-rw-r--r--app/models/concerns/avatarable.rb3
-rw-r--r--app/models/concerns/bulk_insert_safe.rb12
-rw-r--r--app/models/concerns/checksummable.rb6
-rw-r--r--app/models/concerns/ci/has_status.rb1
-rw-r--r--app/models/concerns/ci/metadatable.rb1
-rw-r--r--app/models/concerns/enums/ci/commit_status.rb1
-rw-r--r--app/models/concerns/has_repository.rb4
-rw-r--r--app/models/concerns/integrations/has_data_fields.rb1
-rw-r--r--app/models/concerns/issue_available_features.rb3
-rw-r--r--app/models/concerns/packages/debian/distribution.rb10
-rw-r--r--app/models/concerns/restricted_signup.rb42
-rw-r--r--app/models/concerns/routable.rb3
-rw-r--r--app/models/concerns/ttl_expirable.rb20
-rw-r--r--app/models/concerns/vulnerability_finding_helpers.rb9
16 files changed, 147 insertions, 26 deletions
diff --git a/app/models/concerns/analytics/cycle_analytics/stage.rb b/app/models/concerns/analytics/cycle_analytics/stage.rb
index 7bb6004ca83..d9e6756ab86 100644
--- a/app/models/concerns/analytics/cycle_analytics/stage.rb
+++ b/app/models/concerns/analytics/cycle_analytics/stage.rb
@@ -27,7 +27,8 @@ module Analytics
alias_attribute :custom_stage?, :custom
scope :default_stages, -> { where(custom: false) }
scope :ordered, -> { order(:relative_position, :id) }
- scope :for_list, -> { includes(:start_event_label, :end_event_label).ordered }
+ scope :with_preloaded_labels, -> { includes(:start_event_label, :end_event_label) }
+ scope :for_list, -> { with_preloaded_labels.ordered }
scope :by_value_stream, -> (value_stream) { where(value_stream_id: value_stream.id) }
before_save :ensure_stage_event_hash_id
diff --git a/app/models/concerns/analytics/cycle_analytics/stage_event_model.rb b/app/models/concerns/analytics/cycle_analytics/stage_event_model.rb
new file mode 100644
index 00000000000..7462e1e828b
--- /dev/null
+++ b/app/models/concerns/analytics/cycle_analytics/stage_event_model.rb
@@ -0,0 +1,54 @@
+# frozen_string_literal: true
+
+module Analytics
+ module CycleAnalytics
+ module StageEventModel
+ extend ActiveSupport::Concern
+
+ class_methods do
+ def upsert_data(data)
+ upsert_values = data.map do |row|
+ row.values_at(
+ :stage_event_hash_id,
+ :issuable_id,
+ :group_id,
+ :project_id,
+ :author_id,
+ :milestone_id,
+ :start_event_timestamp,
+ :end_event_timestamp
+ )
+ end
+
+ value_list = Arel::Nodes::ValuesList.new(upsert_values).to_sql
+
+ query = <<~SQL
+ INSERT INTO #{quoted_table_name}
+ (
+ stage_event_hash_id,
+ #{connection.quote_column_name(issuable_id_column)},
+ group_id,
+ project_id,
+ milestone_id,
+ author_id,
+ start_event_timestamp,
+ end_event_timestamp
+ )
+ #{value_list}
+ ON CONFLICT(stage_event_hash_id, #{issuable_id_column})
+ DO UPDATE SET
+ group_id = excluded.group_id,
+ project_id = excluded.project_id,
+ start_event_timestamp = excluded.start_event_timestamp,
+ end_event_timestamp = excluded.end_event_timestamp,
+ milestone_id = excluded.milestone_id,
+ author_id = excluded.author_id
+ SQL
+
+ result = connection.execute(query)
+ result.cmd_tuples
+ end
+ end
+ end
+ end
+end
diff --git a/app/models/concerns/avatarable.rb b/app/models/concerns/avatarable.rb
index 84a74386ff7..b32502c3ee2 100644
--- a/app/models/concerns/avatarable.rb
+++ b/app/models/concerns/avatarable.rb
@@ -18,6 +18,7 @@ module Avatarable
prepend ShadowMethods
include ObjectStorage::BackgroundMove
include Gitlab::Utils::StrongMemoize
+ include ApplicationHelper
validate :avatar_type, if: ->(user) { user.avatar.present? && user.avatar_changed? }
validates :avatar, file_size: { maximum: MAXIMUM_FILE_SIZE }, if: :avatar_changed?
@@ -110,7 +111,7 @@ module Avatarable
def retrieve_upload_from_batch(identifier)
BatchLoader.for(identifier: identifier, model: self)
- .batch(key: self.class, cache: true, replace_methods: false) do |upload_params, loader, args|
+ .batch(key: self.class) do |upload_params, loader, args|
model_class = args[:key]
paths = upload_params.flat_map do |params|
params[:model].upload_paths(params[:identifier])
diff --git a/app/models/concerns/bulk_insert_safe.rb b/app/models/concerns/bulk_insert_safe.rb
index 908f0b6a7e2..6c3093ca916 100644
--- a/app/models/concerns/bulk_insert_safe.rb
+++ b/app/models/concerns/bulk_insert_safe.rb
@@ -51,6 +51,12 @@ module BulkInsertSafe
PrimaryKeySetError = Class.new(StandardError)
class_methods do
+ def insert_all_proxy_class
+ @insert_all_proxy_class ||= Class.new(self) do
+ attr_readonly :created_at
+ end
+ end
+
def set_callback(name, *args)
unless _bulk_insert_callback_allowed?(name, args)
raise MethodNotAllowedError,
@@ -138,7 +144,7 @@ module BulkInsertSafe
when nil
false
else
- raise ArgumentError, "returns needs to be :ids or nil"
+ returns
end
# Handle insertions for tables with a composite primary key
@@ -153,9 +159,9 @@ module BulkInsertSafe
item_batch, validate, &handle_attributes)
ActiveRecord::InsertAll
- .new(self, attributes, on_duplicate: on_duplicate, returning: returning, unique_by: unique_by)
+ .new(insert_all_proxy_class, attributes, on_duplicate: on_duplicate, returning: returning, unique_by: unique_by)
.execute
- .pluck(primary_key)
+ .cast_values(insert_all_proxy_class.attribute_types).to_a
end
end
end
diff --git a/app/models/concerns/checksummable.rb b/app/models/concerns/checksummable.rb
index 056abafd0ce..9812c62fcc4 100644
--- a/app/models/concerns/checksummable.rb
+++ b/app/models/concerns/checksummable.rb
@@ -8,8 +8,12 @@ module Checksummable
Zlib.crc32(data)
end
- def hexdigest(path)
+ def sha256_hexdigest(path)
::Digest::SHA256.file(path).hexdigest
end
+
+ def md5_hexdigest(path)
+ ::Digest::MD5.file(path).hexdigest
+ end
end
end
diff --git a/app/models/concerns/ci/has_status.rb b/app/models/concerns/ci/has_status.rb
index c1299e3d468..8d715279da8 100644
--- a/app/models/concerns/ci/has_status.rb
+++ b/app/models/concerns/ci/has_status.rb
@@ -95,6 +95,7 @@ module Ci
scope :failed_or_canceled, -> { with_status(:failed, :canceled) }
scope :complete, -> { with_status(completed_statuses) }
scope :incomplete, -> { without_statuses(completed_statuses) }
+ scope :waiting_for_resource_or_upcoming, -> { with_status(:created, :scheduled, :waiting_for_resource) }
scope :cancelable, -> do
where(status: [:running, :waiting_for_resource, :preparing, :pending, :created, :scheduled])
diff --git a/app/models/concerns/ci/metadatable.rb b/app/models/concerns/ci/metadatable.rb
index ec86746ae54..344f5aa4cd5 100644
--- a/app/models/concerns/ci/metadatable.rb
+++ b/app/models/concerns/ci/metadatable.rb
@@ -20,6 +20,7 @@ module Ci
delegate :interruptible, to: :metadata, prefix: false, allow_nil: true
delegate :has_exposed_artifacts?, to: :metadata, prefix: false, allow_nil: true
delegate :environment_auto_stop_in, to: :metadata, prefix: false, allow_nil: true
+ delegate :runner_features, to: :metadata, prefix: false, allow_nil: false
before_create :ensure_metadata
end
diff --git a/app/models/concerns/enums/ci/commit_status.rb b/app/models/concerns/enums/ci/commit_status.rb
index 7f46e44697e..1b4cc14f4a2 100644
--- a/app/models/concerns/enums/ci/commit_status.rb
+++ b/app/models/concerns/enums/ci/commit_status.rb
@@ -27,6 +27,7 @@ module Enums
no_matching_runner: 18, # not used anymore, but cannot be deleted because of old data
trace_size_exceeded: 19,
builds_disabled: 20,
+ environment_creation_failure: 21,
insufficient_bridge_permissions: 1_001,
downstream_bridge_project_not_found: 1_002,
invalid_bridge_trigger: 1_003,
diff --git a/app/models/concerns/has_repository.rb b/app/models/concerns/has_repository.rb
index 9218ba47d20..d614d6c4584 100644
--- a/app/models/concerns/has_repository.rb
+++ b/app/models/concerns/has_repository.rb
@@ -72,12 +72,10 @@ module HasRepository
end
def default_branch
- @default_branch ||= repository.root_ref || default_branch_from_preferences
+ @default_branch ||= repository.empty? ? default_branch_from_preferences : repository.root_ref
end
def default_branch_from_preferences
- return unless empty_repo?
-
(default_branch_from_group_preferences || Gitlab::CurrentSettings.default_branch_name).presence
end
diff --git a/app/models/concerns/integrations/has_data_fields.rb b/app/models/concerns/integrations/has_data_fields.rb
index 1709b56080e..25a1d855119 100644
--- a/app/models/concerns/integrations/has_data_fields.rb
+++ b/app/models/concerns/integrations/has_data_fields.rb
@@ -45,7 +45,6 @@ module Integrations
included do
has_one :issue_tracker_data, autosave: true, inverse_of: :integration, foreign_key: :service_id, class_name: 'Integrations::IssueTrackerData'
has_one :jira_tracker_data, autosave: true, inverse_of: :integration, foreign_key: :service_id, class_name: 'Integrations::JiraTrackerData'
- has_one :open_project_tracker_data, autosave: true, inverse_of: :integration, foreign_key: :service_id, class_name: 'Integrations::OpenProjectTrackerData'
has_one :zentao_tracker_data, autosave: true, inverse_of: :integration, foreign_key: :integration_id, class_name: 'Integrations::ZentaoTrackerData'
def data_fields
diff --git a/app/models/concerns/issue_available_features.rb b/app/models/concerns/issue_available_features.rb
index 933e8b5f687..209456f8b67 100644
--- a/app/models/concerns/issue_available_features.rb
+++ b/app/models/concerns/issue_available_features.rb
@@ -12,7 +12,8 @@ module IssueAvailableFeatures
{
assignee: %w(issue incident),
confidentiality: %w(issue incident),
- time_tracking: %w(issue incident)
+ time_tracking: %w(issue incident),
+ move_and_clone: %w(issue incident)
}.with_indifferent_access
end
end
diff --git a/app/models/concerns/packages/debian/distribution.rb b/app/models/concerns/packages/debian/distribution.rb
index 196bec04be6..ff52769fce8 100644
--- a/app/models/concerns/packages/debian/distribution.rb
+++ b/app/models/concerns/packages/debian/distribution.rb
@@ -96,18 +96,8 @@ module Packages
architectures.pluck(:name).sort
end
- def needs_update?
- !file.exists? || time_duration_expired?
- end
-
private
- def time_duration_expired?
- return false unless valid_time_duration_seconds.present?
-
- updated_at + valid_time_duration_seconds.seconds + 6.hours < Time.current
- end
-
def unique_codename_and_suite
errors.add(:codename, _('has already been taken as Suite')) if codename_exists_as_suite?
errors.add(:suite, _('has already been taken as Codename')) if suite_exists_as_codename?
diff --git a/app/models/concerns/restricted_signup.rb b/app/models/concerns/restricted_signup.rb
index 587f8c35ff7..cf97be21165 100644
--- a/app/models/concerns/restricted_signup.rb
+++ b/app/models/concerns/restricted_signup.rb
@@ -7,15 +7,49 @@ module RestrictedSignup
def validate_admin_signup_restrictions(email)
return if allowed_domain?(email)
+ error_type = fetch_error_type(email)
+
+ return unless error_type.present?
+
+ [
+ signup_email_invalid_message,
+ error_message[created_by_key][error_type]
+ ].join(' ')
+ end
+
+ def fetch_error_type(email)
if allowlist_present?
- return _('domain is not authorized for sign-up.')
+ :allowlist
elsif denied_domain?(email)
- return _('is not from an allowed domain.')
+ :denylist
elsif restricted_email?(email)
- return _('is not allowed. Try again with a different email address, or contact your GitLab admin.')
+ :restricted
end
+ end
+
+ def error_message
+ {
+ admin: {
+ allowlist: html_escape_once(_("Go to the 'Admin area &gt; Sign-up restrictions', and check 'Allowed domains for sign-ups'.")).html_safe,
+ denylist: html_escape_once(_("Go to the 'Admin area &gt; Sign-up restrictions', and check the 'Domain denylist'.")).html_safe,
+ restricted: html_escape_once(_("Go to the 'Admin area &gt; Sign-up restrictions', and check 'Email restrictions for sign-ups'.")).html_safe,
+ group_setting: html_escape_once(_("Go to the group’s 'Settings &gt; General' page, and check 'Restrict membership by email domain'.")).html_safe
+ },
+ nonadmin: {
+ allowlist: error_nonadmin,
+ denylist: error_nonadmin,
+ restricted: error_nonadmin,
+ group_setting: error_nonadmin
+ }
+ }
+ end
+
+ def error_nonadmin
+ _("Check with your administrator.")
+ end
- nil
+ def created_by_key
+ created_by&.can_admin_all_resources? ? :admin : :nonadmin
end
def denied_domain?(email)
diff --git a/app/models/concerns/routable.rb b/app/models/concerns/routable.rb
index 847abdc1b6d..f382b3624ed 100644
--- a/app/models/concerns/routable.rb
+++ b/app/models/concerns/routable.rb
@@ -41,7 +41,7 @@ module Routable
has_one :route, as: :source, autosave: true, dependent: :destroy, inverse_of: :source # rubocop:disable Cop/ActiveRecordDependent
has_many :redirect_routes, as: :source, autosave: true, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
- validates :route, presence: true
+ validates :route, presence: true, unless: -> { is_a?(Namespaces::ProjectNamespace) }
scope :with_route, -> { includes(:route) }
@@ -185,6 +185,7 @@ module Routable
def prepare_route
return unless full_path_changed? || full_name_changed?
+ return if is_a?(Namespaces::ProjectNamespace)
route || build_route(source: self)
route.path = build_full_path
diff --git a/app/models/concerns/ttl_expirable.rb b/app/models/concerns/ttl_expirable.rb
new file mode 100644
index 00000000000..00abe0a06e6
--- /dev/null
+++ b/app/models/concerns/ttl_expirable.rb
@@ -0,0 +1,20 @@
+# frozen_string_literal: true
+
+module TtlExpirable
+ extend ActiveSupport::Concern
+
+ included do
+ validates :status, presence: true
+
+ enum status: { default: 0, expired: 1, processing: 2, error: 3 }
+
+ scope :updated_before, ->(number_of_days) { where("updated_at <= ?", Time.zone.now - number_of_days.days) }
+ scope :active, -> { where(status: :default) }
+
+ scope :lock_next_by, ->(sort) do
+ order(sort)
+ .limit(1)
+ .lock('FOR UPDATE SKIP LOCKED')
+ end
+ end
+end
diff --git a/app/models/concerns/vulnerability_finding_helpers.rb b/app/models/concerns/vulnerability_finding_helpers.rb
index a656856487d..7f96b3901f1 100644
--- a/app/models/concerns/vulnerability_finding_helpers.rb
+++ b/app/models/concerns/vulnerability_finding_helpers.rb
@@ -2,6 +2,15 @@
module VulnerabilityFindingHelpers
extend ActiveSupport::Concern
+
+ # Manually resolvable report types cannot be considered fixed once removed from the
+ # target branch due to requiring active triage, such as rotation of an exposed token.
+ REPORT_TYPES_REQUIRING_MANUAL_RESOLUTION = %w[secret_detection].freeze
+
+ def requires_manual_resolution?
+ REPORT_TYPES_REQUIRING_MANUAL_RESOLUTION.include?(report_type)
+ end
+
def matches_signatures(other_signatures, other_uuid)
other_signature_types = other_signatures.index_by(&:algorithm_type)