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
diff options
context:
space:
mode:
Diffstat (limited to 'app/controllers')
-rw-r--r--app/controllers/admin/application_settings_controller.rb9
-rw-r--r--app/controllers/admin/broadcast_messages_controller.rb2
-rw-r--r--app/controllers/admin/clusters_controller.rb1
-rw-r--r--app/controllers/admin/cohorts_controller.rb2
-rw-r--r--app/controllers/admin/dev_ops_report_controller.rb2
-rw-r--r--app/controllers/admin/instance_review_controller.rb2
-rw-r--r--app/controllers/admin/integrations_controller.rb4
-rw-r--r--app/controllers/admin/runner_projects_controller.rb5
-rw-r--r--app/controllers/admin/runners_controller.rb8
-rw-r--r--app/controllers/admin/usage_trends_controller.rb2
-rw-r--r--app/controllers/admin/users_controller.rb4
-rw-r--r--app/controllers/application_controller.rb15
-rw-r--r--app/controllers/autocomplete_controller.rb10
-rw-r--r--app/controllers/clusters/clusters_controller.rb26
-rw-r--r--app/controllers/concerns/floc_opt_out.rb2
-rw-r--r--app/controllers/concerns/issuable_actions.rb14
-rw-r--r--app/controllers/concerns/issuable_collections_action.rb2
-rw-r--r--app/controllers/concerns/membership_actions.rb15
-rw-r--r--app/controllers/concerns/product_analytics_tracking.rb27
-rw-r--r--app/controllers/concerns/search_rate_limitable.rb15
-rw-r--r--app/controllers/concerns/sessionless_authentication.rb3
-rw-r--r--app/controllers/concerns/spammable_actions/akismet_mark_as_spam_action.rb11
-rw-r--r--app/controllers/concerns/spammable_actions/attributes.rb13
-rw-r--r--app/controllers/concerns/spammable_actions/captcha_check/common.rb32
-rw-r--r--app/controllers/concerns/spammable_actions/captcha_check/html_format_actions_support.rb5
-rw-r--r--app/controllers/concerns/spammable_actions/captcha_check/json_format_actions_support.rb11
-rw-r--r--app/controllers/concerns/spammable_actions/captcha_check/rest_api_actions_support.rb39
-rw-r--r--app/controllers/concerns/uploads_actions.rb2
-rw-r--r--app/controllers/dashboard/projects_controller.rb2
-rw-r--r--app/controllers/dashboard_controller.rb15
-rw-r--r--app/controllers/groups/application_controller.rb4
-rw-r--r--app/controllers/groups/boards_controller.rb1
-rw-r--r--app/controllers/groups/clusters_controller.rb1
-rw-r--r--app/controllers/groups/crm/contacts_controller.rb1
-rw-r--r--app/controllers/groups/crm/organizations_controller.rb1
-rw-r--r--app/controllers/groups/deploy_tokens_controller.rb3
-rw-r--r--app/controllers/groups/group_members_controller.rb6
-rw-r--r--app/controllers/groups/harbor/repositories_controller.rb24
-rw-r--r--app/controllers/groups/releases_controller.rb16
-rw-r--r--app/controllers/groups/runners_controller.rb14
-rw-r--r--app/controllers/groups/settings/ci_cd_controller.rb2
-rw-r--r--app/controllers/groups/settings/integrations_controller.rb4
-rw-r--r--app/controllers/groups/uploads_controller.rb2
-rw-r--r--app/controllers/groups_controller.rb4
-rw-r--r--app/controllers/jira_connect/events_controller.rb30
-rw-r--r--app/controllers/jira_connect/oauth_callbacks_controller.rb11
-rw-r--r--app/controllers/jira_connect/subscriptions_controller.rb4
-rw-r--r--app/controllers/profiles_controller.rb2
-rw-r--r--app/controllers/projects/application_controller.rb7
-rw-r--r--app/controllers/projects/blob_controller.rb18
-rw-r--r--app/controllers/projects/boards_controller.rb1
-rw-r--r--app/controllers/projects/builds_controller.rb3
-rw-r--r--app/controllers/projects/ci/pipeline_editor_controller.rb8
-rw-r--r--app/controllers/projects/ci/secure_files_controller.rb10
-rw-r--r--app/controllers/projects/cluster_agents_controller.rb4
-rw-r--r--app/controllers/projects/commit_controller.rb1
-rw-r--r--app/controllers/projects/commits_controller.rb2
-rw-r--r--app/controllers/projects/deploy_tokens_controller.rb2
-rw-r--r--app/controllers/projects/environments_controller.rb12
-rw-r--r--app/controllers/projects/error_tracking_controller.rb8
-rw-r--r--app/controllers/projects/forks_controller.rb8
-rw-r--r--app/controllers/projects/google_cloud/base_controller.rb27
-rw-r--r--app/controllers/projects/google_cloud/deployments_controller.rb5
-rw-r--r--app/controllers/projects/google_cloud/gcp_regions_controller.rb31
-rw-r--r--app/controllers/projects/google_cloud/revoke_oauth_controller.rb23
-rw-r--r--app/controllers/projects/google_cloud/service_accounts_controller.rb25
-rw-r--r--app/controllers/projects/google_cloud_controller.rb26
-rw-r--r--app/controllers/projects/harbor/application_controller.rb22
-rw-r--r--app/controllers/projects/harbor/repositories_controller.rb11
-rw-r--r--app/controllers/projects/incidents_controller.rb7
-rw-r--r--app/controllers/projects/issues_controller.rb30
-rw-r--r--app/controllers/projects/jobs_controller.rb2
-rw-r--r--app/controllers/projects/merge_requests/diffs_controller.rb4
-rw-r--r--app/controllers/projects/merge_requests_controller.rb21
-rw-r--r--app/controllers/projects/pipeline_schedules_controller.rb4
-rw-r--r--app/controllers/projects/pipelines/stages_controller.rb4
-rw-r--r--app/controllers/projects/pipelines/tests_controller.rb4
-rw-r--r--app/controllers/projects/pipelines_controller.rb58
-rw-r--r--app/controllers/projects/project_members_controller.rb21
-rw-r--r--app/controllers/projects/redirect_controller.rb20
-rw-r--r--app/controllers/projects/releases_controller.rb33
-rw-r--r--app/controllers/projects/runner_projects_controller.rb5
-rw-r--r--app/controllers/projects/runners_controller.rb8
-rw-r--r--app/controllers/projects/serverless/functions_controller.rb5
-rw-r--r--app/controllers/projects/services_controller.rb4
-rw-r--r--app/controllers/projects/settings/ci_cd_controller.rb2
-rw-r--r--app/controllers/projects/settings/operations_controller.rb4
-rw-r--r--app/controllers/projects/tags_controller.rb2
-rw-r--r--app/controllers/projects/tree_controller.rb1
-rw-r--r--app/controllers/projects_controller.rb27
-rw-r--r--app/controllers/registrations_controller.rb2
-rw-r--r--app/controllers/search_controller.rb10
-rw-r--r--app/controllers/uploads_controller.rb45
-rw-r--r--app/controllers/users_controller.rb4
94 files changed, 672 insertions, 339 deletions
diff --git a/app/controllers/admin/application_settings_controller.rb b/app/controllers/admin/application_settings_controller.rb
index 1d0930ba73c..0dd85376050 100644
--- a/app/controllers/admin/application_settings_controller.rb
+++ b/app/controllers/admin/application_settings_controller.rb
@@ -66,12 +66,17 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController
render html: Gitlab::Highlight.highlight('payload.json', usage_data_json, language: 'json')
end
- format.json { render json: Gitlab::Usage::ServicePingReport.for(output: :all_metrics_values, cached: true).to_json }
+
+ format.json do
+ Gitlab::UsageDataCounters::ServiceUsageDataCounter.count(:download_payload_click)
+
+ render json: Gitlab::Usage::ServicePingReport.for(output: :all_metrics_values, cached: true).to_json
+ end
end
end
def reset_registration_token
- @application_setting.reset_runners_registration_token!
+ ::Ci::Runners::ResetRegistrationTokenService.new(@application_setting, current_user).execute
flash[:notice] = _('New runners registration token has been generated!')
redirect_to admin_runners_path
diff --git a/app/controllers/admin/broadcast_messages_controller.rb b/app/controllers/admin/broadcast_messages_controller.rb
index 4660b0bfbb0..ef843a84e6c 100644
--- a/app/controllers/admin/broadcast_messages_controller.rb
+++ b/app/controllers/admin/broadcast_messages_controller.rb
@@ -65,6 +65,6 @@ class Admin::BroadcastMessagesController < Admin::ApplicationController
target_path
broadcast_type
dismissable
- ))
+ ), target_access_levels: []).reverse_merge!(target_access_levels: [])
end
end
diff --git a/app/controllers/admin/clusters_controller.rb b/app/controllers/admin/clusters_controller.rb
index 9a642e53d86..052c8821588 100644
--- a/app/controllers/admin/clusters_controller.rb
+++ b/app/controllers/admin/clusters_controller.rb
@@ -2,6 +2,7 @@
class Admin::ClustersController < Clusters::ClustersController
include EnforcesAdminAuthentication
+ before_action :ensure_feature_enabled!
layout 'admin'
diff --git a/app/controllers/admin/cohorts_controller.rb b/app/controllers/admin/cohorts_controller.rb
index e750b5c5ad4..468a1077694 100644
--- a/app/controllers/admin/cohorts_controller.rb
+++ b/app/controllers/admin/cohorts_controller.rb
@@ -5,6 +5,8 @@ class Admin::CohortsController < Admin::ApplicationController
feature_category :devops_reports
+ urgency :low
+
def index
@cohorts = load_cohorts
track_cohorts_visit
diff --git a/app/controllers/admin/dev_ops_report_controller.rb b/app/controllers/admin/dev_ops_report_controller.rb
index a235af7c538..47e3337aed7 100644
--- a/app/controllers/admin/dev_ops_report_controller.rb
+++ b/app/controllers/admin/dev_ops_report_controller.rb
@@ -9,6 +9,8 @@ class Admin::DevOpsReportController < Admin::ApplicationController
feature_category :devops_reports
+ urgency :low
+
# rubocop: disable CodeReuse/ActiveRecord
def show
@metric = DevOpsReport::Metric.order(:created_at).last&.present
diff --git a/app/controllers/admin/instance_review_controller.rb b/app/controllers/admin/instance_review_controller.rb
index 1ce6e66c6de..cc801bce5b7 100644
--- a/app/controllers/admin/instance_review_controller.rb
+++ b/app/controllers/admin/instance_review_controller.rb
@@ -2,6 +2,8 @@
class Admin::InstanceReviewController < Admin::ApplicationController
feature_category :devops_reports
+ urgency :low
+
def index
redirect_to("#{Gitlab::SubscriptionPortal.subscriptions_instance_review_url}?#{instance_review_params}")
end
diff --git a/app/controllers/admin/integrations_controller.rb b/app/controllers/admin/integrations_controller.rb
index ad0ee0b2cef..db9835e65ec 100644
--- a/app/controllers/admin/integrations_controller.rb
+++ b/app/controllers/admin/integrations_controller.rb
@@ -5,6 +5,10 @@ class Admin::IntegrationsController < Admin::ApplicationController
before_action :not_found, unless: -> { instance_level_integrations? }
+ before_action do
+ push_frontend_feature_flag(:integration_form_sections, default_enabled: :yaml)
+ end
+
feature_category :integrations
def overrides
diff --git a/app/controllers/admin/runner_projects_controller.rb b/app/controllers/admin/runner_projects_controller.rb
index 598c536d652..a4055cbe990 100644
--- a/app/controllers/admin/runner_projects_controller.rb
+++ b/app/controllers/admin/runner_projects_controller.rb
@@ -8,7 +8,7 @@ class Admin::RunnerProjectsController < Admin::ApplicationController
def create
@runner = Ci::Runner.find(params[:runner_project][:runner_id])
- if @runner.assign_to(@project, current_user)
+ if ::Ci::Runners::AssignRunnerService.new(@runner, @project, current_user).execute
redirect_to edit_admin_runner_url(@runner), notice: s_('Runners|Runner assigned to project.')
else
redirect_to edit_admin_runner_url(@runner), alert: 'Failed adding runner to project'
@@ -18,7 +18,8 @@ class Admin::RunnerProjectsController < Admin::ApplicationController
def destroy
rp = Ci::RunnerProject.find(params[:id])
runner = rp.runner
- rp.destroy
+
+ ::Ci::Runners::UnassignRunnerService.new(rp, current_user).execute
redirect_to edit_admin_runner_url(runner), status: :found, notice: s_('Runners|Runner unassigned from project.')
end
diff --git a/app/controllers/admin/runners_controller.rb b/app/controllers/admin/runners_controller.rb
index f7f78ab3229..2744be0150c 100644
--- a/app/controllers/admin/runners_controller.rb
+++ b/app/controllers/admin/runners_controller.rb
@@ -23,7 +23,7 @@ class Admin::RunnersController < Admin::ApplicationController
end
def update
- if Ci::UpdateRunnerService.new(@runner).update(runner_params)
+ if Ci::Runners::UpdateRunnerService.new(@runner).update(runner_params)
respond_to do |format|
format.html { redirect_to edit_admin_runner_path(@runner) }
end
@@ -34,13 +34,13 @@ class Admin::RunnersController < Admin::ApplicationController
end
def destroy
- Ci::UnregisterRunnerService.new(@runner).execute
+ Ci::Runners::UnregisterRunnerService.new(@runner, current_user).execute
redirect_to admin_runners_path, status: :found
end
def resume
- if Ci::UpdateRunnerService.new(@runner).update(active: true)
+ if Ci::Runners::UpdateRunnerService.new(@runner).update(active: true)
redirect_to admin_runners_path, notice: _('Runner was successfully updated.')
else
redirect_to admin_runners_path, alert: _('Runner was not updated.')
@@ -48,7 +48,7 @@ class Admin::RunnersController < Admin::ApplicationController
end
def pause
- if Ci::UpdateRunnerService.new(@runner).update(active: false)
+ if Ci::Runners::UpdateRunnerService.new(@runner).update(active: false)
redirect_to admin_runners_path, notice: _('Runner was successfully updated.')
else
redirect_to admin_runners_path, alert: _('Runner was not updated.')
diff --git a/app/controllers/admin/usage_trends_controller.rb b/app/controllers/admin/usage_trends_controller.rb
index 0b315517594..2cede1aec05 100644
--- a/app/controllers/admin/usage_trends_controller.rb
+++ b/app/controllers/admin/usage_trends_controller.rb
@@ -7,6 +7,8 @@ class Admin::UsageTrendsController < Admin::ApplicationController
feature_category :devops_reports
+ urgency :low
+
def index
end
end
diff --git a/app/controllers/admin/users_controller.rb b/app/controllers/admin/users_controller.rb
index c1fa104ffda..f19333d5d57 100644
--- a/app/controllers/admin/users_controller.rb
+++ b/app/controllers/admin/users_controller.rb
@@ -2,6 +2,7 @@
class Admin::UsersController < Admin::ApplicationController
include RoutableActions
+ include SortingHelper
before_action :user, except: [:index, :new, :create]
before_action :check_impersonation_availability, only: :impersonate
@@ -18,7 +19,8 @@ class Admin::UsersController < Admin::ApplicationController
@users = User.filter_items(params[:filter]).order_name_asc
@users = @users.search(params[:search_query], with_private_emails: true) if params[:search_query].present?
@users = users_with_included_associations(@users)
- @users = @users.sort_by_attribute(@sort = params[:sort])
+ @sort = params[:sort].presence || sort_value_name
+ @users = @users.sort_by_attribute(@sort)
@users = @users.page(params[:page])
@users = @users.without_count if paginate_without_count?
end
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index 8e758c669db..1d17e8aa085 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -111,6 +111,15 @@ class ApplicationController < ActionController::Base
render plain: e.message, status: :too_many_requests
end
+ content_security_policy do |p|
+ next if p.directives.blank?
+ next unless Gitlab::CurrentSettings.snowplow_enabled? && !Gitlab::CurrentSettings.snowplow_collector_hostname.blank?
+
+ default_connect_src = p.directives['connect-src'] || p.directives['default-src']
+ connect_src_values = Array.wrap(default_connect_src) | [Gitlab::CurrentSettings.snowplow_collector_hostname]
+ p.connect_src(*connect_src_values)
+ end
+
def redirect_back_or_default(default: root_path, options: {})
redirect_back(fallback_location: default, **options)
end
@@ -237,19 +246,19 @@ class ApplicationController < ActionController::Base
end
def git_not_found!
- render "errors/git_not_found.html", layout: "errors", status: :not_found
+ render template: "errors/git_not_found", formats: :html, layout: "errors", status: :not_found
end
def render_403
respond_to do |format|
- format.html { render "errors/access_denied", layout: "errors", status: :forbidden }
+ format.html { render template: "errors/access_denied", formats: :html, layout: "errors", status: :forbidden }
format.any { head :forbidden }
end
end
def render_404
respond_to do |format|
- format.html { render "errors/not_found", layout: "errors", status: :not_found }
+ format.html { render template: "errors/not_found", formats: :html, layout: "errors", status: :not_found }
# Prevent the Rails CSRF protector from thinking a missing .js file is a JavaScript file
format.js { render json: '', status: :not_found, content_type: 'application/json' }
format.any { head :not_found }
diff --git a/app/controllers/autocomplete_controller.rb b/app/controllers/autocomplete_controller.rb
index ee5caf63703..4bcd1be9f53 100644
--- a/app/controllers/autocomplete_controller.rb
+++ b/app/controllers/autocomplete_controller.rb
@@ -1,8 +1,10 @@
# frozen_string_literal: true
class AutocompleteController < ApplicationController
+ include SearchRateLimitable
+
skip_before_action :authenticate_user!, only: [:users, :award_emojis, :merge_request_target_branches]
- before_action :check_email_search_rate_limit!, only: [:users]
+ before_action :check_search_rate_limit!, only: [:users, :projects]
feature_category :users, [:users, :user]
feature_category :projects, [:projects]
@@ -72,12 +74,6 @@ class AutocompleteController < ApplicationController
def target_branch_params
params.permit(:group_id, :project_id).select { |_, v| v.present? }
end
-
- def check_email_search_rate_limit!
- search_params = Gitlab::Search::Params.new(params)
-
- check_rate_limit!(:user_email_lookup, scope: [current_user]) if search_params.email_lookup?
- end
end
AutocompleteController.prepend_mod_with('AutocompleteController')
diff --git a/app/controllers/clusters/clusters_controller.rb b/app/controllers/clusters/clusters_controller.rb
index c12ceca9c3b..d9179129983 100644
--- a/app/controllers/clusters/clusters_controller.rb
+++ b/app/controllers/clusters/clusters_controller.rb
@@ -9,15 +9,25 @@ class Clusters::ClustersController < Clusters::BaseController
before_action :generate_gcp_authorize_url, only: [:new]
before_action :validate_gcp_token, only: [:new]
before_action :gcp_cluster, only: [:new]
- before_action :user_cluster, only: [:new]
+ before_action :user_cluster, only: [:new, :connect]
before_action :authorize_read_cluster!, only: [:show, :index]
- before_action :authorize_create_cluster!, only: [:new, :authorize_aws_role]
+ before_action :authorize_create_cluster!, only: [:new, :connect, :authorize_aws_role]
before_action :authorize_update_cluster!, only: [:update]
before_action :update_applications_status, only: [:cluster_status]
+ before_action :ensure_feature_enabled!, except: :index
helper_method :token_in_session
STATUS_POLLING_INTERVAL = 10_000
+ AWS_CSP_DOMAINS = %w[https://ec2.ap-east-1.amazonaws.com https://ec2.ap-northeast-1.amazonaws.com https://ec2.ap-northeast-2.amazonaws.com https://ec2.ap-northeast-3.amazonaws.com https://ec2.ap-south-1.amazonaws.com https://ec2.ap-southeast-1.amazonaws.com https://ec2.ap-southeast-2.amazonaws.com https://ec2.ca-central-1.amazonaws.com https://ec2.eu-central-1.amazonaws.com https://ec2.eu-north-1.amazonaws.com https://ec2.eu-west-1.amazonaws.com https://ec2.eu-west-2.amazonaws.com https://ec2.eu-west-3.amazonaws.com https://ec2.me-south-1.amazonaws.com https://ec2.sa-east-1.amazonaws.com https://ec2.us-east-1.amazonaws.com https://ec2.us-east-2.amazonaws.com https://ec2.us-west-1.amazonaws.com https://ec2.us-west-2.amazonaws.com https://ec2.af-south-1.amazonaws.com https://iam.amazonaws.com].freeze
+
+ content_security_policy do |p|
+ next if p.directives.blank?
+
+ default_connect_src = p.directives['connect-src'] || p.directives['default-src']
+ connect_src_values = Array.wrap(default_connect_src) | AWS_CSP_DOMAINS
+ p.connect_src(*connect_src_values)
+ end
def index
@clusters = cluster_list
@@ -142,7 +152,7 @@ class Clusters::ClustersController < Clusters::BaseController
validate_gcp_token
gcp_cluster
- render :new, locals: { active_tab: 'add' }
+ render :connect
end
end
@@ -163,7 +173,17 @@ class Clusters::ClustersController < Clusters::BaseController
private
+ def certificate_based_clusters_enabled?
+ Feature.enabled?(:certificate_based_clusters, clusterable, default_enabled: :yaml, type: :ops)
+ end
+
+ def ensure_feature_enabled!
+ render_404 unless certificate_based_clusters_enabled?
+ end
+
def cluster_list
+ return [] unless certificate_based_clusters_enabled?
+
finder = ClusterAncestorsFinder.new(clusterable.subject, current_user)
clusters = finder.execute
diff --git a/app/controllers/concerns/floc_opt_out.rb b/app/controllers/concerns/floc_opt_out.rb
index 3039af02bbb..50a52cecda9 100644
--- a/app/controllers/concerns/floc_opt_out.rb
+++ b/app/controllers/concerns/floc_opt_out.rb
@@ -4,7 +4,7 @@ module FlocOptOut
extend ActiveSupport::Concern
included do
- after_action :set_floc_opt_out_header, unless: :floc_enabled?
+ before_action :set_floc_opt_out_header, unless: :floc_enabled?
end
def floc_enabled?
diff --git a/app/controllers/concerns/issuable_actions.rb b/app/controllers/concerns/issuable_actions.rb
index eae087bca4d..ae90bd59d01 100644
--- a/app/controllers/concerns/issuable_actions.rb
+++ b/app/controllers/concerns/issuable_actions.rb
@@ -17,10 +17,6 @@ module IssuableActions
def show
respond_to do |format|
format.html do
- @show_crm_contacts = issuable.is_a?(Issue) && # rubocop:disable Gitlab/ModuleWithInstanceVariables
- can?(current_user, :read_crm_contact, issuable.project.group) &&
- CustomerRelations::Contact.exists_for_group?(issuable.project.group)
-
@issuable_sidebar = serializer.represent(issuable, serializer: 'sidebar') # rubocop:disable Gitlab/ModuleWithInstanceVariables
render 'show'
end
@@ -43,18 +39,18 @@ module IssuableActions
if updated_issuable.is_a?(Spammable)
respond_to do |format|
format.html do
- # NOTE: This redirect is intentionally only performed in the case where the updated
- # issuable is a spammable, and intentionally is not performed in the non-spammable case.
- # This preserves the legacy behavior of this action.
if updated_issuable.valid?
+ # NOTE: This redirect is intentionally only performed in the case where the valid updated
+ # issuable is a spammable, and intentionally is not performed below in the
+ # valid non-spammable case. This preserves the legacy behavior of this action.
redirect_to spammable_path
else
- with_captcha_check_html_format { render :edit }
+ with_captcha_check_html_format(spammable: spammable) { render :edit }
end
end
format.json do
- with_captcha_check_json_format { render_entity_json }
+ with_captcha_check_json_format(spammable: spammable) { render_entity_json }
end
end
else
diff --git a/app/controllers/concerns/issuable_collections_action.rb b/app/controllers/concerns/issuable_collections_action.rb
index b68db0e3f9f..96cf6021ea9 100644
--- a/app/controllers/concerns/issuable_collections_action.rb
+++ b/app/controllers/concerns/issuable_collections_action.rb
@@ -17,7 +17,7 @@ module IssuableCollectionsAction
respond_to do |format|
format.html
- format.atom { render layout: 'xml.atom' }
+ format.atom { render layout: 'xml' }
end
end
diff --git a/app/controllers/concerns/membership_actions.rb b/app/controllers/concerns/membership_actions.rb
index f716c1f6c2f..0b9024dc3db 100644
--- a/app/controllers/concerns/membership_actions.rb
+++ b/app/controllers/concerns/membership_actions.rb
@@ -4,17 +4,6 @@ module MembershipActions
include MembersPresentation
extend ActiveSupport::Concern
- def create
- create_params = params.permit(:user_ids, :access_level, :expires_at)
- result = Members::CreateService.new(current_user, create_params.merge({ source: membershipable, invite_source: "#{plain_source_type}-members-page" })).execute
-
- if result[:status] == :success
- redirect_to members_page_url, notice: _('Users were successfully added.')
- else
- redirect_to members_page_url, alert: result[:message]
- end
- end
-
def update
update_params = params.require(root_params_key).permit(:access_level, :expires_at)
member = membershipable.members_and_requesters.find(params[:id])
@@ -79,8 +68,8 @@ module MembershipActions
notice: _('Your request for access has been queued for review.')
else
redirect_to polymorphic_path(membershipable),
- alert: _("Your request for access could not be processed: %{error_meesage}") %
- { error_meesage: access_requester.errors.full_messages.to_sentence }
+ alert: _("Your request for access could not be processed: %{error_message}") %
+ { error_message: access_requester.errors.full_messages.to_sentence }
end
end
diff --git a/app/controllers/concerns/product_analytics_tracking.rb b/app/controllers/concerns/product_analytics_tracking.rb
new file mode 100644
index 00000000000..03296d6b233
--- /dev/null
+++ b/app/controllers/concerns/product_analytics_tracking.rb
@@ -0,0 +1,27 @@
+# frozen_string_literal: true
+
+module ProductAnalyticsTracking
+ include Gitlab::Tracking::Helpers
+ include RedisTracking
+ extend ActiveSupport::Concern
+
+ class_methods do
+ def track_event(*controller_actions, name:, conditions: nil, destinations: [:redis_hll], &block)
+ custom_conditions = [:trackable_html_request?, *conditions]
+
+ after_action only: controller_actions, if: custom_conditions do
+ route_events_to(destinations, name, &block)
+ end
+ end
+ end
+
+ private
+
+ def route_events_to(destinations, name, &block)
+ track_unique_redis_hll_event(name, &block) if destinations.include?(:redis_hll)
+
+ if destinations.include?(:snowplow) && Feature.enabled?(:route_hll_to_snowplow, tracking_namespace_source, default_enabled: :yaml)
+ Gitlab::Tracking.event(self.class.to_s, name, namespace: tracking_namespace_source, user: current_user)
+ end
+ end
+end
diff --git a/app/controllers/concerns/search_rate_limitable.rb b/app/controllers/concerns/search_rate_limitable.rb
new file mode 100644
index 00000000000..a77ebd276b6
--- /dev/null
+++ b/app/controllers/concerns/search_rate_limitable.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+module SearchRateLimitable
+ extend ActiveSupport::Concern
+
+ private
+
+ def check_search_rate_limit!
+ if current_user
+ check_rate_limit!(:search_rate_limit, scope: [current_user])
+ else
+ check_rate_limit!(:search_rate_limit_unauthenticated, scope: [request.ip])
+ end
+ end
+end
diff --git a/app/controllers/concerns/sessionless_authentication.rb b/app/controllers/concerns/sessionless_authentication.rb
index 1f17f9f4e1b..48daacc09c2 100644
--- a/app/controllers/concerns/sessionless_authentication.rb
+++ b/app/controllers/concerns/sessionless_authentication.rb
@@ -26,6 +26,9 @@ module SessionlessAuthentication
# for every request. If you want the token to work as a
# sign in token, you can simply remove store: false.
sign_in(user, store: false, message: :sessionless_sign_in)
+ elsif request_authenticator.can_sign_in_bot?(user)
+ # we suppress callbacks to avoid redirecting the bot
+ sign_in(user, store: false, message: :sessionless_sign_in, run_callbacks: false)
end
end
diff --git a/app/controllers/concerns/spammable_actions/akismet_mark_as_spam_action.rb b/app/controllers/concerns/spammable_actions/akismet_mark_as_spam_action.rb
index 234c591ffb7..044519004b2 100644
--- a/app/controllers/concerns/spammable_actions/akismet_mark_as_spam_action.rb
+++ b/app/controllers/concerns/spammable_actions/akismet_mark_as_spam_action.rb
@@ -2,7 +2,6 @@
module SpammableActions::AkismetMarkAsSpamAction
extend ActiveSupport::Concern
- include SpammableActions::Attributes
included do
before_action :authorize_submit_spammable!, only: :mark_as_spam
@@ -22,7 +21,15 @@ module SpammableActions::AkismetMarkAsSpamAction
access_denied! unless current_user.can_admin_all_resources?
end
+ def spammable
+ # The class extending this module should define the #spammable method to return
+ # the Spammable model instance via: `alias_method :spammable , <:model_name>`
+ raise NotImplementedError, "#{self.class} should implement #{__method__}"
+ end
+
def spammable_path
- raise NotImplementedError, "#{self.class} does not implement #{__method__}"
+ # The class extending this module should define the #spammable_path method to return
+ # the route helper pointing to the action to show the Spammable instance
+ raise NotImplementedError, "#{self.class} should implement #{__method__}"
end
end
diff --git a/app/controllers/concerns/spammable_actions/attributes.rb b/app/controllers/concerns/spammable_actions/attributes.rb
deleted file mode 100644
index d7060e47c07..00000000000
--- a/app/controllers/concerns/spammable_actions/attributes.rb
+++ /dev/null
@@ -1,13 +0,0 @@
-# frozen_string_literal: true
-
-module SpammableActions
- module Attributes
- extend ActiveSupport::Concern
-
- private
-
- def spammable
- raise NotImplementedError, "#{self.class} does not implement #{__method__}"
- end
- end
-end
diff --git a/app/controllers/concerns/spammable_actions/captcha_check/common.rb b/app/controllers/concerns/spammable_actions/captcha_check/common.rb
index 7c047e02a1d..aaeb6b3ba83 100644
--- a/app/controllers/concerns/spammable_actions/captcha_check/common.rb
+++ b/app/controllers/concerns/spammable_actions/captcha_check/common.rb
@@ -1,23 +1,25 @@
# frozen_string_literal: true
-module SpammableActions::CaptchaCheck
- module Common
- extend ActiveSupport::Concern
+module SpammableActions
+ module CaptchaCheck
+ module Common
+ extend ActiveSupport::Concern
- private
+ private
- def with_captcha_check_common(captcha_render_lambda:, &block)
- # If the Spammable indicates that CAPTCHA is not necessary (either due to it not being flagged
- # as spam, or if spam/captcha is disabled for some reason), then we will go ahead and
- # yield to the block containing the action's original behavior, then return.
- return yield unless spammable.render_recaptcha?
+ def with_captcha_check_common(spammable:, captcha_render_lambda:, &block)
+ # If the Spammable indicates that CAPTCHA is not necessary (either due to it not being flagged
+ # as spam, or if spam/captcha is disabled for some reason), then we will go ahead and
+ # yield to the block containing the action's original behavior, then return.
+ return yield unless spammable.render_recaptcha?
- # If we got here, we need to render the CAPTCHA instead of yielding to action's original
- # behavior. We will present a CAPTCHA to be solved by executing the lambda which was passed
- # as the `captcha_render_lambda:` argument. This lambda contains either the HTML-specific or
- # JSON-specific behavior to cause the CAPTCHA modal to be rendered.
- Gitlab::Recaptcha.load_configurations!
- captcha_render_lambda.call
+ # If we got here, we need to render the CAPTCHA instead of yielding to action's original
+ # behavior. We will present a CAPTCHA to be solved by executing the lambda which was passed
+ # as the `captcha_render_lambda:` argument. This lambda contains either the HTML-specific or
+ # JSON-specific behavior to cause the CAPTCHA modal to be rendered.
+ Gitlab::Recaptcha.load_configurations!
+ captcha_render_lambda.call
+ end
end
end
end
diff --git a/app/controllers/concerns/spammable_actions/captcha_check/html_format_actions_support.rb b/app/controllers/concerns/spammable_actions/captcha_check/html_format_actions_support.rb
index f687c0fcf2d..b254916cdd6 100644
--- a/app/controllers/concerns/spammable_actions/captcha_check/html_format_actions_support.rb
+++ b/app/controllers/concerns/spammable_actions/captcha_check/html_format_actions_support.rb
@@ -8,7 +8,6 @@
# which supports JSON format should be used instead.
module SpammableActions::CaptchaCheck::HtmlFormatActionsSupport
extend ActiveSupport::Concern
- include SpammableActions::Attributes
include SpammableActions::CaptchaCheck::Common
included do
@@ -17,9 +16,9 @@ module SpammableActions::CaptchaCheck::HtmlFormatActionsSupport
private
- def with_captcha_check_html_format(&block)
+ def with_captcha_check_html_format(spammable:, &block)
captcha_render_lambda = -> { render :captcha_check }
- with_captcha_check_common(captcha_render_lambda: captcha_render_lambda, &block)
+ with_captcha_check_common(spammable: spammable, captcha_render_lambda: captcha_render_lambda, &block)
end
# Convert spam/CAPTCHA values from form field params to headers, because all spam-related services
diff --git a/app/controllers/concerns/spammable_actions/captcha_check/json_format_actions_support.rb b/app/controllers/concerns/spammable_actions/captcha_check/json_format_actions_support.rb
index 0bfea05abc7..4a278a7b233 100644
--- a/app/controllers/concerns/spammable_actions/captcha_check/json_format_actions_support.rb
+++ b/app/controllers/concerns/spammable_actions/captcha_check/json_format_actions_support.rb
@@ -4,22 +4,27 @@
# In other words, forms handled by actions which use a `respond_to` of `format.js` or `format.json`.
#
# For example, for all Javascript based form submissions and Vue components which use Apollo and Axios
+# which are directly handled by a controller other than `GraphqlController`. For example, issue
+# update currently uses this module.
+#
+# However, requests which directly hit `GraphqlController` will not use this module - the
+# `Mutations::SpamProtection` module handles those requests (for example, snippet create/update
+# requests)
#
# If the request is handled by actions via `format.html`, then the corresponding module which
# supports HTML format should be used instead.
module SpammableActions::CaptchaCheck::JsonFormatActionsSupport
extend ActiveSupport::Concern
- include SpammableActions::Attributes
include SpammableActions::CaptchaCheck::Common
include Spam::Concerns::HasSpamActionResponseFields
private
- def with_captcha_check_json_format(&block)
+ def with_captcha_check_json_format(spammable:, &block)
# NOTE: "409 - Conflict" seems to be the most appropriate HTTP status code for a response
# which requires a CAPTCHA to be solved in order for the request to be resubmitted.
# https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.10
captcha_render_lambda = -> { render json: spam_action_response_fields(spammable), status: :conflict }
- with_captcha_check_common(captcha_render_lambda: captcha_render_lambda, &block)
+ with_captcha_check_common(spammable: spammable, captcha_render_lambda: captcha_render_lambda, &block)
end
end
diff --git a/app/controllers/concerns/spammable_actions/captcha_check/rest_api_actions_support.rb b/app/controllers/concerns/spammable_actions/captcha_check/rest_api_actions_support.rb
new file mode 100644
index 00000000000..2ebfa90e6da
--- /dev/null
+++ b/app/controllers/concerns/spammable_actions/captcha_check/rest_api_actions_support.rb
@@ -0,0 +1,39 @@
+# frozen_string_literal: true
+
+# This module should be included to support CAPTCHA check for REST API actions via Grape.
+#
+# If the request is directly handled by a controller action, then the corresponding module which
+# supports HTML or JSON formats should be used instead.
+module SpammableActions::CaptchaCheck::RestApiActionsSupport
+ extend ActiveSupport::Concern
+ include SpammableActions::CaptchaCheck::Common
+ include Spam::Concerns::HasSpamActionResponseFields
+
+ private
+
+ def with_captcha_check_rest_api(spammable:, &block)
+ # In the case of the REST API, the request is handled by Grape, so if there is a spam-related
+ # error, we don't render directly, instead we will pass the error message and other necessary
+ # fields to the Grape api error helper for it to handle.
+ captcha_render_lambda = -> do
+ fields = spam_action_response_fields(spammable)
+
+ fields.delete :spam
+ # NOTE: "409 - Conflict" seems to be the most appropriate HTTP status code for a response
+ # which requires a CAPTCHA to be solved in order for the request to be resubmitted.
+ # https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.10
+ status = 409
+
+ # NOTE: This nested 'error' key may not be consistent with all other API error responses,
+ # because they are not currently consistent across different API endpoints
+ # and models. Some (snippets) will nest errors in an errors key like this,
+ # while others (issues) will return the model's errors hash without an errors key,
+ # while still others just return a plain string error.
+ # See https://gitlab.com/groups/gitlab-org/-/epics/5527#revisit-inconsistent-shape-of-error-responses-in-rest-api
+ fields[:message] = { error: spammable.errors.full_messages.to_sentence }
+ render_structured_api_error!(fields, status)
+ end
+
+ with_captcha_check_common(spammable: spammable, captcha_render_lambda: captcha_render_lambda, &block)
+ end
+end
diff --git a/app/controllers/concerns/uploads_actions.rb b/app/controllers/concerns/uploads_actions.rb
index e1bfe92f61b..c9b6e8923fe 100644
--- a/app/controllers/concerns/uploads_actions.rb
+++ b/app/controllers/concerns/uploads_actions.rb
@@ -143,7 +143,7 @@ module UploadsActions
end
def bypass_auth_checks_on_uploads?
- if ::Feature.enabled?(:enforce_auth_checks_on_uploads, default_enabled: :yaml)
+ if ::Feature.enabled?(:enforce_auth_checks_on_uploads, project, default_enabled: :yaml)
false
else
action_name == 'show' && embeddable?
diff --git a/app/controllers/dashboard/projects_controller.rb b/app/controllers/dashboard/projects_controller.rb
index 0074bcac360..4d6c7a63516 100644
--- a/app/controllers/dashboard/projects_controller.rb
+++ b/app/controllers/dashboard/projects_controller.rb
@@ -23,7 +23,7 @@ class Dashboard::ProjectsController < Dashboard::ApplicationController
end
format.atom do
load_events
- render layout: 'xml.atom'
+ render layout: 'xml'
end
format.json do
render json: {
diff --git a/app/controllers/dashboard_controller.rb b/app/controllers/dashboard_controller.rb
index f94da77609f..f25cc1bbc32 100644
--- a/app/controllers/dashboard_controller.rb
+++ b/app/controllers/dashboard_controller.rb
@@ -20,10 +20,6 @@ class DashboardController < Dashboard::ApplicationController
urgency :low, [:merge_requests]
- before_action only: [:merge_requests] do
- push_frontend_feature_flag(:mr_attention_requests, default_enabled: :yaml)
- end
-
def activity
respond_to do |format|
format.html
@@ -71,10 +67,15 @@ class DashboardController < Dashboard::ApplicationController
end
def check_filters_presence!
- no_scalar_filters_set = finder_type.scalar_params.none? { |k| params.key?(k) }
- no_array_filters_set = finder_type.array_params.none? { |k, _| params.key?(k) }
+ no_scalar_filters_set = finder_type.scalar_params.none? { |k| params[k].present? }
+ no_array_filters_set = finder_type.array_params.none? { |k, _| params[k].present? }
+
+ # The `in` param is a modifier of `search`. If it's present while the `search`
+ # param isn't, the finder won't use the `in` param. We consider this as a no
+ # filter scenario.
+ no_search_filter_set = params[:in].present? && params[:search].blank?
- @no_filters_set = no_scalar_filters_set && no_array_filters_set
+ @no_filters_set = (no_scalar_filters_set && no_array_filters_set) || no_search_filter_set
return unless @no_filters_set
diff --git a/app/controllers/groups/application_controller.rb b/app/controllers/groups/application_controller.rb
index f9c875b80b2..bf72ade32d0 100644
--- a/app/controllers/groups/application_controller.rb
+++ b/app/controllers/groups/application_controller.rb
@@ -82,6 +82,10 @@ class Groups::ApplicationController < ApplicationController
def has_project_list?
false
end
+
+ def validate_root_group!
+ render_404 unless group.root?
+ end
end
Groups::ApplicationController.prepend_mod_with('Groups::ApplicationController')
diff --git a/app/controllers/groups/boards_controller.rb b/app/controllers/groups/boards_controller.rb
index 6fac6fcf426..641b3adb12b 100644
--- a/app/controllers/groups/boards_controller.rb
+++ b/app/controllers/groups/boards_controller.rb
@@ -7,7 +7,6 @@ class Groups::BoardsController < Groups::ApplicationController
before_action :assign_endpoint_vars
before_action do
- push_frontend_feature_flag(:issue_boards_filtered_search, group, default_enabled: :yaml)
push_frontend_feature_flag(:board_multi_select, group, default_enabled: :yaml)
push_frontend_feature_flag(:iteration_cadences, group, default_enabled: :yaml)
experiment(:prominent_create_board_btn, subject: current_user) do |e|
diff --git a/app/controllers/groups/clusters_controller.rb b/app/controllers/groups/clusters_controller.rb
index 666a96d6fc0..2fe9faa252f 100644
--- a/app/controllers/groups/clusters_controller.rb
+++ b/app/controllers/groups/clusters_controller.rb
@@ -3,6 +3,7 @@
class Groups::ClustersController < Clusters::ClustersController
include ControllerWithCrossProjectAccessCheck
+ before_action :ensure_feature_enabled!
prepend_before_action :group
requires_cross_project_access
diff --git a/app/controllers/groups/crm/contacts_controller.rb b/app/controllers/groups/crm/contacts_controller.rb
index f00f4d1df25..b59e20d9cea 100644
--- a/app/controllers/groups/crm/contacts_controller.rb
+++ b/app/controllers/groups/crm/contacts_controller.rb
@@ -3,6 +3,7 @@
class Groups::Crm::ContactsController < Groups::ApplicationController
feature_category :team_planning
+ before_action :validate_root_group!
before_action :authorize_read_crm_contact!
def new
diff --git a/app/controllers/groups/crm/organizations_controller.rb b/app/controllers/groups/crm/organizations_controller.rb
index ab720f490be..f8536b4f538 100644
--- a/app/controllers/groups/crm/organizations_controller.rb
+++ b/app/controllers/groups/crm/organizations_controller.rb
@@ -3,6 +3,7 @@
class Groups::Crm::OrganizationsController < Groups::ApplicationController
feature_category :team_planning
+ before_action :validate_root_group!
before_action :authorize_read_crm_organization!
def new
diff --git a/app/controllers/groups/deploy_tokens_controller.rb b/app/controllers/groups/deploy_tokens_controller.rb
index 79152bf2695..9ef22aa33dc 100644
--- a/app/controllers/groups/deploy_tokens_controller.rb
+++ b/app/controllers/groups/deploy_tokens_controller.rb
@@ -6,8 +6,7 @@ class Groups::DeployTokensController < Groups::ApplicationController
feature_category :continuous_delivery
def revoke
- @token = @group.deploy_tokens.find(params[:id])
- @token.revoke!
+ Groups::DeployTokens::RevokeService.new(@group, current_user, params).execute
redirect_to group_settings_repository_path(@group, anchor: 'js-deploy-tokens')
end
diff --git a/app/controllers/groups/group_members_controller.rb b/app/controllers/groups/group_members_controller.rb
index 6e59f159636..ece1083d4d1 100644
--- a/app/controllers/groups/group_members_controller.rb
+++ b/app/controllers/groups/group_members_controller.rb
@@ -16,7 +16,7 @@ class Groups::GroupMembersController < Groups::ApplicationController
before_action :authorize_admin_group_member!, except: admin_not_required_endpoints
skip_before_action :check_two_factor_requirement, only: :leave
- skip_cross_project_access_check :index, :create, :update, :destroy, :request_access,
+ skip_cross_project_access_check :index, :update, :destroy, :request_access,
:approve_access_request, :leave, :resend_invite,
:override
@@ -26,8 +26,6 @@ class Groups::GroupMembersController < Groups::ApplicationController
@sort = params[:sort].presence || sort_value_name
if can?(current_user, :admin_group_member, @group)
- @skip_groups = @group.related_group_ids
-
@invited_members = invited_members
@invited_members = @invited_members.search_invite_email(params[:search_invited]) if params[:search_invited].present?
@invited_members = present_invited_members(@invited_members)
@@ -38,8 +36,6 @@ class Groups::GroupMembersController < Groups::ApplicationController
@requesters = present_members(
AccessRequestsFinder.new(@group).execute(current_user)
)
-
- @group_member = @group.group_members.new
end
# MembershipActions concern
diff --git a/app/controllers/groups/harbor/repositories_controller.rb b/app/controllers/groups/harbor/repositories_controller.rb
new file mode 100644
index 00000000000..364607f9b20
--- /dev/null
+++ b/app/controllers/groups/harbor/repositories_controller.rb
@@ -0,0 +1,24 @@
+# frozen_string_literal: true
+
+module Groups
+ module Harbor
+ class RepositoriesController < Groups::ApplicationController
+ feature_category :integrations
+
+ before_action :harbor_registry_enabled!
+ before_action do
+ push_frontend_feature_flag(:harbor_registry_integration)
+ end
+
+ def show
+ render :index
+ end
+
+ private
+
+ def harbor_registry_enabled!
+ render_404 unless Feature.enabled?(:harbor_registry_integration)
+ end
+ end
+ end
+end
diff --git a/app/controllers/groups/releases_controller.rb b/app/controllers/groups/releases_controller.rb
index 6a42f30b847..db5385ecc71 100644
--- a/app/controllers/groups/releases_controller.rb
+++ b/app/controllers/groups/releases_controller.rb
@@ -15,11 +15,17 @@ module Groups
private
def releases
- ReleasesFinder
- .new(@group, current_user, { include_subgroups: true })
- .execute(preload: false)
- .page(params[:page])
- .per(30)
+ if Feature.enabled?(:group_releases_finder_inoperator)
+ Releases::GroupReleasesFinder
+ .new(@group, current_user, { include_subgroups: true, page: params[:page], per: 30 })
+ .execute(preload: false)
+ else
+ ReleasesFinder
+ .new(@group, current_user, { include_subgroups: true })
+ .execute(preload: false)
+ .page(params[:page])
+ .per(30)
+ end
end
end
end
diff --git a/app/controllers/groups/runners_controller.rb b/app/controllers/groups/runners_controller.rb
index b194aeff80d..dabef978ee1 100644
--- a/app/controllers/groups/runners_controller.rb
+++ b/app/controllers/groups/runners_controller.rb
@@ -24,7 +24,7 @@ class Groups::RunnersController < Groups::ApplicationController
end
def update
- if Ci::UpdateRunnerService.new(@runner).update(runner_params)
+ if Ci::Runners::UpdateRunnerService.new(@runner).update(runner_params)
redirect_to group_runner_path(@group, @runner), notice: _('Runner was successfully updated.')
else
render 'edit'
@@ -32,17 +32,17 @@ class Groups::RunnersController < Groups::ApplicationController
end
def destroy
- if @runner.belongs_to_more_than_one_project?
- redirect_to group_settings_ci_cd_path(@group, anchor: 'runners-settings'), status: :found, alert: _('Runner was not deleted because it is assigned to multiple projects.')
- else
- Ci::UnregisterRunnerService.new(@runner).execute
+ if can?(current_user, :delete_runner, @runner)
+ Ci::Runners::UnregisterRunnerService.new(@runner, current_user).execute
redirect_to group_settings_ci_cd_path(@group, anchor: 'runners-settings'), status: :found
+ else
+ redirect_to group_settings_ci_cd_path(@group, anchor: 'runners-settings'), status: :found, alert: _('Runner cannot be deleted, please contact your administrator.')
end
end
def resume
- if Ci::UpdateRunnerService.new(@runner).update(active: true)
+ if Ci::Runners::UpdateRunnerService.new(@runner).update(active: true)
redirect_to group_settings_ci_cd_path(@group, anchor: 'runners-settings'), notice: _('Runner was successfully updated.')
else
redirect_to group_settings_ci_cd_path(@group, anchor: 'runners-settings'), alert: _('Runner was not updated.')
@@ -50,7 +50,7 @@ class Groups::RunnersController < Groups::ApplicationController
end
def pause
- if Ci::UpdateRunnerService.new(@runner).update(active: false)
+ if Ci::Runners::UpdateRunnerService.new(@runner).update(active: false)
redirect_to group_settings_ci_cd_path(@group, anchor: 'runners-settings'), notice: _('Runner was successfully updated.')
else
redirect_to group_settings_ci_cd_path(@group, anchor: 'runners-settings'), alert: _('Runner was not updated.')
diff --git a/app/controllers/groups/settings/ci_cd_controller.rb b/app/controllers/groups/settings/ci_cd_controller.rb
index a290ef9b5e7..9b9e3f7b0bc 100644
--- a/app/controllers/groups/settings/ci_cd_controller.rb
+++ b/app/controllers/groups/settings/ci_cd_controller.rb
@@ -36,7 +36,7 @@ module Groups
end
def reset_registration_token
- @group.reset_runners_token!
+ ::Ci::Runners::ResetRegistrationTokenService.new(@group, current_user).execute
flash[:notice] = _('GroupSettings|New runners registration token has been generated!')
redirect_to group_settings_ci_cd_path
diff --git a/app/controllers/groups/settings/integrations_controller.rb b/app/controllers/groups/settings/integrations_controller.rb
index 0a63c3d304b..ec64e75a68e 100644
--- a/app/controllers/groups/settings/integrations_controller.rb
+++ b/app/controllers/groups/settings/integrations_controller.rb
@@ -7,6 +7,10 @@ module Groups
before_action :authorize_admin_group!
+ before_action do
+ push_frontend_feature_flag(:integration_form_sections, group, default_enabled: :yaml)
+ end
+
feature_category :integrations
layout 'group_settings'
diff --git a/app/controllers/groups/uploads_controller.rb b/app/controllers/groups/uploads_controller.rb
index 387f7be56cd..49249f87d31 100644
--- a/app/controllers/groups/uploads_controller.rb
+++ b/app/controllers/groups/uploads_controller.rb
@@ -4,7 +4,7 @@ class Groups::UploadsController < Groups::ApplicationController
include UploadsActions
include WorkhorseRequest
- skip_before_action :group, if: -> { bypass_auth_checks_on_uploads? }
+ skip_before_action :group, if: -> { action_name == 'show' && embeddable? }
before_action :authorize_upload_file!, only: [:create, :authorize]
before_action :verify_workhorse_api!, only: [:authorize]
diff --git a/app/controllers/groups_controller.rb b/app/controllers/groups_controller.rb
index 12af76efe0d..b53d9b1be04 100644
--- a/app/controllers/groups_controller.rb
+++ b/app/controllers/groups_controller.rb
@@ -212,7 +212,7 @@ class GroupsController < Groups::ApplicationController
def issues
return super if !html_request? || Feature.disabled?(:vue_issues_list, group, default_enabled: :yaml)
- @has_issues = IssuesFinder.new(current_user, group_id: group.id).execute
+ @has_issues = IssuesFinder.new(current_user, group_id: group.id, include_subgroups: true).execute
.non_archived
.exists?
@@ -235,7 +235,7 @@ class GroupsController < Groups::ApplicationController
def render_details_view_atom
load_events
- render layout: 'xml.atom', template: 'groups/show'
+ render layout: 'xml', template: 'groups/show'
end
# rubocop: disable CodeReuse/ActiveRecord
diff --git a/app/controllers/jira_connect/events_controller.rb b/app/controllers/jira_connect/events_controller.rb
index 1ea0a92662b..327192857f6 100644
--- a/app/controllers/jira_connect/events_controller.rb
+++ b/app/controllers/jira_connect/events_controller.rb
@@ -7,11 +7,13 @@ class JiraConnect::EventsController < JiraConnect::ApplicationController
before_action :verify_asymmetric_atlassian_jwt!
def installed
- return head :ok if current_jira_installation
+ unless Feature.enabled?(:jira_connect_installation_update, default_enabled: :yaml)
+ return head :ok if current_jira_installation
+ end
- installation = JiraConnectInstallation.new(event_params)
+ success = current_jira_installation ? update_installation : create_installation
- if installation.save
+ if success
head :ok
else
head :unprocessable_entity
@@ -28,8 +30,24 @@ class JiraConnect::EventsController < JiraConnect::ApplicationController
private
- def event_params
- params.permit(:clientKey, :sharedSecret, :baseUrl).transform_keys(&:underscore)
+ def create_installation
+ JiraConnectInstallation.new(create_params).save
+ end
+
+ def update_installation
+ current_jira_installation.update(update_params)
+ end
+
+ def create_params
+ transformed_params.permit(:client_key, :shared_secret, :base_url)
+ end
+
+ def update_params
+ transformed_params.permit(:shared_secret, :base_url)
+ end
+
+ def transformed_params
+ @transformed_params ||= params.transform_keys(&:underscore)
end
def verify_asymmetric_atlassian_jwt!
@@ -43,7 +61,7 @@ class JiraConnect::EventsController < JiraConnect::ApplicationController
def jwt_verification_claims
{
aud: jira_connect_base_url(protocol: 'https'),
- iss: event_params[:client_key],
+ iss: transformed_params[:client_key],
qsh: Atlassian::Jwt.create_query_string_hash(request.url, request.method, jira_connect_base_url)
}
end
diff --git a/app/controllers/jira_connect/oauth_callbacks_controller.rb b/app/controllers/jira_connect/oauth_callbacks_controller.rb
new file mode 100644
index 00000000000..f603a563402
--- /dev/null
+++ b/app/controllers/jira_connect/oauth_callbacks_controller.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+# This controller's role is to serve as a landing page
+# that users get redirected to after installing and authenticating
+# The GitLab.com for Jira App (https://marketplace.atlassian.com/apps/1221011/gitlab-com-for-jira-cloud)
+#
+class JiraConnect::OauthCallbacksController < ApplicationController
+ feature_category :integrations
+
+ def index; end
+end
diff --git a/app/controllers/jira_connect/subscriptions_controller.rb b/app/controllers/jira_connect/subscriptions_controller.rb
index fcd95c7942c..ec6ba07a125 100644
--- a/app/controllers/jira_connect/subscriptions_controller.rb
+++ b/app/controllers/jira_connect/subscriptions_controller.rb
@@ -16,6 +16,10 @@ class JiraConnect::SubscriptionsController < JiraConnect::ApplicationController
p.style_src(*style_src_values)
end
+ before_action do
+ push_frontend_feature_flag(:jira_connect_oauth, @user, default_enabled: :yaml)
+ end
+
before_action :allow_rendering_in_iframe, only: :index
before_action :verify_qsh_claim!, only: :index
before_action :authenticate_user!, only: :create
diff --git a/app/controllers/profiles_controller.rb b/app/controllers/profiles_controller.rb
index 46738651960..d57a293ab4d 100644
--- a/app/controllers/profiles_controller.rb
+++ b/app/controllers/profiles_controller.rb
@@ -7,7 +7,7 @@ class ProfilesController < Profiles::ApplicationController
before_action :user
before_action :authorize_change_username!, only: :update_username
before_action only: :update_username do
- check_rate_limit!(:profile_update_username, scope: current_user) if Feature.enabled?(:rate_limit_profile_update_username, default_enabled: :yaml)
+ check_rate_limit!(:profile_update_username, scope: current_user)
end
skip_before_action :require_email, only: [:show, :update]
before_action do
diff --git a/app/controllers/projects/application_controller.rb b/app/controllers/projects/application_controller.rb
index 7a03e7b84b7..62233c8c3c9 100644
--- a/app/controllers/projects/application_controller.rb
+++ b/app/controllers/projects/application_controller.rb
@@ -24,11 +24,14 @@ class Projects::ApplicationController < ApplicationController
return unless params[:project_id] || params[:id]
path = File.join(params[:namespace_id], params[:project_id] || params[:id])
- auth_proc = ->(project) { !project.pending_delete? }
@project = find_routable!(Project, path, request.fullpath, extra_authorization_proc: auth_proc)
end
+ def auth_proc
+ ->(project) { !project.pending_delete? }
+ end
+
def build_canonical_path(project)
params[:namespace_id] = project.namespace.to_param
params[:project_id] = project.to_param
@@ -89,3 +92,5 @@ class Projects::ApplicationController < ApplicationController
return render_404 unless @project.feature_available?(:issues, current_user)
end
end
+
+Projects::ApplicationController.prepend_mod_with('Projects::ApplicationController')
diff --git a/app/controllers/projects/blob_controller.rb b/app/controllers/projects/blob_controller.rb
index b30ef7506aa..26a7b5662be 100644
--- a/app/controllers/projects/blob_controller.rb
+++ b/app/controllers/projects/blob_controller.rb
@@ -35,7 +35,6 @@ class Projects::BlobController < Projects::ApplicationController
before_action :editor_variables, except: [:show, :preview, :diff]
before_action :validate_diff_params, only: :diff
before_action :set_last_commit_sha, only: [:edit, :update]
- before_action :track_experiment, only: :create
track_redis_hll_event :create, :update, name: 'g_edit_by_sfe'
@@ -45,7 +44,6 @@ class Projects::BlobController < Projects::ApplicationController
before_action do
push_frontend_feature_flag(:refactor_blob_viewer, @project, default_enabled: :yaml)
push_frontend_feature_flag(:highlight_js, @project, default_enabled: :yaml)
- push_frontend_feature_flag(:consolidated_edit_button, @project, default_enabled: :yaml)
push_licensed_feature(:file_locks) if @project.licensed_feature_available?(:file_locks)
end
@@ -55,7 +53,7 @@ class Projects::BlobController < Projects::ApplicationController
def create
create_commit(Files::CreateService, success_notice: _("The file has been successfully created."),
- success_path: -> { create_success_path },
+ success_path: -> { project_blob_path(@project, File.join(@branch_name, @file_path)) },
failure_view: :new,
failure_path: project_new_blob_path(@project, @ref))
end
@@ -283,20 +281,6 @@ class Projects::BlobController < Projects::ApplicationController
def visitor_id
current_user&.id
end
-
- def create_success_path
- if params[:code_quality_walkthrough]
- project_pipelines_path(@project, code_quality_walkthrough: true)
- else
- project_blob_path(@project, File.join(@branch_name, @file_path))
- end
- end
-
- def track_experiment
- return unless params[:code_quality_walkthrough]
-
- experiment(:code_quality_walkthrough, namespace: @project.root_ancestor).track(:commit_created)
- end
end
Projects::BlobController.prepend_mod
diff --git a/app/controllers/projects/boards_controller.rb b/app/controllers/projects/boards_controller.rb
index 0170cff6160..c44a0830e2e 100644
--- a/app/controllers/projects/boards_controller.rb
+++ b/app/controllers/projects/boards_controller.rb
@@ -7,7 +7,6 @@ class Projects::BoardsController < Projects::ApplicationController
before_action :check_issues_available!
before_action :assign_endpoint_vars
before_action do
- push_frontend_feature_flag(:issue_boards_filtered_search, project&.group, default_enabled: :yaml)
push_frontend_feature_flag(:board_multi_select, project, default_enabled: :yaml)
push_frontend_feature_flag(:iteration_cadences, project&.group, default_enabled: :yaml)
experiment(:prominent_create_board_btn, subject: current_user) do |e|
diff --git a/app/controllers/projects/builds_controller.rb b/app/controllers/projects/builds_controller.rb
index c5f6ed1c105..61e8e5b015a 100644
--- a/app/controllers/projects/builds_controller.rb
+++ b/app/controllers/projects/builds_controller.rb
@@ -5,6 +5,9 @@ class Projects::BuildsController < Projects::ApplicationController
feature_category :continuous_integration
+ urgency :high, [:index, :show]
+ urgency :low, [:raw]
+
def index
redirect_to project_jobs_path(project)
end
diff --git a/app/controllers/projects/ci/pipeline_editor_controller.rb b/app/controllers/projects/ci/pipeline_editor_controller.rb
index 6f12e3940dd..8c6e8f0e126 100644
--- a/app/controllers/projects/ci/pipeline_editor_controller.rb
+++ b/app/controllers/projects/ci/pipeline_editor_controller.rb
@@ -2,7 +2,6 @@
class Projects::Ci::PipelineEditorController < Projects::ApplicationController
before_action :check_can_collaborate!
- before_action :setup_walkthrough_experiment, only: :show
before_action do
push_frontend_feature_flag(:schema_linting, @project, default_enabled: :yaml)
end
@@ -19,11 +18,4 @@ class Projects::Ci::PipelineEditorController < Projects::ApplicationController
def check_can_collaborate!
render_404 unless can_collaborate_with_project?(@project)
end
-
- def setup_walkthrough_experiment
- experiment(:pipeline_editor_walkthrough, namespace: @project.namespace, sticky_to: current_user) do |e|
- e.candidate {}
- e.publish_to_database
- end
- end
end
diff --git a/app/controllers/projects/ci/secure_files_controller.rb b/app/controllers/projects/ci/secure_files_controller.rb
new file mode 100644
index 00000000000..5141d0188b0
--- /dev/null
+++ b/app/controllers/projects/ci/secure_files_controller.rb
@@ -0,0 +1,10 @@
+# frozen_string_literal: true
+
+class Projects::Ci::SecureFilesController < Projects::ApplicationController
+ before_action :authorize_read_secure_files!
+
+ feature_category :pipeline_authoring
+
+ def show
+ end
+end
diff --git a/app/controllers/projects/cluster_agents_controller.rb b/app/controllers/projects/cluster_agents_controller.rb
index 84bb01ee266..282b9ef1fb7 100644
--- a/app/controllers/projects/cluster_agents_controller.rb
+++ b/app/controllers/projects/cluster_agents_controller.rb
@@ -3,10 +3,6 @@
class Projects::ClusterAgentsController < Projects::ApplicationController
before_action :authorize_can_read_cluster_agent!
- before_action do
- push_frontend_feature_flag(:cluster_vulnerabilities, project, default_enabled: :yaml)
- end
-
feature_category :kubernetes_management
def show
diff --git a/app/controllers/projects/commit_controller.rb b/app/controllers/projects/commit_controller.rb
index 0ce0b8b8895..0c26b402876 100644
--- a/app/controllers/projects/commit_controller.rb
+++ b/app/controllers/projects/commit_controller.rb
@@ -164,6 +164,7 @@ class Projects::CommitController < Projects::ApplicationController
opts = diff_options
opts[:ignore_whitespace_change] = true if params[:format] == 'diff'
+ opts[:use_extra_viewer_as_main] = false
@diffs = commit.diffs(opts)
@notes_count = commit.notes.count
diff --git a/app/controllers/projects/commits_controller.rb b/app/controllers/projects/commits_controller.rb
index 82a13b60b13..60b8e45f5be 100644
--- a/app/controllers/projects/commits_controller.rb
+++ b/app/controllers/projects/commits_controller.rb
@@ -30,7 +30,7 @@ class Projects::CommitsController < Projects::ApplicationController
respond_to do |format|
format.html
- format.atom { render layout: 'xml.atom' }
+ format.atom { render layout: 'xml' }
format.json do
pager_json(
diff --git a/app/controllers/projects/deploy_tokens_controller.rb b/app/controllers/projects/deploy_tokens_controller.rb
index 3c890bbafdf..42c2d8b17f1 100644
--- a/app/controllers/projects/deploy_tokens_controller.rb
+++ b/app/controllers/projects/deploy_tokens_controller.rb
@@ -12,3 +12,5 @@ class Projects::DeployTokensController < Projects::ApplicationController
redirect_to project_settings_repository_path(project, anchor: 'js-deploy-tokens')
end
end
+
+Projects::DeployTokensController.prepend_mod
diff --git a/app/controllers/projects/environments_controller.rb b/app/controllers/projects/environments_controller.rb
index 84ebdcd9364..eabc048e341 100644
--- a/app/controllers/projects/environments_controller.rb
+++ b/app/controllers/projects/environments_controller.rb
@@ -29,13 +29,14 @@ class Projects::EnvironmentsController < Projects::ApplicationController
feature_category :continuous_delivery
def index
- @environments = project.environments
- .with_state(params[:scope] || :available)
@project = ProjectPresenter.new(project, current_user: current_user)
respond_to do |format|
format.html
format.json do
+ @environments = project.environments
+ .with_state(params[:scope] || :available)
+
Gitlab::PollingInterval.set_header(response, interval: 3_000)
environments_count_by_state = project.environments.count_by_state
@@ -52,14 +53,15 @@ class Projects::EnvironmentsController < Projects::ApplicationController
# Returns all environments for a given folder
# rubocop: disable CodeReuse/ActiveRecord
def folder
- folder_environments = project.environments.where(environment_type: params[:id])
- @environments = folder_environments.with_state(params[:scope] || :available)
- .order(:name)
@folder = params[:id]
respond_to do |format|
format.html
format.json do
+ folder_environments = project.environments.where(environment_type: params[:id])
+ @environments = folder_environments.with_state(params[:scope] || :available)
+ .order(:name)
+
render json: {
environments: serialize_environments(request, response),
available_count: folder_environments.available.count,
diff --git a/app/controllers/projects/error_tracking_controller.rb b/app/controllers/projects/error_tracking_controller.rb
index 8700d3c2198..06383d26133 100644
--- a/app/controllers/projects/error_tracking_controller.rb
+++ b/app/controllers/projects/error_tracking_controller.rb
@@ -6,6 +6,10 @@ class Projects::ErrorTrackingController < Projects::ErrorTracking::BaseControlle
before_action :authorize_read_sentry_issue!
before_action :set_issue_id, only: :details
+ before_action only: [:index] do
+ push_frontend_feature_flag(:integrated_error_tracking, project)
+ end
+
def index
respond_to do |format|
format.html
@@ -75,7 +79,7 @@ class Projects::ErrorTrackingController < Projects::ErrorTracking::BaseControlle
end
def list_issues_params
- params.permit(:search_term, :sort, :cursor, :issue_status)
+ params.permit(:search_term, :sort, :cursor, :issue_status).merge(tracking_event: :error_tracking_view_list)
end
def issue_update_params
@@ -83,7 +87,7 @@ class Projects::ErrorTrackingController < Projects::ErrorTracking::BaseControlle
end
def issue_details_params
- params.permit(:issue_id)
+ params.permit(:issue_id).merge(tracking_event: :error_tracking_view_details)
end
def set_issue_id
diff --git a/app/controllers/projects/forks_controller.rb b/app/controllers/projects/forks_controller.rb
index 475c41eec9c..3208a5076e7 100644
--- a/app/controllers/projects/forks_controller.rb
+++ b/app/controllers/projects/forks_controller.rb
@@ -17,10 +17,6 @@ class Projects::ForksController < Projects::ApplicationController
feature_category :source_code_management
urgency :low, [:index]
- before_action do
- push_frontend_feature_flag(:fork_project_form, @project, default_enabled: :yaml)
- end
-
def index
@sort = forks_params[:sort]
@@ -54,9 +50,7 @@ class Projects::ForksController < Projects::ApplicationController
format.json do
namespaces = load_namespaces_with_associations - [project.namespace]
- namespaces = [current_user.namespace] + namespaces if
- Feature.enabled?(:fork_project_form, project, default_enabled: :yaml) &&
- can_fork_to?(current_user.namespace)
+ namespaces = [current_user.namespace] + namespaces if can_fork_to?(current_user.namespace)
render json: {
namespaces: ForkNamespaceSerializer.new.represent(
diff --git a/app/controllers/projects/google_cloud/base_controller.rb b/app/controllers/projects/google_cloud/base_controller.rb
index f4a773a62f6..f293ec752ab 100644
--- a/app/controllers/projects/google_cloud/base_controller.rb
+++ b/app/controllers/projects/google_cloud/base_controller.rb
@@ -10,18 +10,25 @@ class Projects::GoogleCloud::BaseController < Projects::ApplicationController
private
def admin_project_google_cloud!
- access_denied! unless can?(current_user, :admin_project_google_cloud, project)
+ unless can?(current_user, :admin_project_google_cloud, project)
+ track_event('admin_project_google_cloud!', 'access_denied', 'invalid_user')
+ access_denied!
+ end
end
def google_oauth2_enabled!
config = Gitlab::Auth::OAuth::Provider.config_for('google_oauth2')
if config.app_id.blank? || config.app_secret.blank?
+ track_event('google_oauth2_enabled!', 'access_denied', { reason: 'google_oauth2_not_configured', config: config })
access_denied! 'This GitLab instance not configured for Google Oauth2.'
end
end
def feature_flag_enabled!
- access_denied! unless Feature.enabled?(:incubation_5mp_google_cloud, project)
+ unless Feature.enabled?(:incubation_5mp_google_cloud)
+ track_event('feature_flag_enabled!', 'access_denied', 'feature_flag_not_enabled')
+ access_denied!
+ end
end
def validate_gcp_token!
@@ -53,9 +60,21 @@ class Projects::GoogleCloud::BaseController < Projects::ApplicationController
session[GoogleApi::CloudPlatform::Client.session_key_for_expires_at]
end
- def handle_gcp_error(error, project)
- Gitlab::ErrorTracking.track_exception(error, project_id: project.id)
+ def handle_gcp_error(action, error)
+ track_event(action, 'gcp_error', error)
@js_data = { screen: 'gcp_error', error: error.to_s }.to_json
render status: :unauthorized, template: 'projects/google_cloud/errors/gcp_error'
end
+
+ def track_event(action, label, property)
+ options = { label: label, project: project, user: current_user }
+
+ if property.is_a?(String)
+ options[:property] = property
+ else
+ options[:extra] = property
+ end
+
+ Gitlab::Tracking.event('Projects::GoogleCloud', action, **options)
+ end
end
diff --git a/app/controllers/projects/google_cloud/deployments_controller.rb b/app/controllers/projects/google_cloud/deployments_controller.rb
index 1941eb8a5f9..4867d344c5a 100644
--- a/app/controllers/projects/google_cloud/deployments_controller.rb
+++ b/app/controllers/projects/google_cloud/deployments_controller.rb
@@ -9,6 +9,7 @@ class Projects::GoogleCloud::DeploymentsController < Projects::GoogleCloud::Base
.new(project, current_user, params).execute
if enable_cloud_run_response[:status] == :error
+ track_event('deployments#cloud_run', 'enable_cloud_run_error', enable_cloud_run_response)
flash[:error] = enable_cloud_run_response[:message]
redirect_to project_google_cloud_index_path(project)
else
@@ -17,15 +18,17 @@ class Projects::GoogleCloud::DeploymentsController < Projects::GoogleCloud::Base
.new(project, current_user, params).execute
if generate_pipeline_response[:status] == :error
+ track_event('deployments#cloud_run', 'generate_pipeline_error', generate_pipeline_response)
flash[:error] = 'Failed to generate pipeline'
redirect_to project_google_cloud_index_path(project)
else
cloud_run_mr_params = cloud_run_mr_params(generate_pipeline_response[:branch_name])
+ track_event('deployments#cloud_run', 'cloud_run_success', cloud_run_mr_params)
redirect_to project_new_merge_request_path(project, merge_request: cloud_run_mr_params)
end
end
rescue Google::Apis::ClientError => error
- handle_gcp_error(error, project)
+ handle_gcp_error('deployments#cloud_run', error)
end
def cloud_storage
diff --git a/app/controllers/projects/google_cloud/gcp_regions_controller.rb b/app/controllers/projects/google_cloud/gcp_regions_controller.rb
new file mode 100644
index 00000000000..beeb91cfd80
--- /dev/null
+++ b/app/controllers/projects/google_cloud/gcp_regions_controller.rb
@@ -0,0 +1,31 @@
+# frozen_string_literal: true
+
+class Projects::GoogleCloud::GcpRegionsController < Projects::GoogleCloud::BaseController
+ # filtered list of GCP cloud run locations...
+ # ...that have domain mapping available
+ # Source https://cloud.google.com/run/docs/locations 2022-01-30
+ AVAILABLE_REGIONS = %w[asia-east1 asia-northeast1 asia-southeast1 europe-north1 europe-west1 europe-west4 us-central1 us-east1 us-east4 us-west1].freeze
+
+ def index
+ @google_cloud_path = project_google_cloud_index_path(project)
+ params = { per_page: 50 }
+ branches = BranchesFinder.new(project.repository, params).execute(gitaly_pagination: true)
+ tags = TagsFinder.new(project.repository, params).execute(gitaly_pagination: true)
+ refs = (branches + tags).map(&:name)
+ js_data = {
+ screen: 'gcp_regions_form',
+ availableRegions: AVAILABLE_REGIONS,
+ refs: refs,
+ cancelPath: project_google_cloud_index_path(project)
+ }
+ @js_data = js_data.to_json
+ track_event('gcp_regions#index', 'form_render', js_data)
+ end
+
+ def create
+ permitted_params = params.permit(:ref, :gcp_region)
+ response = GoogleCloud::GcpRegionAddOrReplaceService.new(project).execute(permitted_params[:ref], permitted_params[:gcp_region])
+ track_event('gcp_regions#create', 'form_submit', response)
+ redirect_to project_google_cloud_index_path(project), notice: _('GCP region configured')
+ end
+end
diff --git a/app/controllers/projects/google_cloud/revoke_oauth_controller.rb b/app/controllers/projects/google_cloud/revoke_oauth_controller.rb
new file mode 100644
index 00000000000..03d1474707b
--- /dev/null
+++ b/app/controllers/projects/google_cloud/revoke_oauth_controller.rb
@@ -0,0 +1,23 @@
+# frozen_string_literal: true
+
+class Projects::GoogleCloud::RevokeOauthController < Projects::GoogleCloud::BaseController
+ before_action :validate_gcp_token!
+
+ def create
+ google_api_client = GoogleApi::CloudPlatform::Client.new(token_in_session, nil)
+ response = google_api_client.revoke_authorizations
+
+ if response.success?
+ status = 'success'
+ redirect_message = { notice: s_('GoogleCloud|Google OAuth2 token revocation requested') }
+ else
+ status = 'failed'
+ redirect_message = { alert: s_('GoogleCloud|Google OAuth2 token revocation request failed') }
+ end
+
+ session.delete(GoogleApi::CloudPlatform::Client.session_key_for_token)
+ track_event('revoke_oauth#create', 'create', status)
+
+ redirect_to project_google_cloud_index_path(project), redirect_message
+ end
+end
diff --git a/app/controllers/projects/google_cloud/service_accounts_controller.rb b/app/controllers/projects/google_cloud/service_accounts_controller.rb
index b5f2b658235..5d8b2030d5c 100644
--- a/app/controllers/projects/google_cloud/service_accounts_controller.rb
+++ b/app/controllers/projects/google_cloud/service_accounts_controller.rb
@@ -10,30 +10,41 @@ class Projects::GoogleCloud::ServiceAccountsController < Projects::GoogleCloud::
if gcp_projects.empty?
@js_data = { screen: 'no_gcp_projects' }.to_json
+ track_event('service_accounts#index', 'form_error', 'no_gcp_projects')
render status: :unauthorized, template: 'projects/google_cloud/errors/no_gcp_projects'
else
- @js_data = {
+ params = { per_page: 50 }
+ branches = BranchesFinder.new(project.repository, params).execute(gitaly_pagination: true)
+ tags = TagsFinder.new(project.repository, params).execute(gitaly_pagination: true)
+ refs = (branches + tags).map(&:name)
+ js_data = {
screen: 'service_accounts_form',
gcpProjects: gcp_projects,
- environments: project.environments,
+ refs: refs,
cancelPath: project_google_cloud_index_path(project)
- }.to_json
+ }
+ @js_data = js_data.to_json
+
+ track_event('service_accounts#index', 'form_success', js_data)
end
rescue Google::Apis::ClientError => error
- handle_gcp_error(error, project)
+ handle_gcp_error('service_accounts#index', error)
end
def create
+ permitted_params = params.permit(:gcp_project, :ref)
+
response = GoogleCloud::CreateServiceAccountsService.new(
project,
current_user,
google_oauth2_token: token_in_session,
- gcp_project_id: params[:gcp_project],
- environment_name: params[:environment]
+ gcp_project_id: permitted_params[:gcp_project],
+ environment_name: permitted_params[:ref]
).execute
+ track_event('service_accounts#create', 'form_submit', response)
redirect_to project_google_cloud_index_path(project), notice: response.message
rescue Google::Apis::ClientError, Google::Apis::ServerError, Google::Apis::AuthorizationError => error
- handle_gcp_error(error, project)
+ handle_gcp_error('service_accounts#create', error)
end
end
diff --git a/app/controllers/projects/google_cloud_controller.rb b/app/controllers/projects/google_cloud_controller.rb
index 206a8c7e391..49bb4bec859 100644
--- a/app/controllers/projects/google_cloud_controller.rb
+++ b/app/controllers/projects/google_cloud_controller.rb
@@ -1,14 +1,34 @@
# frozen_string_literal: true
class Projects::GoogleCloudController < Projects::GoogleCloud::BaseController
+ GCP_REGION_CI_VAR_KEY = 'GCP_REGION'
+
def index
- @js_data = {
+ js_data = {
screen: 'home',
serviceAccounts: GoogleCloud::ServiceAccountsService.new(project).find_for_project,
createServiceAccountUrl: project_google_cloud_service_accounts_path(project),
enableCloudRunUrl: project_google_cloud_deployments_cloud_run_path(project),
enableCloudStorageUrl: project_google_cloud_deployments_cloud_storage_path(project),
- emptyIllustrationUrl: ActionController::Base.helpers.image_path('illustrations/pipelines_empty.svg')
- }.to_json
+ emptyIllustrationUrl: ActionController::Base.helpers.image_path('illustrations/pipelines_empty.svg'),
+ configureGcpRegionsUrl: project_google_cloud_gcp_regions_path(project),
+ gcpRegions: gcp_regions,
+ revokeOauthUrl: revoke_oauth_url
+ }
+ @js_data = js_data.to_json
+ track_event('google_cloud#index', 'index', js_data)
+ end
+
+ private
+
+ def gcp_regions
+ list = ::Ci::VariablesFinder.new(project, { key: GCP_REGION_CI_VAR_KEY }).execute
+ list.map { |variable| { gcp_region: variable.value, environment: variable.environment_scope } }
+ end
+
+ def revoke_oauth_url
+ google_token_valid = GoogleApi::CloudPlatform::Client.new(token_in_session, nil)
+ .validate_token(expires_at_in_session)
+ google_token_valid ? project_google_cloud_revoke_oauth_index_path(project) : nil
end
end
diff --git a/app/controllers/projects/harbor/application_controller.rb b/app/controllers/projects/harbor/application_controller.rb
new file mode 100644
index 00000000000..e6e694783fa
--- /dev/null
+++ b/app/controllers/projects/harbor/application_controller.rb
@@ -0,0 +1,22 @@
+# frozen_string_literal: true
+
+module Projects
+ module Harbor
+ class ApplicationController < Projects::ApplicationController
+ layout 'project'
+
+ before_action :harbor_registry_enabled!
+ before_action do
+ push_frontend_feature_flag(:harbor_registry_integration)
+ end
+
+ feature_category :integrations
+
+ private
+
+ def harbor_registry_enabled!
+ render_404 unless Feature.enabled?(:harbor_registry_integration)
+ end
+ end
+ end
+end
diff --git a/app/controllers/projects/harbor/repositories_controller.rb b/app/controllers/projects/harbor/repositories_controller.rb
new file mode 100644
index 00000000000..dd3e3dc1978
--- /dev/null
+++ b/app/controllers/projects/harbor/repositories_controller.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+module Projects
+ module Harbor
+ class RepositoriesController < ::Projects::Harbor::ApplicationController
+ def show
+ render :index
+ end
+ end
+ end
+end
diff --git a/app/controllers/projects/incidents_controller.rb b/app/controllers/projects/incidents_controller.rb
index 3395e75666e..293581a6744 100644
--- a/app/controllers/projects/incidents_controller.rb
+++ b/app/controllers/projects/incidents_controller.rb
@@ -6,6 +6,11 @@ class Projects::IncidentsController < Projects::ApplicationController
before_action :authorize_read_issue!
before_action :load_incident, only: [:show]
+ before_action do
+ push_frontend_feature_flag(:incident_escalations, @project)
+ push_frontend_feature_flag(:incident_timeline_event_tab, @project, default_enabled: :yaml)
+ push_licensed_feature(:incident_timeline_events) if @project.licensed_feature_available?(:incident_timeline_events)
+ end
feature_category :incident_management
@@ -43,3 +48,5 @@ class Projects::IncidentsController < Projects::ApplicationController
IssueSerializer.new(current_user: current_user, project: incident.project)
end
end
+
+Projects::IncidentsController.prepend_mod
diff --git a/app/controllers/projects/issues_controller.rb b/app/controllers/projects/issues_controller.rb
index 1b98810b09b..d4474b9d5a3 100644
--- a/app/controllers/projects/issues_controller.rb
+++ b/app/controllers/projects/issues_controller.rb
@@ -36,11 +36,6 @@ class Projects::IssuesController < Projects::ApplicationController
before_action :authorize_import_issues!, only: [:import_csv]
before_action :authorize_download_code!, only: [:related_branches]
- # Limit the amount of issues created per minute
- before_action -> { check_rate_limit!(:issues_create, scope: [@project, @current_user])},
- only: [:create],
- if: -> { Feature.disabled?('rate_limited_service_issues_create', project, default_enabled: :yaml) }
-
before_action do
push_frontend_feature_flag(:improved_emoji_picker, project, default_enabled: :yaml)
push_frontend_feature_flag(:vue_issues_list, project&.group, default_enabled: :yaml)
@@ -50,12 +45,10 @@ class Projects::IssuesController < Projects::ApplicationController
end
before_action only: :show do
- push_frontend_feature_flag(:real_time_issue_sidebar, project, default_enabled: :yaml)
push_frontend_feature_flag(:confidential_notes, project&.group, default_enabled: :yaml)
push_frontend_feature_flag(:issue_assignees_widget, project, default_enabled: :yaml)
push_frontend_feature_flag(:paginated_issue_discussions, project, default_enabled: :yaml)
- push_frontend_feature_flag(:fix_comment_scroll, project, default_enabled: :yaml)
- push_frontend_feature_flag(:work_items, project, default_enabled: :yaml)
+ push_frontend_feature_flag(:work_items, project&.group, default_enabled: :yaml)
end
around_action :allow_gitaly_ref_name_caching, only: [:discussions]
@@ -79,13 +72,16 @@ class Projects::IssuesController < Projects::ApplicationController
attr_accessor :vulnerability_id
def index
- set_issuables_index if !html_request? || Feature.disabled?(:vue_issues_list, project&.group, default_enabled: :yaml)
-
- @issues = @issuables
+ if html_request? && Feature.enabled?(:vue_issues_list, project&.group, default_enabled: :yaml)
+ set_sort_order
+ else
+ set_issuables_index
+ @issues = @issuables
+ end
respond_to do |format|
format.html
- format.atom { render layout: 'xml.atom' }
+ format.atom { render layout: 'xml' }
format.json do
render json: {
html: view_to_html_string("projects/issues/_issues"),
@@ -112,6 +108,8 @@ class Projects::IssuesController < Projects::ApplicationController
@issue = @noteable = service.execute
+ @add_related_issue = add_related_issue
+
@merge_request_to_resolve_discussions_of = service.merge_request_to_resolve_discussions_of
if params[:discussion_to_resolve]
@@ -128,6 +126,7 @@ class Projects::IssuesController < Projects::ApplicationController
def create
create_params = issue_params.merge(
+ add_related_issue: add_related_issue,
merge_request_to_resolve_discussions_of: params[:merge_request_to_resolve_discussions_of],
discussion_to_resolve: params[:discussion_to_resolve]
)
@@ -150,7 +149,7 @@ class Projects::IssuesController < Projects::ApplicationController
redirect_to project_issue_path(@project, @issue)
else
# NOTE: this CAPTCHA support method is indirectly included via IssuableActions
- with_captcha_check_html_format { render :new }
+ with_captcha_check_html_format(spammable: spammable) { render :new }
end
end
@@ -383,6 +382,11 @@ class Projects::IssuesController < Projects::ApplicationController
action_name == 'service_desk'
end
+ def add_related_issue
+ add_related_issue = project.issues.find_by_iid(params[:add_related_issue])
+ add_related_issue if Ability.allowed?(current_user, :read_issue, add_related_issue)
+ end
+
# Overridden in EE
def create_vulnerability_issue_feedback(issue); end
end
diff --git a/app/controllers/projects/jobs_controller.rb b/app/controllers/projects/jobs_controller.rb
index bfc2fe6432d..b0f032a01e5 100644
--- a/app/controllers/projects/jobs_controller.rb
+++ b/app/controllers/projects/jobs_controller.rb
@@ -4,6 +4,8 @@ class Projects::JobsController < Projects::ApplicationController
include SendFileUpload
include ContinueParams
+ urgency :low, [:index, :show, :trace, :retry, :play, :cancel, :unschedule, :status, :erase, :raw]
+
before_action :find_job_as_build, except: [:index, :play, :show]
before_action :find_job_as_processable, only: [:play, :show]
before_action :authorize_read_build_trace!, only: [:trace, :raw]
diff --git a/app/controllers/projects/merge_requests/diffs_controller.rb b/app/controllers/projects/merge_requests/diffs_controller.rb
index 9bc9c19157a..0dcc2bc3181 100644
--- a/app/controllers/projects/merge_requests/diffs_controller.rb
+++ b/app/controllers/projects/merge_requests/diffs_controller.rb
@@ -111,9 +111,7 @@ class Projects::MergeRequests::DiffsController < Projects::MergeRequests::Applic
allow_tree_conflicts: display_merge_conflicts_in_diff?
)
- if @merge_request.project.context_commits_enabled?
- options[:context_commits] = @merge_request.recent_context_commits
- end
+ options[:context_commits] = @merge_request.recent_context_commits
render json: DiffsSerializer.new(request).represent(diffs, options)
end
diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb
index 6445f920db5..60d7920f83e 100644
--- a/app/controllers/projects/merge_requests_controller.rb
+++ b/app/controllers/projects/merge_requests_controller.rb
@@ -30,14 +30,10 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
before_action :set_issuables_index, only: [:index]
before_action :authenticate_user!, only: [:assign_related_issues]
before_action :check_user_can_push_to_source_branch!, only: [:rebase]
- before_action only: [:index, :show] do
- push_frontend_feature_flag(:mr_attention_requests, project, default_enabled: :yaml)
- end
before_action only: [:show] do
push_frontend_feature_flag(:file_identifier_hash)
push_frontend_feature_flag(:merge_request_widget_graphql, project, default_enabled: :yaml)
- push_frontend_feature_flag(:default_merge_ref_for_diffs, project, default_enabled: :yaml)
push_frontend_feature_flag(:core_security_mr_widget_counts, project)
push_frontend_feature_flag(:paginated_notes, project, default_enabled: :yaml)
push_frontend_feature_flag(:confidential_notes, project, default_enabled: :yaml)
@@ -45,8 +41,9 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
push_frontend_feature_flag(:restructured_mr_widget, project, default_enabled: :yaml)
push_frontend_feature_flag(:refactor_mr_widgets_extensions, project, default_enabled: :yaml)
push_frontend_feature_flag(:rebase_without_ci_ui, project, default_enabled: :yaml)
- push_frontend_feature_flag(:rearrange_pipelines_table, project, default_enabled: :yaml)
push_frontend_feature_flag(:markdown_continue_lists, project, default_enabled: :yaml)
+ push_frontend_feature_flag(:secure_vulnerability_training, project, default_enabled: :yaml)
+ push_frontend_feature_flag(:issue_assignees_widget, @project, default_enabled: :yaml)
# Usage data feature flags
push_frontend_feature_flag(:users_expanding_widgets_usage_data, project, default_enabled: :yaml)
push_frontend_feature_flag(:diff_settings_usage_data, default_enabled: :yaml)
@@ -87,7 +84,8 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
:ci_environments_status,
:destroy,
:rebase,
- :discussions
+ :discussions,
+ :pipelines
]
def index
@@ -95,7 +93,7 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
respond_to do |format|
format.html
- format.atom { render layout: 'xml.atom' }
+ format.atom { render layout: 'xml' }
format.json do
render json: {
html: view_to_html_string("projects/merge_requests/_merge_requests")
@@ -220,8 +218,6 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
end
def context_commits
- return render_404 unless project.context_commits_enabled?
-
# Get commits from repository
# or from cache if already merged
commits = ContextCommitsFinder.new(project, @merge_request, { search: params[:search], limit: params[:limit], offset: params[:offset] }).execute
@@ -553,12 +549,7 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
end
def endpoint_metadata_url(project, merge_request)
- params = request.query_parameters
- params[:view] = "inline"
-
- if Feature.enabled?(:default_merge_ref_for_diffs, project, default_enabled: :yaml)
- params = params.merge(diff_head: true)
- end
+ params = request.query_parameters.merge(view: 'inline', diff_head: true)
diffs_metadata_project_json_merge_request_path(project, merge_request, 'json', params)
end
diff --git a/app/controllers/projects/pipeline_schedules_controller.rb b/app/controllers/projects/pipeline_schedules_controller.rb
index ac94cc001dd..271c31b6429 100644
--- a/app/controllers/projects/pipeline_schedules_controller.rb
+++ b/app/controllers/projects/pipeline_schedules_controller.rb
@@ -10,6 +10,10 @@ class Projects::PipelineSchedulesController < Projects::ApplicationController
before_action :authorize_update_pipeline_schedule!, except: [:index, :new, :create, :play]
before_action :authorize_admin_pipeline_schedule!, only: [:destroy]
+ before_action do
+ push_frontend_feature_flag(:pipeline_schedules_with_tags, @project, default_enabled: :yaml)
+ end
+
feature_category :continuous_integration
# rubocop: disable CodeReuse/ActiveRecord
diff --git a/app/controllers/projects/pipelines/stages_controller.rb b/app/controllers/projects/pipelines/stages_controller.rb
index ce08b49ce9f..0447bbf29e7 100644
--- a/app/controllers/projects/pipelines/stages_controller.rb
+++ b/app/controllers/projects/pipelines/stages_controller.rb
@@ -5,6 +5,10 @@ module Projects
class StagesController < Projects::Pipelines::ApplicationController
before_action :authorize_update_pipeline!
+ urgency :low, [
+ :play_manual
+ ]
+
def play_manual
::Ci::PlayManualStageService
.new(@project, current_user, pipeline: pipeline)
diff --git a/app/controllers/projects/pipelines/tests_controller.rb b/app/controllers/projects/pipelines/tests_controller.rb
index 25ec7ab1335..602fc02686a 100644
--- a/app/controllers/projects/pipelines/tests_controller.rb
+++ b/app/controllers/projects/pipelines/tests_controller.rb
@@ -42,9 +42,9 @@ module Projects
end
def test_suite
- suite = builds.map do |build|
+ suite = builds.sum do |build|
build.collect_test_reports!(Gitlab::Ci::Reports::TestReports.new)
- end.sum
+ end
Gitlab::Ci::Reports::TestFailureHistory.new(suite.failed.values, project).load!
diff --git a/app/controllers/projects/pipelines_controller.rb b/app/controllers/projects/pipelines_controller.rb
index 7f680bbf121..8279bb20769 100644
--- a/app/controllers/projects/pipelines_controller.rb
+++ b/app/controllers/projects/pipelines_controller.rb
@@ -4,6 +4,9 @@ class Projects::PipelinesController < Projects::ApplicationController
include ::Gitlab::Utils::StrongMemoize
include RedisTracking
+ urgency :default, [:status]
+ urgency :low, [:index, :new, :builds, :show, :failures, :create, :stage, :retry, :dag, :cancel]
+
before_action :disable_query_limiting, only: [:create, :retry]
before_action :pipeline, except: [:index, :new, :create, :charts, :config_variables]
before_action :set_pipeline_path, only: [:show]
@@ -13,13 +16,6 @@ class Projects::PipelinesController < Projects::ApplicationController
before_action :authorize_create_pipeline!, only: [:new, :create, :config_variables]
before_action :authorize_update_pipeline!, only: [:retry, :cancel]
before_action :ensure_pipeline, only: [:show, :downloadable_artifacts]
- before_action do
- push_frontend_feature_flag(:rearrange_pipelines_table, project, default_enabled: :yaml)
- end
-
- before_action do
- push_frontend_feature_flag(:jobs_tab_vue, @project, default_enabled: :yaml)
- end
# Will be removed with https://gitlab.com/gitlab-org/gitlab/-/issues/225596
before_action :redirect_for_legacy_scope_filter, only: [:index], if: -> { request.format.html? }
@@ -55,8 +51,7 @@ class Projects::PipelinesController < Projects::ApplicationController
respond_to do |format|
format.html do
- enable_code_quality_walkthrough_experiment
- enable_ci_runner_templates_experiment
+ enable_runners_availability_section_experiment
end
format.json do
Gitlab::PollingInterval.set_header(response, interval: POLLING_INTERVAL)
@@ -166,14 +161,20 @@ class Projects::PipelinesController < Projects::ApplicationController
end
def retry
- ::Ci::RetryPipelineWorker.perform_async(pipeline.id, current_user.id) # rubocop:disable CodeReuse/Worker
+ # Check for access before execution to allow for async execution while still returning access results
+ access_response = ::Ci::RetryPipelineService.new(@project, current_user).check_access(pipeline)
+
+ if access_response.error?
+ response = { json: { errors: [access_response.message] }, status: access_response.http_status }
+ else
+ response = { json: {}, status: :no_content }
+ ::Ci::RetryPipelineWorker.perform_async(pipeline.id, current_user.id) # rubocop:disable CodeReuse/Worker
+ end
respond_to do |format|
- format.html do
- redirect_back_or_default default: project_pipelines_path(project)
+ format.json do
+ render response
end
-
- format.json { head :no_content }
end
end
@@ -224,7 +225,7 @@ class Projects::PipelinesController < Projects::ApplicationController
PipelineSerializer
.new(project: @project, current_user: @current_user)
.with_pagination(request, response)
- .represent(@pipelines, disable_coverage: true, preload: true, code_quality_walkthrough: params[:code_quality_walkthrough].present?)
+ .represent(@pipelines, disable_coverage: true, preload: true)
end
def render_show
@@ -309,28 +310,13 @@ class Projects::PipelinesController < Projects::ApplicationController
params.permit(:scope, :username, :ref, :status, :source)
end
- def enable_code_quality_walkthrough_experiment
- experiment(:code_quality_walkthrough, namespace: project.root_ancestor) do |e|
- e.exclude! unless current_user
- e.exclude! unless can?(current_user, :create_pipeline, project)
- e.exclude! unless project.root_ancestor.recent?
- e.exclude! if @pipelines_count.to_i > 0
- e.exclude! if helpers.has_gitlab_ci?(project)
-
- e.control {}
- e.candidate {}
- e.publish_to_database
- end
- end
-
- def enable_ci_runner_templates_experiment
- experiment(:ci_runner_templates, namespace: project.root_ancestor) do |e|
- e.exclude! unless current_user
- e.exclude! unless can?(current_user, :create_pipeline, project)
- e.exclude! if @pipelines_count.to_i > 0
- e.exclude! if helpers.has_gitlab_ci?(project)
+ def enable_runners_availability_section_experiment
+ return unless current_user
+ return unless can?(current_user, :create_pipeline, project)
+ return if @pipelines_count.to_i > 0
+ return if helpers.has_gitlab_ci?(project)
- e.control {}
+ experiment(:runners_availability_section, namespace: project.root_ancestor) do |e|
e.candidate {}
e.publish_to_database
end
diff --git a/app/controllers/projects/project_members_controller.rb b/app/controllers/projects/project_members_controller.rb
index dc0614c6bdd..0279a65f262 100644
--- a/app/controllers/projects/project_members_controller.rb
+++ b/app/controllers/projects/project_members_controller.rb
@@ -13,8 +13,6 @@ class Projects::ProjectMembersController < Projects::ApplicationController
def index
@sort = params[:sort].presence || sort_value_name
- @skip_groups = @project.related_group_ids
-
@group_links = @project.project_group_links
@group_links = @group_links.search(params[:search_groups]) if params[:search_groups].present?
@@ -24,25 +22,6 @@ class Projects::ProjectMembersController < Projects::ApplicationController
end
@project_members = present_members(non_invited_members.page(params[:page]))
-
- @project_member = @project.project_members.new
- end
-
- def import
- @projects = Project.visible_to_user_and_access_level(current_user, Gitlab::Access::MAINTAINER).order_id_desc
- end
-
- def apply_import
- source_project = Project.find(params[:source_project_id])
-
- if can?(current_user, :admin_project_member, source_project)
- status = @project.team.import(source_project, current_user)
- notice = status ? "Successfully imported" : "Import failed"
- else
- return render_404
- end
-
- redirect_to(project_project_members_path(project), notice: notice)
end
# MembershipActions concern
diff --git a/app/controllers/projects/redirect_controller.rb b/app/controllers/projects/redirect_controller.rb
new file mode 100644
index 00000000000..6bcbe87ee42
--- /dev/null
+++ b/app/controllers/projects/redirect_controller.rb
@@ -0,0 +1,20 @@
+# frozen_string_literal: true
+
+# Projects::RedirectController is used to resolve the route projects/:id.
+# It's helpful for this to be in its own controller so that the
+# ProjectsController can assume that :namespace_id exists
+class Projects::RedirectController < ::ApplicationController
+ skip_before_action :authenticate_user!
+
+ feature_category :projects
+
+ def redirect_from_id
+ project = Project.find(params[:id])
+
+ if can?(current_user, :read_project, project)
+ redirect_to project
+ else
+ render_404
+ end
+ end
+end
diff --git a/app/controllers/projects/releases_controller.rb b/app/controllers/projects/releases_controller.rb
index 7fba6cc5bf4..1a2baf96020 100644
--- a/app/controllers/projects/releases_controller.rb
+++ b/app/controllers/projects/releases_controller.rb
@@ -7,6 +7,7 @@ class Projects::ReleasesController < Projects::ApplicationController
before_action :authorize_read_release!
before_action :authorize_update_release!, only: %i[edit update]
before_action :authorize_create_release!, only: :new
+ before_action :validate_suffix_path, :fetch_latest_tag, only: :latest_permalink
before_action only: :index do
push_frontend_feature_flag(:releases_index_apollo_client, project, default_enabled: :yaml)
end
@@ -26,10 +27,24 @@ class Projects::ReleasesController < Projects::ApplicationController
redirect_to link.url
end
+ def latest_permalink
+ unless @latest_tag.present?
+ return render_404
+ end
+
+ query_parameters_except_order_by = request.query_parameters.except(:order_by)
+
+ redirect_url = project_release_url(@project, @latest_tag)
+ redirect_url += "/#{params[:suffix_path]}" if params[:suffix_path]
+ redirect_url += "?#{query_parameters_except_order_by.compact.to_param}" if query_parameters_except_order_by.present?
+
+ redirect_to redirect_url
+ end
+
private
- def releases
- ReleasesFinder.new(@project, current_user).execute
+ def releases(params = {})
+ ReleasesFinder.new(@project, current_user, params).execute
end
def authorize_update_release!
@@ -51,4 +66,18 @@ class Projects::ReleasesController < Projects::ApplicationController
def sanitized_tag_name
CGI.unescape(params[:tag])
end
+
+ # Default order_by is 'released_at', which is set in ReleasesFinder.
+ # Also if the passed order_by is invalid, we reject and default to 'released_at'.
+ def fetch_latest_tag
+ allowed_values = ['released_at']
+
+ params.reject! { |key, value| key.to_sym == :order_by && !allowed_values.any?(value) }
+
+ @latest_tag = releases(order_by: params[:order_by]).first&.tag
+ end
+
+ def validate_suffix_path
+ Gitlab::Utils.check_path_traversal!(params[:suffix_path]) if params[:suffix_path]
+ end
end
diff --git a/app/controllers/projects/runner_projects_controller.rb b/app/controllers/projects/runner_projects_controller.rb
index 39db7618db0..b77ce070492 100644
--- a/app/controllers/projects/runner_projects_controller.rb
+++ b/app/controllers/projects/runner_projects_controller.rb
@@ -14,7 +14,7 @@ class Projects::RunnerProjectsController < Projects::ApplicationController
path = project_runners_path(project)
- if @runner.assign_to(project, current_user)
+ if ::Ci::Runners::AssignRunnerService.new(@runner, @project, current_user).execute
redirect_to path, notice: s_('Runners|Runner assigned to project.')
else
assign_to_messages = @runner.errors.messages[:assign_to]
@@ -26,7 +26,8 @@ class Projects::RunnerProjectsController < Projects::ApplicationController
def destroy
runner_project = project.runner_projects.find(params[:id])
- runner_project.destroy
+
+ ::Ci::Runners::UnassignRunnerService.new(runner_project, current_user).execute
redirect_to project_runners_path(project), status: :found, notice: s_('Runners|Runner unassigned from project.')
end
diff --git a/app/controllers/projects/runners_controller.rb b/app/controllers/projects/runners_controller.rb
index 192a29730d9..0eda8e3352d 100644
--- a/app/controllers/projects/runners_controller.rb
+++ b/app/controllers/projects/runners_controller.rb
@@ -14,7 +14,7 @@ class Projects::RunnersController < Projects::ApplicationController
end
def update
- if Ci::UpdateRunnerService.new(@runner).update(runner_params)
+ if Ci::Runners::UpdateRunnerService.new(@runner).update(runner_params)
redirect_to project_runner_path(@project, @runner), notice: _('Runner was successfully updated.')
else
render 'edit'
@@ -23,14 +23,14 @@ class Projects::RunnersController < Projects::ApplicationController
def destroy
if @runner.only_for?(project)
- Ci::UnregisterRunnerService.new(@runner).execute
+ Ci::Runners::UnregisterRunnerService.new(@runner, current_user).execute
end
redirect_to project_runners_path(@project), status: :found
end
def resume
- if Ci::UpdateRunnerService.new(@runner).update(active: true)
+ if Ci::Runners::UpdateRunnerService.new(@runner).update(active: true)
redirect_to project_runners_path(@project), notice: _('Runner was successfully updated.')
else
redirect_to project_runners_path(@project), alert: _('Runner was not updated.')
@@ -38,7 +38,7 @@ class Projects::RunnersController < Projects::ApplicationController
end
def pause
- if Ci::UpdateRunnerService.new(@runner).update(active: false)
+ if Ci::Runners::UpdateRunnerService.new(@runner).update(active: false)
redirect_to project_runners_path(@project), notice: _('Runner was successfully updated.')
else
redirect_to project_runners_path(@project), alert: _('Runner was not updated.')
diff --git a/app/controllers/projects/serverless/functions_controller.rb b/app/controllers/projects/serverless/functions_controller.rb
index 3fc379a135a..b6f77a6d515 100644
--- a/app/controllers/projects/serverless/functions_controller.rb
+++ b/app/controllers/projects/serverless/functions_controller.rb
@@ -3,6 +3,7 @@
module Projects
module Serverless
class FunctionsController < Projects::ApplicationController
+ before_action :ensure_feature_enabled!
before_action :authorize_read_cluster!
feature_category :not_owned
@@ -69,6 +70,10 @@ module Projects
def serialize_function(function)
Projects::Serverless::ServiceSerializer.new(current_user: @current_user, project: project).represent(function)
end
+
+ def ensure_feature_enabled!
+ render_404 unless Feature.enabled?(:deprecated_serverless, project, default_enabled: :yaml, type: :ops)
+ end
end
end
end
diff --git a/app/controllers/projects/services_controller.rb b/app/controllers/projects/services_controller.rb
index 1321111faaf..105f8efde7b 100644
--- a/app/controllers/projects/services_controller.rb
+++ b/app/controllers/projects/services_controller.rb
@@ -13,6 +13,10 @@ class Projects::ServicesController < Projects::ApplicationController
before_action :set_deprecation_notice_for_prometheus_integration, only: [:edit, :update]
before_action :redirect_deprecated_prometheus_integration, only: [:update]
+ before_action do
+ push_frontend_feature_flag(:integration_form_sections, project, default_enabled: :yaml)
+ end
+
respond_to :html
layout "project_settings"
diff --git a/app/controllers/projects/settings/ci_cd_controller.rb b/app/controllers/projects/settings/ci_cd_controller.rb
index dd2fb57f7ac..3f4d26bb6ec 100644
--- a/app/controllers/projects/settings/ci_cd_controller.rb
+++ b/app/controllers/projects/settings/ci_cd_controller.rb
@@ -64,7 +64,7 @@ module Projects
end
def reset_registration_token
- @project.reset_runners_token!
+ ::Ci::Runners::ResetRegistrationTokenService.new(@project, current_user).execute
flash[:toast] = _("New runners registration token has been generated!")
redirect_to namespace_project_settings_ci_cd_path
diff --git a/app/controllers/projects/settings/operations_controller.rb b/app/controllers/projects/settings/operations_controller.rb
index 56e201c592f..43c72b358db 100644
--- a/app/controllers/projects/settings/operations_controller.rb
+++ b/app/controllers/projects/settings/operations_controller.rb
@@ -7,6 +7,10 @@ module Projects
before_action :authorize_admin_operations!
before_action :authorize_read_prometheus_alerts!, only: [:reset_alerting_token]
+ before_action do
+ push_frontend_feature_flag(:integrated_error_tracking, project)
+ end
+
respond_to :json, only: [:reset_alerting_token, :reset_pagerduty_token]
helper_method :error_tracking_setting
diff --git a/app/controllers/projects/tags_controller.rb b/app/controllers/projects/tags_controller.rb
index 6472d3c3454..eb3579551bd 100644
--- a/app/controllers/projects/tags_controller.rb
+++ b/app/controllers/projects/tags_controller.rb
@@ -42,7 +42,7 @@ class Projects::TagsController < Projects::ApplicationController
status = @tags_loading_error ? :service_unavailable : :ok
format.html { render status: status }
- format.atom { render layout: 'xml.atom', status: status }
+ format.atom { render layout: 'xml', status: status }
end
end
# rubocop: enable CodeReuse/ActiveRecord
diff --git a/app/controllers/projects/tree_controller.rb b/app/controllers/projects/tree_controller.rb
index 4f905a2d565..e447fc3f3fe 100644
--- a/app/controllers/projects/tree_controller.rb
+++ b/app/controllers/projects/tree_controller.rb
@@ -22,7 +22,6 @@ class Projects::TreeController < Projects::ApplicationController
push_frontend_feature_flag(:refactor_blob_viewer, @project, default_enabled: :yaml)
push_frontend_feature_flag(:highlight_js, @project, default_enabled: :yaml)
push_licensed_feature(:file_locks) if @project.licensed_feature_available?(:file_locks)
- push_frontend_feature_flag(:consolidated_edit_button, @project, default_enabled: :yaml)
end
feature_category :source_code_management
diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb
index 519d9cd0d52..507a8b66942 100644
--- a/app/controllers/projects_controller.rb
+++ b/app/controllers/projects_controller.rb
@@ -17,10 +17,10 @@ class ProjectsController < Projects::ApplicationController
around_action :allow_gitaly_ref_name_caching, only: [:index, :show]
before_action :disable_query_limiting, only: [:show, :create]
- before_action :authenticate_user!, except: [:index, :show, :activity, :refs, :resolve, :unfoldered_environment_names]
+ before_action :authenticate_user!, except: [:index, :show, :activity, :refs, :unfoldered_environment_names]
before_action :redirect_git_extension, only: [:show]
- before_action :project, except: [:index, :new, :create, :resolve]
- before_action :repository, except: [:index, :new, :create, :resolve]
+ before_action :project, except: [:index, :new, :create]
+ before_action :repository, except: [:index, :new, :create]
before_action :verify_git_import_enabled, only: [:create]
before_action :project_export_enabled, only: [:export, :download_export, :remove_export, :generate_new_export]
before_action :present_project, only: [:edit]
@@ -41,7 +41,6 @@ class ProjectsController < Projects::ApplicationController
push_frontend_feature_flag(:increase_page_size_exponentially, @project, default_enabled: :yaml)
push_frontend_feature_flag(:new_dir_modal, @project, default_enabled: :yaml)
push_licensed_feature(:file_locks) if @project.present? && @project.licensed_feature_available?(:file_locks)
- push_frontend_feature_flag(:consolidated_edit_button, @project, default_enabled: :yaml)
push_frontend_feature_flag(:work_items, @project, default_enabled: :yaml)
end
@@ -49,7 +48,7 @@ class ProjectsController < Projects::ApplicationController
feature_category :projects, [
:index, :show, :new, :create, :edit, :update, :transfer,
- :destroy, :resolve, :archive, :unarchive, :toggle_star, :activity
+ :destroy, :archive, :unarchive, :toggle_star, :activity
]
feature_category :source_code_management, [:remove_fork, :housekeeping, :refs]
@@ -174,7 +173,7 @@ class ProjectsController < Projects::ApplicationController
format.atom do
load_events
@events = @events.select { |event| event.visible_to_user?(current_user) }
- render layout: 'xml.atom'
+ render layout: 'xml'
end
end
end
@@ -325,16 +324,6 @@ class ProjectsController < Projects::ApplicationController
end
# rubocop: enable CodeReuse/ActiveRecord
- def resolve
- @project = Project.find(params[:id])
-
- if can?(current_user, :read_project, @project)
- redirect_to @project
- else
- render_404
- end
- end
-
def unfoldered_environment_names
respond_to do |format|
format.json do
@@ -346,11 +335,7 @@ class ProjectsController < Projects::ApplicationController
private
def refs_params
- if Feature.enabled?(:strong_parameters_for_project_controller, @project, default_enabled: :yaml)
- params.permit(:search, :sort, :ref, find: [])
- else
- params
- end
+ params.permit(:search, :sort, :ref, find: [])
end
# Render project landing depending of which features are available
diff --git a/app/controllers/registrations_controller.rb b/app/controllers/registrations_controller.rb
index 057c451ace2..7011bf856e3 100644
--- a/app/controllers/registrations_controller.rb
+++ b/app/controllers/registrations_controller.rb
@@ -15,7 +15,7 @@ class RegistrationsController < Devise::RegistrationsController
before_action :load_recaptcha, only: :new
before_action :set_invite_params, only: :new
before_action only: [:create] do
- check_rate_limit!(:user_sign_up, scope: request.ip) if Feature.enabled?(:rate_limit_user_sign_up_endpoint, default_enabled: :yaml)
+ check_rate_limit!(:user_sign_up, scope: request.ip)
end
before_action only: [:new] do
diff --git a/app/controllers/search_controller.rb b/app/controllers/search_controller.rb
index e38eeaed367..817da658f14 100644
--- a/app/controllers/search_controller.rb
+++ b/app/controllers/search_controller.rb
@@ -4,6 +4,7 @@ class SearchController < ApplicationController
include ControllerWithCrossProjectAccessCheck
include SearchHelper
include RedisTracking
+ include SearchRateLimitable
RESCUE_FROM_TIMEOUT_ACTIONS = [:count, :show, :autocomplete].freeze
@@ -17,7 +18,7 @@ class SearchController < ApplicationController
search_term_present = params[:search].present? || params[:term].present?
search_term_present && !params[:project_id].present?
end
- before_action :check_email_search_rate_limit!, only: [:show, :count, :autocomplete]
+ before_action :check_search_rate_limit!, only: [:show, :count, :autocomplete]
rescue_from ActiveRecord::QueryCanceled, with: :render_timeout
@@ -25,6 +26,7 @@ class SearchController < ApplicationController
feature_category :global_search
urgency :high, [:opensearch]
+ urgency :low, [:count]
def show
@project = search_service.project
@@ -201,12 +203,6 @@ class SearchController < ApplicationController
render status: :request_timeout
end
end
-
- def check_email_search_rate_limit!
- return unless search_service.params.email_lookup?
-
- check_rate_limit!(:user_email_lookup, scope: [current_user])
- end
end
SearchController.prepend_mod_with('SearchController')
diff --git a/app/controllers/uploads_controller.rb b/app/controllers/uploads_controller.rb
index d7eb3ccd274..4df0ef78907 100644
--- a/app/controllers/uploads_controller.rb
+++ b/app/controllers/uploads_controller.rb
@@ -40,30 +40,29 @@ class UploadsController < ApplicationController
upload_model_class.find(params[:id])
end
- def authorize_access!
- authorized =
- case model
- when Note
- can?(current_user, :read_project, model.project)
- when Snippet, ProjectSnippet
- can?(current_user, :read_snippet, model)
- when User
- # We validate the current user has enough (writing)
- # access to itself when a secret is given.
- # For instance, user avatars are readable by anyone,
- # while temporary, user snippet uploads are not.
- !secret? || can?(current_user, :update_user, model)
- when Appearance
- true
- when Projects::Topic
- true
- else
- permission = "read_#{model.class.underscore}".to_sym
-
- can?(current_user, permission, model)
- end
+ def authorized?
+ case model
+ when Note
+ can?(current_user, :read_project, model.project)
+ when Snippet, ProjectSnippet
+ can?(current_user, :read_snippet, model)
+ when User
+ # We validate the current user has enough (writing)
+ # access to itself when a secret is given.
+ # For instance, user avatars are readable by anyone,
+ # while temporary, user snippet uploads are not.
+ !secret? || can?(current_user, :update_user, model)
+ when Appearance
+ true
+ when Projects::Topic
+ true
+ else
+ can?(current_user, "read_#{model.class.underscore}".to_sym, model)
+ end
+ end
- render_unauthorized unless authorized
+ def authorize_access!
+ render_unauthorized unless authorized?
end
def authorize_create_access!
diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb
index f6cef7e133c..dc02e4a3e87 100644
--- a/app/controllers/users_controller.rb
+++ b/app/controllers/users_controller.rb
@@ -24,7 +24,7 @@ class UsersController < ApplicationController
before_action :authorize_read_user_profile!,
only: [:calendar, :calendar_activities, :groups, :projects, :contributed, :starred, :snippets, :followers, :following]
before_action only: [:exists] do
- check_rate_limit!(:username_exists, scope: request.ip) if Feature.enabled?(:rate_limit_username_exists_endpoint, default_enabled: :yaml)
+ check_rate_limit!(:username_exists, scope: request.ip)
end
feature_category :users
@@ -35,7 +35,7 @@ class UsersController < ApplicationController
format.atom do
load_events
- render layout: 'xml.atom'
+ render layout: 'xml'
end
format.json do