diff options
Diffstat (limited to 'app/models/concerns')
-rw-r--r-- | app/models/concerns/analytics/cycle_analytics/stage.rb | 3 | ||||
-rw-r--r-- | app/models/concerns/analytics/cycle_analytics/stage_event_model.rb | 54 | ||||
-rw-r--r-- | app/models/concerns/avatarable.rb | 3 | ||||
-rw-r--r-- | app/models/concerns/bulk_insert_safe.rb | 12 | ||||
-rw-r--r-- | app/models/concerns/checksummable.rb | 6 | ||||
-rw-r--r-- | app/models/concerns/ci/has_status.rb | 1 | ||||
-rw-r--r-- | app/models/concerns/ci/metadatable.rb | 1 | ||||
-rw-r--r-- | app/models/concerns/enums/ci/commit_status.rb | 1 | ||||
-rw-r--r-- | app/models/concerns/has_repository.rb | 4 | ||||
-rw-r--r-- | app/models/concerns/integrations/has_data_fields.rb | 1 | ||||
-rw-r--r-- | app/models/concerns/issue_available_features.rb | 3 | ||||
-rw-r--r-- | app/models/concerns/packages/debian/distribution.rb | 10 | ||||
-rw-r--r-- | app/models/concerns/restricted_signup.rb | 42 | ||||
-rw-r--r-- | app/models/concerns/routable.rb | 3 | ||||
-rw-r--r-- | app/models/concerns/ttl_expirable.rb | 20 | ||||
-rw-r--r-- | app/models/concerns/vulnerability_finding_helpers.rb | 9 |
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 > Sign-up restrictions', and check 'Allowed domains for sign-ups'.")).html_safe, + denylist: html_escape_once(_("Go to the 'Admin area > Sign-up restrictions', and check the 'Domain denylist'.")).html_safe, + restricted: html_escape_once(_("Go to the 'Admin area > Sign-up restrictions', and check 'Email restrictions for sign-ups'.")).html_safe, + group_setting: html_escape_once(_("Go to the group’s 'Settings > 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) |