Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2023-08-02 00:10:20 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2023-08-02 00:10:20 +0300
commitcc77bdd6f5f12bea0f50064f3feadcd9c87009a6 (patch)
treeb9347c56663684eaa5939984c9a604dc767f214e /app
parent9cf7b70ac7b17ea3310ebdf83e94d1d5fd248b82 (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app')
-rw-r--r--app/assets/javascripts/commit/pipelines/pipelines_table_wrapper.vue0
-rw-r--r--app/assets/javascripts/diffs/store/mutations.js2
-rw-r--r--app/assets/javascripts/diffs/utils/diff_file.js6
-rw-r--r--app/assets/javascripts/notes/components/diff_with_note.vue3
-rw-r--r--app/assets/javascripts/notes/components/noteable_discussion.vue2
-rw-r--r--app/controllers/projects/pipeline_schedules_controller.rb10
-rw-r--r--app/finders/work_items/namespace_work_items_finder.rb26
-rw-r--r--app/graphql/resolvers/concerns/work_items/look_ahead_preloads.rb57
-rw-r--r--app/graphql/resolvers/namespaces/work_items_resolver.rb32
-rw-r--r--app/graphql/resolvers/work_items_resolver.rb46
-rw-r--r--app/graphql/types/group_type.rb6
-rw-r--r--app/models/concerns/milestoneable.rb4
-rw-r--r--app/models/project.rb11
-rw-r--r--app/models/project_setting.rb11
-rw-r--r--app/models/work_item.rb12
-rw-r--r--app/policies/ci/pipeline_schedule_policy.rb24
-rw-r--r--app/policies/group_policy.rb1
-rw-r--r--app/services/bulk_imports/archive_extraction_service.rb6
-rw-r--r--app/services/bulk_imports/file_decompression_service.rb2
-rw-r--r--app/services/discussions/capture_diff_note_positions_service.rb2
20 files changed, 202 insertions, 61 deletions
diff --git a/app/assets/javascripts/commit/pipelines/pipelines_table_wrapper.vue b/app/assets/javascripts/commit/pipelines/pipelines_table_wrapper.vue
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/app/assets/javascripts/commit/pipelines/pipelines_table_wrapper.vue
diff --git a/app/assets/javascripts/diffs/store/mutations.js b/app/assets/javascripts/diffs/store/mutations.js
index 402b1a82ca4..3af2d6ee6b1 100644
--- a/app/assets/javascripts/diffs/store/mutations.js
+++ b/app/assets/javascripts/diffs/store/mutations.js
@@ -167,7 +167,7 @@ export default {
originalStartLineCode,
...(discussion.line_codes || []),
];
- const fileHash = discussion.diff_file.file_hash;
+ const fileHash = discussion.diff_file?.file_hash;
const lineCheck = (line) =>
discussionLineCodes.some(
(discussionLineCode) =>
diff --git a/app/assets/javascripts/diffs/utils/diff_file.js b/app/assets/javascripts/diffs/utils/diff_file.js
index f2a3224d332..98e1c1cc849 100644
--- a/app/assets/javascripts/diffs/utils/diff_file.js
+++ b/app/assets/javascripts/diffs/utils/diff_file.js
@@ -77,7 +77,7 @@ export function prepareRawDiffFile({ file, allFiles, meta = false, index = -1 })
}
export function collapsedType(file) {
- const isManual = typeof file.viewer?.manuallyCollapsed === 'boolean';
+ const isManual = typeof file?.viewer?.manuallyCollapsed === 'boolean';
return isManual ? DIFF_FILE_MANUAL_COLLAPSE : DIFF_FILE_AUTOMATIC_COLLAPSE;
}
@@ -85,8 +85,8 @@ export function collapsedType(file) {
export function isCollapsed(file) {
const type = collapsedType(file);
const collapsedStates = {
- [DIFF_FILE_AUTOMATIC_COLLAPSE]: file.viewer?.automaticallyCollapsed || false,
- [DIFF_FILE_MANUAL_COLLAPSE]: file.viewer?.manuallyCollapsed,
+ [DIFF_FILE_AUTOMATIC_COLLAPSE]: file?.viewer?.automaticallyCollapsed || false,
+ [DIFF_FILE_MANUAL_COLLAPSE]: file?.viewer?.manuallyCollapsed,
};
return collapsedStates[type];
diff --git a/app/assets/javascripts/notes/components/diff_with_note.vue b/app/assets/javascripts/notes/components/diff_with_note.vue
index db32079e6b9..b1a2ab77fa8 100644
--- a/app/assets/javascripts/notes/components/diff_with_note.vue
+++ b/app/assets/javascripts/notes/components/diff_with_note.vue
@@ -41,7 +41,7 @@ export default {
return getDiffMode(this.discussion.diff_file);
},
diffViewerMode() {
- return this.discussion.diff_file.viewer.name;
+ return this.discussion.diff_file?.viewer.name;
},
fileDiffRefs() {
return this.discussion.diff_file.diff_refs;
@@ -96,6 +96,7 @@ export default {
<template>
<div :class="{ 'text-file': isTextFile }" class="diff-file file-holder">
<diff-file-header
+ v-if="discussion.diff_file"
:discussion-path="discussion.discussion_path"
:diff-file="discussion.diff_file"
:can-current-user-fork="false"
diff --git a/app/assets/javascripts/notes/components/noteable_discussion.vue b/app/assets/javascripts/notes/components/noteable_discussion.vue
index a5939e1023c..7e79edfea15 100644
--- a/app/assets/javascripts/notes/components/noteable_discussion.vue
+++ b/app/assets/javascripts/notes/components/noteable_discussion.vue
@@ -169,7 +169,7 @@ export default {
return !this.discussionResolved ? this.discussion.resolve_with_issue_path : '';
},
canShowReplyActions() {
- if (this.shouldRenderDiffs && !this.discussion.diff_file.diff_refs) {
+ if (this.shouldRenderDiffs && !this.discussion.diff_file?.diff_refs) {
return false;
}
diff --git a/app/controllers/projects/pipeline_schedules_controller.rb b/app/controllers/projects/pipeline_schedules_controller.rb
index 7d69f3459fb..42b6d83ee85 100644
--- a/app/controllers/projects/pipeline_schedules_controller.rb
+++ b/app/controllers/projects/pipeline_schedules_controller.rb
@@ -21,7 +21,6 @@ class Projects::PipelineSchedulesController < Projects::ApplicationController
end
def new
- @schedule = project.pipeline_schedules.new
end
def create
@@ -101,6 +100,15 @@ class Projects::PipelineSchedulesController < Projects::ApplicationController
variables_attributes: [:id, :variable_type, :key, :secret_value, :_destroy])
end
+ def new_schedule
+ # We need the `ref` here for `authorize_create_pipeline_schedule!`
+ @schedule ||= project.pipeline_schedules.new(ref: params.dig(:schedule, :ref))
+ end
+
+ def authorize_create_pipeline_schedule!
+ return access_denied! unless can?(current_user, :create_pipeline_schedule, new_schedule)
+ end
+
def authorize_play_pipeline_schedule!
return access_denied! unless can?(current_user, :play_pipeline_schedule, schedule)
end
diff --git a/app/finders/work_items/namespace_work_items_finder.rb b/app/finders/work_items/namespace_work_items_finder.rb
new file mode 100644
index 00000000000..9a59cf836b5
--- /dev/null
+++ b/app/finders/work_items/namespace_work_items_finder.rb
@@ -0,0 +1,26 @@
+# frozen_string_literal: true
+
+module WorkItems
+ class NamespaceWorkItemsFinder < WorkItemsFinder
+ def execute
+ items = init_collection
+
+ sort(items)
+ end
+
+ override :with_confidentiality_access_check
+ def with_confidentiality_access_check
+ return klass.none unless parent && current_user&.can?("read_#{parent.to_ability_name}".to_sym, parent)
+ return model_class.all if params.user_can_see_all_issuables?
+
+ # Only admins can see hidden issues, so for non-admins, we filter out any hidden issues
+ issues = model_class.without_hidden.in_namespaces(parent)
+
+ return issues.all if params.user_can_see_all_confidential_issues?
+
+ return issues.public_only if params.user_cannot_see_confidential_issues?
+
+ issues.with_confidentiality_check(current_user)
+ end
+ end
+end
diff --git a/app/graphql/resolvers/concerns/work_items/look_ahead_preloads.rb b/app/graphql/resolvers/concerns/work_items/look_ahead_preloads.rb
new file mode 100644
index 00000000000..92fb9ec5cef
--- /dev/null
+++ b/app/graphql/resolvers/concerns/work_items/look_ahead_preloads.rb
@@ -0,0 +1,57 @@
+# frozen_string_literal: true
+
+module WorkItems
+ module LookAheadPreloads
+ extend ActiveSupport::Concern
+
+ prepended do
+ include ::LooksAhead
+ end
+
+ private
+
+ def preloads
+ {
+ work_item_type: :work_item_type,
+ web_url: { namespace: :route, project: [:project_namespace, { namespace: :route }] },
+ widgets: { work_item_type: :enabled_widget_definitions }
+ }
+ end
+
+ def nested_preloads
+ {
+ widgets: widget_preloads,
+ user_permissions: { update_work_item: :assignees },
+ project: { jira_import_status: { project: :jira_imports } },
+ author: {
+ location: { author: :user_detail },
+ gitpod_enabled: { author: :user_preference }
+ }
+ }
+ end
+
+ def widget_preloads
+ {
+ last_edited_by: :last_edited_by,
+ assignees: :assignees,
+ parent: :work_item_parent,
+ children: { work_item_children_by_relative_position: [:author, { project: :project_feature }] },
+ labels: :labels,
+ milestone: { milestone: [:project, :group] },
+ subscribed: [:assignees, :award_emoji, { notes: [:author, :award_emoji] }],
+ award_emoji: { award_emoji: :awardable }
+ }
+ end
+
+ def unconditional_includes
+ [
+ {
+ project: [:project_feature, :group]
+ },
+ :author
+ ]
+ end
+ end
+end
+
+WorkItems::LookAheadPreloads.prepend_mod
diff --git a/app/graphql/resolvers/namespaces/work_items_resolver.rb b/app/graphql/resolvers/namespaces/work_items_resolver.rb
new file mode 100644
index 00000000000..c4a2d3886e6
--- /dev/null
+++ b/app/graphql/resolvers/namespaces/work_items_resolver.rb
@@ -0,0 +1,32 @@
+# frozen_string_literal: true
+
+module Resolvers
+ module Namespaces
+ class WorkItemsResolver < BaseResolver
+ prepend ::WorkItems::LookAheadPreloads
+
+ type Types::WorkItemType.connection_type, null: true
+
+ def resolve_with_lookahead(**args)
+ return unless Feature.enabled?(:namespace_level_work_items)
+ return WorkItem.none if resource_parent.nil?
+
+ finder = ::WorkItems::NamespaceWorkItemsFinder.new(current_user, args)
+
+ Gitlab::Graphql::Loaders::IssuableLoader.new(resource_parent, finder).batching_find_all do |q|
+ apply_lookahead(q)
+ end
+ end
+
+ private
+
+ def resource_parent
+ # The project could have been loaded in batch by `BatchLoader`.
+ # At this point we need the `id` of the project to query for work items, so
+ # make sure it's loaded and not `nil` before continuing.
+ object.respond_to?(:sync) ? object.sync : object
+ end
+ strong_memoize_attr :resource_parent
+ end
+ end
+end
diff --git a/app/graphql/resolvers/work_items_resolver.rb b/app/graphql/resolvers/work_items_resolver.rb
index 14eec4f696a..d4f73361e05 100644
--- a/app/graphql/resolvers/work_items_resolver.rb
+++ b/app/graphql/resolvers/work_items_resolver.rb
@@ -2,8 +2,8 @@
module Resolvers
class WorkItemsResolver < BaseResolver
+ prepend ::WorkItems::LookAheadPreloads
include SearchArguments
- include LooksAhead
include ::WorkItems::SharedFilterArguments
argument :iid,
@@ -28,48 +28,6 @@ module Resolvers
private
- def preloads
- {
- work_item_type: :work_item_type,
- web_url: { namespace: :route, project: [:project_namespace, { namespace: :route }] },
- widgets: { work_item_type: :enabled_widget_definitions }
- }
- end
-
- def nested_preloads
- {
- widgets: widget_preloads,
- user_permissions: { update_work_item: :assignees },
- project: { jira_import_status: { project: :jira_imports } },
- author: {
- location: { author: :user_detail },
- gitpod_enabled: { author: :user_preference }
- }
- }
- end
-
- def widget_preloads
- {
- last_edited_by: :last_edited_by,
- assignees: :assignees,
- parent: :work_item_parent,
- children: { work_item_children_by_relative_position: [:author, { project: :project_feature }] },
- labels: :labels,
- milestone: { milestone: [:project, :group] },
- subscribed: [:assignees, :award_emoji, { notes: [:author, :award_emoji] }],
- award_emoji: { award_emoji: :awardable }
- }
- end
-
- def unconditional_includes
- [
- {
- project: [:project_feature, :group]
- },
- :author
- ]
- end
-
def prepare_finder_params(args)
params = super(args)
params[:iids] ||= [params.delete(:iid)].compact if params[:iid]
@@ -88,4 +46,4 @@ module Resolvers
end
end
-Resolvers::WorkItemsResolver.prepend_mod_with('Resolvers::WorkItemsResolver')
+Resolvers::WorkItemsResolver.prepend_mod
diff --git a/app/graphql/types/group_type.rb b/app/graphql/types/group_type.rb
index 7b8192dd5df..e031958c799 100644
--- a/app/graphql/types/group_type.rb
+++ b/app/graphql/types/group_type.rb
@@ -262,6 +262,12 @@ module Types
resolver: Resolvers::DataTransfer::GroupDataTransferResolver,
description: 'Data transfer data point for a specific period. This is mocked data under a development feature flag.'
+ field :work_items,
+ null: true,
+ description: 'Work items that belong to the namespace.',
+ alpha: { milestone: '16.3' },
+ resolver: ::Resolvers::Namespaces::WorkItemsResolver
+
def label(title:)
BatchLoader::GraphQL.for(title).batch(key: group) do |titles, loader, args|
LabelsFinder
diff --git a/app/models/concerns/milestoneable.rb b/app/models/concerns/milestoneable.rb
index e95a8a42aa6..b72d99d211c 100644
--- a/app/models/concerns/milestoneable.rb
+++ b/app/models/concerns/milestoneable.rb
@@ -52,7 +52,9 @@ module Milestoneable
def milestone_available?
return true if milestone_id.blank?
- project_id == milestone&.project_id || project.ancestors_upto.compact.include?(milestone&.group)
+ (project_id.present? && project_id == milestone&.project_id) ||
+ try(:namespace)&.self_and_ancestors&.include?(milestone&.group) ||
+ project&.ancestors_upto&.compact&.include?(milestone&.group)
end
##
diff --git a/app/models/project.rb b/app/models/project.rb
index 637f4001501..1f68daeef09 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -585,6 +585,8 @@ class Project < ApplicationRecord
validates :max_artifacts_size, numericality: { only_integer: true, greater_than: 0, allow_nil: true }
validates :suggestion_commit_message, length: { maximum: MAX_SUGGESTIONS_TEMPLATE_LENGTH }
+ validate :path_availability, if: :path_changed?
+
# Scopes
scope :pending_delete, -> { where(pending_delete: true) }
scope :without_deleted, -> { where(pending_delete: false) }
@@ -3230,6 +3232,15 @@ class Project < ApplicationRecord
group.crm_enabled?
end
+ def path_availability
+ base, _, host = path.partition('.')
+
+ return unless host == Gitlab.config.pages&.dig('host')
+ return unless ProjectSetting.where(pages_unique_domain: base).exists?
+
+ errors.add(:path, s_('Project|already in use'))
+ end
+
private
# overridden in EE
diff --git a/app/models/project_setting.rb b/app/models/project_setting.rb
index e8573d5c874..fec951eb7fe 100644
--- a/app/models/project_setting.rb
+++ b/app/models/project_setting.rb
@@ -59,6 +59,8 @@ class ProjectSetting < ApplicationRecord
validate :validates_mr_default_target_self
+ validate :pages_unique_domain_availability, if: :pages_unique_domain_changed?
+
attribute :legacy_open_source_license_available, default: -> do
Feature.enabled?(:legacy_open_source_license_available, type: :ops)
end
@@ -114,6 +116,15 @@ class ProjectSetting < ApplicationRecord
pages_unique_domain_enabled ||
pages_unique_domain_in_database.present?
end
+
+ def pages_unique_domain_availability
+ host = Gitlab.config.pages&.dig('host')
+
+ return if host.blank?
+ return unless Project.where(path: "#{pages_unique_domain}.#{host}").exists?
+
+ errors.add(:pages_unique_domain, s_('ProjectSetting|already in use'))
+ end
end
ProjectSetting.prepend_mod
diff --git a/app/models/work_item.rb b/app/models/work_item.rb
index adf424a1d94..216f2ca81e8 100644
--- a/app/models/work_item.rb
+++ b/app/models/work_item.rb
@@ -22,6 +22,18 @@ class WorkItem < Issue
foreign_key: :work_item_id, source: :work_item
scope :inc_relations_for_permission_check, -> { includes(:author, project: :project_feature) }
+ scope :in_namespaces, ->(namespaces) { where(namespace: namespaces) }
+
+ scope :with_confidentiality_check, ->(user) {
+ confidential_query = <<~SQL
+ issues.confidential = FALSE
+ OR (issues.confidential = TRUE
+ AND (issues.author_id = :user_id
+ OR EXISTS (SELECT TRUE FROM issue_assignees WHERE user_id = :user_id AND issue_id = issues.id)))
+ SQL
+
+ where(confidential_query, user_id: user.id)
+ }
class << self
def assignee_association_name
diff --git a/app/policies/ci/pipeline_schedule_policy.rb b/app/policies/ci/pipeline_schedule_policy.rb
index 7b0d484f9f7..cbc60c4a30a 100644
--- a/app/policies/ci/pipeline_schedule_policy.rb
+++ b/app/policies/ci/pipeline_schedule_policy.rb
@@ -5,7 +5,18 @@ module Ci
alias_method :pipeline_schedule, :subject
condition(:protected_ref) do
- ref_protected?(@user, @subject.project, @subject.project.repository.tag_exists?(@subject.ref), @subject.ref)
+ if full_ref?(@subject.ref)
+ is_tag = Gitlab::Git.tag_ref?(@subject.ref)
+ ref_name = Gitlab::Git.ref_name(@subject.ref)
+ else
+ # NOTE: this block should not be removed
+ # until the full ref validation is in place
+ # and all old refs are updated and validated
+ is_tag = @subject.project.repository.tag_exists?(@subject.ref)
+ ref_name = @subject.ref
+ end
+
+ ref_protected?(@user, @subject.project, is_tag, ref_name)
end
condition(:owner_of_schedule) do
@@ -31,6 +42,15 @@ module Ci
enable :take_ownership_pipeline_schedule
end
- rule { protected_ref }.prevent :play_pipeline_schedule
+ rule { protected_ref }.policy do
+ prevent :play_pipeline_schedule
+ prevent :create_pipeline_schedule
+ end
+
+ private
+
+ def full_ref?(ref)
+ Gitlab::Git.tag_ref?(ref) || Gitlab::Git.branch_ref?(ref)
+ end
end
end
diff --git a/app/policies/group_policy.rb b/app/policies/group_policy.rb
index e35312fbd09..f166946db29 100644
--- a/app/policies/group_policy.rb
+++ b/app/policies/group_policy.rb
@@ -148,6 +148,7 @@ class GroupPolicy < Namespaces::GroupProjectNamespaceSharedPolicy
enable :read_group_member
enable :read_custom_emoji
enable :read_counts
+ enable :read_issue
end
rule { achievements_enabled }.policy do
diff --git a/app/services/bulk_imports/archive_extraction_service.rb b/app/services/bulk_imports/archive_extraction_service.rb
index 4485b19035b..bce2a67218a 100644
--- a/app/services/bulk_imports/archive_extraction_service.rb
+++ b/app/services/bulk_imports/archive_extraction_service.rb
@@ -49,11 +49,7 @@ module BulkImports
end
def validate_symlink
- raise(BulkImports::Error, 'Invalid file') if symlink?(filepath)
- end
-
- def symlink?(filepath)
- File.lstat(filepath).symlink?
+ raise(BulkImports::Error, 'Invalid file') if Gitlab::Utils::FileInfo.linked?(filepath)
end
def extract_archive
diff --git a/app/services/bulk_imports/file_decompression_service.rb b/app/services/bulk_imports/file_decompression_service.rb
index 94573f6bb13..77638f10f54 100644
--- a/app/services/bulk_imports/file_decompression_service.rb
+++ b/app/services/bulk_imports/file_decompression_service.rb
@@ -53,7 +53,7 @@ module BulkImports
end
def validate_symlink(filepath)
- raise(ServiceError, 'Invalid file') if File.lstat(filepath).symlink?
+ raise(ServiceError, 'Invalid file') if Gitlab::Utils::FileInfo.linked?(filepath)
end
def decompress_file
diff --git a/app/services/discussions/capture_diff_note_positions_service.rb b/app/services/discussions/capture_diff_note_positions_service.rb
index 3684a3f679a..f9b31e0f2f1 100644
--- a/app/services/discussions/capture_diff_note_positions_service.rb
+++ b/app/services/discussions/capture_diff_note_positions_service.rb
@@ -26,7 +26,7 @@ module Discussions
active_diff_discussions = merge_request.notes.new_diff_notes.discussions.select do |discussion|
discussion.active?(merge_request.diff_refs)
end
- paths = active_diff_discussions.flat_map { |n| n.diff_file.paths }
+ paths = active_diff_discussions.flat_map { |n| n.diff_file&.paths }
[active_diff_discussions, paths]
end