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-10-19 18:07:55 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2023-10-19 18:07:55 +0300
commit3c55affa6684311ca73bc4e3d3bfb17b7541f63b (patch)
treeb15020de36fa6b7c0b10bce78165eea79dc1455e /app
parent881435f2a3eeca1b5b544ad7c7510481b1773d1b (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app')
-rw-r--r--app/assets/javascripts/lib/graphql.js14
-rw-r--r--app/assets/javascripts/pages/users/index.js2
-rw-r--r--app/assets/javascripts/users/profile/components/report_abuse_button.vue58
-rw-r--r--app/assets/javascripts/users/profile/index.js23
-rw-r--r--app/controllers/search_controller.rb11
-rw-r--r--app/finders/ci/runners_finder.rb6
-rw-r--r--app/graphql/resolvers/ci/runners_resolver.rb6
-rw-r--r--app/models/activity_pub.rb7
-rw-r--r--app/models/activity_pub/releases_subscription.rb22
-rw-r--r--app/models/ci/runner.rb2
-rw-r--r--app/models/note.rb6
-rw-r--r--app/services/import/validate_remote_git_endpoint_service.rb81
-rw-r--r--app/validators/json_schemas/activity_pub_follow_payload.json53
-rw-r--r--app/views/users/_cover_controls.html.haml2
-rw-r--r--app/views/users/_profile_basic_info.html.haml4
-rw-r--r--app/views/users/show.html.haml36
16 files changed, 146 insertions, 187 deletions
diff --git a/app/assets/javascripts/lib/graphql.js b/app/assets/javascripts/lib/graphql.js
index 6ab530576fc..5285fa363a5 100644
--- a/app/assets/javascripts/lib/graphql.js
+++ b/app/assets/javascripts/lib/graphql.js
@@ -1,5 +1,4 @@
import { ApolloClient, InMemoryCache, ApolloLink, HttpLink } from '@apollo/client/core';
-import { BatchHttpLink } from '@apollo/client/link/batch-http';
import { createUploadLink } from 'apollo-upload-client';
import { persistCache } from 'apollo3-cache-persist';
import ActionCableLink from '~/actioncable_link';
@@ -116,18 +115,14 @@ Object.defineProperty(window, 'pendingApolloRequests', {
function createApolloClient(resolvers = {}, config = {}) {
const {
baseUrl,
- batchMax = 10,
cacheConfig = { typePolicies: {}, possibleTypes: {} },
fetchPolicy = fetchPolicies.CACHE_FIRST,
typeDefs,
httpHeaders = {},
fetchCredentials = 'same-origin',
path = '/api/graphql',
- useGet = false,
} = config;
- const shouldUnbatch = gon.features?.unbatchGraphqlQueries;
-
let ac = null;
let uri = `${gon.relative_url_root || ''}${path}`;
@@ -146,7 +141,6 @@ function createApolloClient(resolvers = {}, config = {}) {
// We set to `same-origin` which is default value in modern browsers.
// See https://github.com/whatwg/fetch/pull/585 for more information.
credentials: fetchCredentials,
- batchMax,
};
/*
@@ -165,14 +159,10 @@ function createApolloClient(resolvers = {}, config = {}) {
return fetch(stripWhitespaceFromQuery(url, uri), options);
};
- const requestLink = ApolloLink.split(
- () => useGet || shouldUnbatch,
- new HttpLink({ ...httpOptions, fetch: fetchIntervention }),
- new BatchHttpLink(httpOptions),
- );
+ const requestLink = new HttpLink({ ...httpOptions, fetch: fetchIntervention });
const uploadsLink = ApolloLink.split(
- (operation) => operation.getContext().hasUpload || operation.getContext().isSingleRequest,
+ (operation) => operation.getContext().hasUpload,
createUploadLink(httpOptions),
);
diff --git a/app/assets/javascripts/pages/users/index.js b/app/assets/javascripts/pages/users/index.js
index af55a5dc01a..4215cfbf409 100644
--- a/app/assets/javascripts/pages/users/index.js
+++ b/app/assets/javascripts/pages/users/index.js
@@ -1,7 +1,6 @@
import $ from 'jquery';
import { setCookie } from '~/lib/utils/common_utils';
import UserCallout from '~/user_callout';
-import { initReportAbuse } from '~/users/profile';
import { initProfileTabs } from '~/profile';
import UserTabs from './user_tabs';
@@ -25,4 +24,3 @@ const page = $('body').attr('data-page');
const action = page.split(':')[1];
initUserProfile(action);
new UserCallout(); // eslint-disable-line no-new
-initReportAbuse();
diff --git a/app/assets/javascripts/users/profile/components/report_abuse_button.vue b/app/assets/javascripts/users/profile/components/report_abuse_button.vue
deleted file mode 100644
index 0e41a214888..00000000000
--- a/app/assets/javascripts/users/profile/components/report_abuse_button.vue
+++ /dev/null
@@ -1,58 +0,0 @@
-<script>
-import { GlButton, GlTooltipDirective } from '@gitlab/ui';
-import { s__ } from '~/locale';
-import { BV_HIDE_TOOLTIP } from '~/lib/utils/constants';
-
-import AbuseCategorySelector from '~/abuse_reports/components/abuse_category_selector.vue';
-
-export default {
- name: 'ReportAbuseButton',
- components: {
- GlButton,
- AbuseCategorySelector,
- },
- directives: {
- GlTooltip: GlTooltipDirective,
- },
- inject: ['reportedUserId', 'reportedFromUrl'],
- i18n: {
- reportAbuse: s__('ReportAbuse|Report abuse to administrator'),
- },
- data() {
- return {
- open: false,
- };
- },
- computed: {
- buttonTooltipText() {
- return this.$options.i18n.reportAbuse;
- },
- },
- methods: {
- toggleDrawer(open) {
- this.open = open;
- },
- hideTooltips() {
- this.$root.$emit(BV_HIDE_TOOLTIP);
- },
- },
-};
-</script>
-<template>
- <span>
- <gl-button
- v-gl-tooltip="buttonTooltipText"
- category="primary"
- :aria-label="buttonTooltipText"
- icon="error"
- @click="toggleDrawer(true)"
- @mouseout="hideTooltips"
- />
- <abuse-category-selector
- :reported-user-id="reportedUserId"
- :reported-from-url="reportedFromUrl"
- :show-drawer="open"
- @close-drawer="toggleDrawer(false)"
- />
- </span>
-</template>
diff --git a/app/assets/javascripts/users/profile/index.js b/app/assets/javascripts/users/profile/index.js
deleted file mode 100644
index 3ae3cc2de98..00000000000
--- a/app/assets/javascripts/users/profile/index.js
+++ /dev/null
@@ -1,23 +0,0 @@
-import Vue from 'vue';
-import ReportAbuseButton from './components/report_abuse_button.vue';
-
-export const initReportAbuse = () => {
- const el = document.getElementById('js-report-abuse');
-
- if (!el) return false;
-
- const { reportAbusePath, reportedUserId, reportedFromUrl } = el.dataset;
-
- return new Vue({
- el,
- name: 'ReportAbuseButtonRoot',
- provide: {
- reportAbusePath,
- reportedUserId: reportedUserId ? parseInt(reportedUserId, 10) : null,
- reportedFromUrl,
- },
- render(createElement) {
- return createElement(ReportAbuseButton);
- },
- });
-};
diff --git a/app/controllers/search_controller.rb b/app/controllers/search_controller.rb
index 7fff31c767f..8db302530ea 100644
--- a/app/controllers/search_controller.rb
+++ b/app/controllers/search_controller.rb
@@ -4,7 +4,6 @@ class SearchController < ApplicationController
include ControllerWithCrossProjectAccessCheck
include SearchHelper
include ProductAnalyticsTracking
- include ProductAnalyticsTracking
include SearchRateLimitable
RESCUE_FROM_TIMEOUT_ACTIONS = [:count, :show, :autocomplete, :aggregations].freeze
@@ -16,6 +15,12 @@ class SearchController < ApplicationController
action: 'executed',
destinations: [:redis_hll, :snowplow]
+ track_event :autocomplete,
+ name: 'i_search_total',
+ label: 'redis_hll_counters.search.search_total_unique_counts_monthly',
+ action: 'autocomplete',
+ destinations: [:redis_hll, :snowplow]
+
def self.search_rate_limited_endpoints
%i[show count autocomplete]
end
@@ -40,10 +45,6 @@ class SearchController < ApplicationController
end
before_action only: :show do
- push_frontend_feature_flag(:search_issues_hide_archived_projects, current_user)
- end
-
- before_action only: :show do
push_frontend_feature_flag(:search_merge_requests_hide_archived_projects, current_user)
end
diff --git a/app/finders/ci/runners_finder.rb b/app/finders/ci/runners_finder.rb
index 331f732bff7..a716740ac08 100644
--- a/app/finders/ci/runners_finder.rb
+++ b/app/finders/ci/runners_finder.rb
@@ -20,6 +20,7 @@ module Ci
filter_by_upgrade_status!
filter_by_runner_type!
filter_by_tag_list!
+ filter_by_creator_id!
sort!
request_tag_list!
@@ -113,6 +114,11 @@ module Ci
end
end
+ def filter_by_creator_id!
+ creator_id = @params[:creator_id]
+ @runners = @runners.with_creator_id(creator_id) if creator_id.present?
+ end
+
def sort!
@runners = @runners.order_by(sort_key)
end
diff --git a/app/graphql/resolvers/ci/runners_resolver.rb b/app/graphql/resolvers/ci/runners_resolver.rb
index 3289f1d0056..efc692f7bab 100644
--- a/app/graphql/resolvers/ci/runners_resolver.rb
+++ b/app/graphql/resolvers/ci/runners_resolver.rb
@@ -41,6 +41,10 @@ module Resolvers
required: false,
description: 'Filter by upgrade status.'
+ argument :creator_id, ::Types::GlobalIDType[::User].as('UserID'),
+ required: false,
+ description: 'Filter runners by creator ID.'
+
def resolve_with_lookahead(**args)
apply_lookahead(
::Ci::RunnersFinder
@@ -68,6 +72,8 @@ module Resolvers
upgrade_status: params[:upgrade_status],
search: params[:search],
sort: params[:sort]&.to_s,
+ creator_id:
+ params[:creator_id] ? ::GitlabSchema.parse_gid(params[:creator_id], expected_type: ::User).model_id : nil,
preload: false # we'll handle preloading ourselves
}.compact
.merge(parent_param)
diff --git a/app/models/activity_pub.rb b/app/models/activity_pub.rb
new file mode 100644
index 00000000000..9131d8be776
--- /dev/null
+++ b/app/models/activity_pub.rb
@@ -0,0 +1,7 @@
+# frozen_string_literal: true
+
+module ActivityPub
+ def self.table_name_prefix
+ "activity_pub_"
+ end
+end
diff --git a/app/models/activity_pub/releases_subscription.rb b/app/models/activity_pub/releases_subscription.rb
new file mode 100644
index 00000000000..a6304f1fc35
--- /dev/null
+++ b/app/models/activity_pub/releases_subscription.rb
@@ -0,0 +1,22 @@
+# frozen_string_literal: true
+
+module ActivityPub
+ class ReleasesSubscription < ApplicationRecord
+ belongs_to :project, optional: false
+
+ enum :status, [:requested, :accepted], default: :requested
+
+ attribute :payload, Gitlab::Database::Type::JsonPgSafe.new
+
+ validates :payload, json_schema: { filename: 'activity_pub_follow_payload' }, allow_blank: true
+ validates :subscriber_url, presence: true, uniqueness: { case_sensitive: false, scope: :project_id },
+ public_url: true
+ validates :subscriber_inbox_url, uniqueness: { case_sensitive: false, scope: :project_id },
+ public_url: { allow_nil: true }
+ validates :shared_inbox_url, public_url: { allow_nil: true }
+
+ def self.find_by_subscriber_url(subscriber_url)
+ find_by('LOWER(subscriber_url) = ?', subscriber_url.downcase)
+ end
+ end
+end
diff --git a/app/models/ci/runner.rb b/app/models/ci/runner.rb
index 91c919dc662..8a9e51ef133 100644
--- a/app/models/ci/runner.rb
+++ b/app/models/ci/runner.rb
@@ -123,6 +123,8 @@ module Ci
joins(:runner_namespaces).where(ci_runner_namespaces: { namespace_id: group_id })
}
+ scope :with_creator_id, -> (value) { where(creator_id: value) }
+
scope :belonging_to_group_or_project_descendants, -> (group_id) {
group_ids = Ci::NamespaceMirror.by_group_and_descendants(group_id).select(:namespace_id)
project_ids = Ci::ProjectMirror.by_namespace_id(group_ids).select(:project_id)
diff --git a/app/models/note.rb b/app/models/note.rb
index eae7a40fb4e..6f4a56dd3cc 100644
--- a/app/models/note.rb
+++ b/app/models/note.rb
@@ -383,7 +383,11 @@ class Note < ApplicationRecord
end
def for_project_noteable?
- !(for_personal_snippet? || for_abuse_report?)
+ !(for_personal_snippet? || for_abuse_report? || group_level_issue?)
+ end
+
+ def group_level_issue?
+ (for_issue? || for_work_item?) && noteable&.project_id.blank?
end
def for_design?
diff --git a/app/services/import/validate_remote_git_endpoint_service.rb b/app/services/import/validate_remote_git_endpoint_service.rb
index 2177238fddf..a994072c4aa 100644
--- a/app/services/import/validate_remote_git_endpoint_service.rb
+++ b/app/services/import/validate_remote_git_endpoint_service.rb
@@ -13,8 +13,6 @@ module Import
GIT_PROTOCOL_PKT_LEN = 4
GIT_MINIMUM_RESPONSE_LENGTH = GIT_PROTOCOL_PKT_LEN + GIT_EXPECTED_FIRST_PACKET_LINE.length
EXPECTED_CONTENT_TYPE = "application/x-#{GIT_SERVICE_NAME}-advertisement"
- INVALID_BODY_MESSAGE = 'Not a git repository: Invalid response body'
- INVALID_CONTENT_TYPE_MESSAGE = 'Not a git repository: Invalid content-type'
def initialize(params)
@params = params
@@ -32,35 +30,32 @@ module Import
uri.fragment = nil
url = Gitlab::Utils.append_path(uri.to_s, "/info/refs?service=#{GIT_SERVICE_NAME}")
- response, response_body = http_get_and_extract_first_chunks(url)
-
- validate(uri, response, response_body)
- rescue *Gitlab::HTTP::HTTP_ERRORS => err
- error_result("HTTP #{err.class.name.underscore} error: #{err.message}")
- rescue StandardError => err
- ServiceResponse.error(
- message: "Internal #{err.class.name.underscore} error: #{err.message}",
- reason: 500
- )
- end
-
- private
-
- def http_get_and_extract_first_chunks(url)
- # We are interested only in the first chunks of the response
- # So we're using stream_body: true and breaking when receive enough body
- response = nil
response_body = ''
-
- Gitlab::HTTP.get(url, stream_body: true, follow_redirects: false, basic_auth: auth) do |response_chunk|
- response = response_chunk
- response_body += response_chunk
- break if GIT_MINIMUM_RESPONSE_LENGTH <= response_body.length
+ result = nil
+ Gitlab::HTTP.try_get(url, stream_body: true, follow_redirects: false, basic_auth: auth) do |fragment|
+ response_body += fragment
+ next if response_body.length < GIT_MINIMUM_RESPONSE_LENGTH
+
+ result = if status_code_is_valid(fragment) && content_type_is_valid(fragment) && response_body_is_valid(response_body)
+ :success
+ else
+ :error
+ end
+
+ # We are interested only in the first chunks of the response
+ # So we're using stream_body: true and breaking when receive enough body
+ break
end
- [response, response_body]
+ if result == :success
+ ServiceResponse.success
+ else
+ ServiceResponse.error(message: "#{uri} is not a valid HTTP Git repository")
+ end
end
+ private
+
def auth
unless @params[:user].to_s.blank?
{
@@ -70,38 +65,16 @@ module Import
end
end
- def validate(uri, response, response_body)
- return status_code_error(uri, response) unless status_code_is_valid?(response)
- return error_result(INVALID_CONTENT_TYPE_MESSAGE) unless content_type_is_valid?(response)
- return error_result(INVALID_BODY_MESSAGE) unless response_body_is_valid?(response_body)
-
- ServiceResponse.success
- end
-
- def status_code_error(uri, response)
- http_code = response.http_response.code.to_i
- message = response.http_response.message || Rack::Utils::HTTP_STATUS_CODES[http_code]
-
- error_result(
- "#{uri} endpoint error: #{http_code}#{message.presence&.prepend(' ')}",
- http_code
- )
- end
-
- def error_result(message, reason = nil)
- ServiceResponse.error(message: message, reason: reason)
- end
-
- def status_code_is_valid?(response)
- response.http_response.code == '200'
+ def status_code_is_valid(fragment)
+ fragment.http_response.code == '200'
end
- def content_type_is_valid?(response)
- response.http_response['content-type'] == EXPECTED_CONTENT_TYPE
+ def content_type_is_valid(fragment)
+ fragment.http_response['content-type'] == EXPECTED_CONTENT_TYPE
end
- def response_body_is_valid?(response_body)
- response_body.length <= GIT_MINIMUM_RESPONSE_LENGTH && response_body.match?(GIT_BODY_MESSAGE_REGEXP)
+ def response_body_is_valid(response_body)
+ response_body.match?(GIT_BODY_MESSAGE_REGEXP)
end
end
end
diff --git a/app/validators/json_schemas/activity_pub_follow_payload.json b/app/validators/json_schemas/activity_pub_follow_payload.json
new file mode 100644
index 00000000000..1f453ce840f
--- /dev/null
+++ b/app/validators/json_schemas/activity_pub_follow_payload.json
@@ -0,0 +1,53 @@
+{
+ "description": "ActivityPub Follow activity payload",
+ "type": "object",
+ "required": [
+ "@context",
+ "id",
+ "type",
+ "actor",
+ "object"
+ ],
+ "properties": {
+ "@context": {
+ "oneOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "array"
+ }
+ ]
+ },
+ "id": {
+ "type": "string"
+ },
+ "type": {
+ "type": "string"
+ },
+ "actor": {
+ "oneOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "object",
+ "required": [
+ "id"
+ ],
+ "id": {
+ "type": "string"
+ },
+ "inbox": {
+ "type": "string"
+ },
+ "additionalProperties": true
+ }
+ ]
+ },
+ "object": {
+ "type": "string"
+ },
+ "additionalProperties": true
+ }
+}
diff --git a/app/views/users/_cover_controls.html.haml b/app/views/users/_cover_controls.html.haml
deleted file mode 100644
index 899a08c8a17..00000000000
--- a/app/views/users/_cover_controls.html.haml
+++ /dev/null
@@ -1,2 +0,0 @@
-.cover-controls.gl-display-flex.gl-gap-3.gl-pb-4
- = yield
diff --git a/app/views/users/_profile_basic_info.html.haml b/app/views/users/_profile_basic_info.html.haml
index 6de9e80008e..7dd131dbe2c 100644
--- a/app/views/users/_profile_basic_info.html.haml
+++ b/app/views/users/_profile_basic_info.html.haml
@@ -2,9 +2,5 @@
= render 'middle_dot_divider', stacking: true do
@#{@user.username}
- if can?(current_user, :read_user_profile, @user)
- - unless Feature.enabled?(:user_profile_overflow_menu_vue)
- = render 'middle_dot_divider', stacking: true do
- = s_('UserProfile|User ID: %{id}') % { id: @user.id }
- = clipboard_button(title: s_('UserProfile|Copy user ID'), text: @user.id)
= render 'middle_dot_divider', stacking: true do
= s_('Member since %{date}') % { date: l(@user.created_at.to_date, format: :long) }
diff --git a/app/views/users/show.html.haml b/app/views/users/show.html.haml
index 0881c5bba54..034e7f18bbe 100644
--- a/app/views/users/show.html.haml
+++ b/app/views/users/show.html.haml
@@ -17,32 +17,16 @@
.user-profile
.cover-block.user-cover-block.gl-border-t.gl-border-b.gl-mt-n1
%div{ class: container_class }
- - if Feature.enabled?(:user_profile_overflow_menu_vue)
- .cover-controls.gl-display-flex.gl-gap-3.gl-pb-4
- = render 'users/follow_user'
- -# The following edit button is mutually exclusive to the follow user button, they won't be shown together
- - if @user == current_user
- = render Pajamas::ButtonComponent.new(href: profile_path,
- button_options: { class: 'gl-flex-grow-1', title: s_('UserProfile|Edit profile') }) do
- = s_("UserProfile|Edit profile")
- = render 'users/view_gpg_keys'
- = render 'users/view_user_in_admin_area'
- .js-user-profile-actions{ data: user_profile_actions_data(@user) }
- - else
- = render layout: 'users/cover_controls' do
- - if @user == current_user
- = render Pajamas::ButtonComponent.new(href: profile_path,
- icon: 'pencil',
- button_options: { class: 'gl-flex-grow-1 has-tooltip', title: s_('UserProfile|Edit profile'), 'aria-label': 'Edit profile', data: { toggle: 'tooltip', placement: 'bottom', container: 'body' }})
- - elsif current_user
- #js-report-abuse{ data: { report_abuse_path: add_category_abuse_reports_path, reported_user_id: @user.id, reported_from_url: user_url(@user) } }
- = render 'users/view_gpg_keys'
- - if can?(current_user, :read_user_profile, @user)
- = render Pajamas::ButtonComponent.new(href: user_path(@user, rss_url_options),
- icon: 'rss',
- button_options: { class: 'gl-flex-grow-1 has-tooltip', title: s_('UserProfile|Subscribe'), data: { toggle: 'tooltip', placement: 'bottom', container: 'body' }})
- = render 'users/view_user_in_admin_area'
- = render 'users/follow_user'
+ .cover-controls.gl-display-flex.gl-gap-3.gl-pb-4
+ = render 'users/follow_user'
+ -# The following edit button is mutually exclusive to the follow user button, they won't be shown together
+ - if @user == current_user
+ = render Pajamas::ButtonComponent.new(href: profile_path,
+ button_options: { class: 'gl-flex-grow-1', title: s_('UserProfile|Edit profile') }) do
+ = s_("UserProfile|Edit profile")
+ = render 'users/view_gpg_keys'
+ = render 'users/view_user_in_admin_area'
+ .js-user-profile-actions{ data: user_profile_actions_data(@user) }
.profile-header{ class: [('with-no-profile-tabs' if profile_tabs.empty?), ('gl-mb-4!' if show_super_sidebar?)] }
.gl-display-inline-block.gl-mx-8.gl-vertical-align-top