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.rb1
-rw-r--r--app/controllers/admin/clusters_controller.rb9
-rw-r--r--app/controllers/admin/jobs_controller.rb4
-rw-r--r--app/controllers/admin/services_controller.rb11
-rw-r--r--app/controllers/application_controller.rb12
-rw-r--r--app/controllers/autocomplete_controller.rb16
-rw-r--r--app/controllers/chaos_controller.rb1
-rw-r--r--app/controllers/clusters/clusters_controller.rb25
-rw-r--r--app/controllers/concerns/controller_with_feature_category.rb45
-rw-r--r--app/controllers/concerns/controller_with_feature_category/config.rb38
-rw-r--r--app/controllers/concerns/filters_events.rb14
-rw-r--r--app/controllers/concerns/integrations_actions.rb8
-rw-r--r--app/controllers/concerns/issuable_actions.rb12
-rw-r--r--app/controllers/concerns/issuable_collections.rb61
-rw-r--r--app/controllers/concerns/known_sign_in.rb19
-rw-r--r--app/controllers/concerns/membership_actions.rb5
-rw-r--r--app/controllers/concerns/metrics/dashboard/prometheus_api_proxy.rb53
-rw-r--r--app/controllers/concerns/metrics_dashboard.rb14
-rw-r--r--app/controllers/concerns/notes_actions.rb84
-rw-r--r--app/controllers/concerns/renders_member_access.rb6
-rw-r--r--app/controllers/concerns/renders_projects_list.rb13
-rw-r--r--app/controllers/concerns/service_params.rb4
-rw-r--r--app/controllers/concerns/snippets/blobs_actions.rb53
-rw-r--r--app/controllers/concerns/snippets/send_blob.rb22
-rw-r--r--app/controllers/concerns/snippets_actions.rb19
-rw-r--r--app/controllers/concerns/snippets_sort.rb9
-rw-r--r--app/controllers/concerns/wiki_actions.rb49
-rw-r--r--app/controllers/dashboard/projects_controller.rb3
-rw-r--r--app/controllers/dashboard/snippets_controller.rb3
-rw-r--r--app/controllers/dashboard/todos_controller.rb3
-rw-r--r--app/controllers/dashboard_controller.rb1
-rw-r--r--app/controllers/explore/projects_controller.rb1
-rw-r--r--app/controllers/groups/application_controller.rb8
-rw-r--r--app/controllers/groups/boards_controller.rb1
-rw-r--r--app/controllers/groups/clusters_controller.rb10
-rw-r--r--app/controllers/groups/runners_controller.rb12
-rw-r--r--app/controllers/groups/settings/ci_cd_controller.rb8
-rw-r--r--app/controllers/groups/variables_controller.rb4
-rw-r--r--app/controllers/groups_controller.rb1
-rw-r--r--app/controllers/ide_controller.rb1
-rw-r--r--app/controllers/import/base_controller.rb11
-rw-r--r--app/controllers/import/bitbucket_controller.rb17
-rw-r--r--app/controllers/import/bitbucket_server_controller.rb46
-rw-r--r--app/controllers/import/fogbugz_controller.rb18
-rw-r--r--app/controllers/import/gitea_controller.rb14
-rw-r--r--app/controllers/import/github_controller.rb99
-rw-r--r--app/controllers/import/gitlab_controller.rb20
-rw-r--r--app/controllers/instance_statistics/cohorts_controller.rb4
-rw-r--r--app/controllers/instance_statistics/dev_ops_score_controller.rb4
-rw-r--r--app/controllers/invites_controller.rb19
-rw-r--r--app/controllers/oauth/applications_controller.rb6
-rw-r--r--app/controllers/omniauth_callbacks_controller.rb2
-rw-r--r--app/controllers/profiles/keys_controller.rb21
-rw-r--r--app/controllers/profiles/personal_access_tokens_controller.rb10
-rw-r--r--app/controllers/profiles/preferences_controller.rb1
-rw-r--r--app/controllers/projects/application_controller.rb6
-rw-r--r--app/controllers/projects/blob_controller.rb7
-rw-r--r--app/controllers/projects/boards_controller.rb1
-rw-r--r--app/controllers/projects/ci/lints_controller.rb2
-rw-r--r--app/controllers/projects/clusters_controller.rb11
-rw-r--r--app/controllers/projects/confluences_controller.rb14
-rw-r--r--app/controllers/projects/cycle_analytics_controller.rb3
-rw-r--r--app/controllers/projects/deployments_controller.rb1
-rw-r--r--app/controllers/projects/environments/prometheus_api_controller.rb46
-rw-r--r--app/controllers/projects/environments_controller.rb4
-rw-r--r--app/controllers/projects/forks_controller.rb1
-rw-r--r--app/controllers/projects/graphs_controller.rb3
-rw-r--r--app/controllers/projects/imports_controller.rb7
-rw-r--r--app/controllers/projects/incident_management/pager_duty_incidents_controller.rb35
-rw-r--r--app/controllers/projects/issues_controller.rb31
-rw-r--r--app/controllers/projects/jobs_controller.rb10
-rw-r--r--app/controllers/projects/logs_controller.rb46
-rw-r--r--app/controllers/projects/merge_requests/application_controller.rb9
-rw-r--r--app/controllers/projects/merge_requests/creations_controller.rb4
-rw-r--r--app/controllers/projects/merge_requests/diffs_controller.rb9
-rw-r--r--app/controllers/projects/merge_requests_controller.rb29
-rw-r--r--app/controllers/projects/metrics_dashboard_controller.rb33
-rw-r--r--app/controllers/projects/pipelines/application_controller.rb24
-rw-r--r--app/controllers/projects/pipelines/stages_controller.rb29
-rw-r--r--app/controllers/projects/pipelines/tests_controller.rb59
-rw-r--r--app/controllers/projects/pipelines_controller.rb25
-rw-r--r--app/controllers/projects/refs_controller.rb15
-rw-r--r--app/controllers/projects/releases_controller.rb21
-rw-r--r--app/controllers/projects/service_desk_controller.rb45
-rw-r--r--app/controllers/projects/services_controller.rb9
-rw-r--r--app/controllers/projects/settings/operations_controller.rb29
-rw-r--r--app/controllers/projects/snippets/blobs_controller.rb5
-rw-r--r--app/controllers/projects/snippets_controller.rb6
-rw-r--r--app/controllers/projects/stages_controller.rb25
-rw-r--r--app/controllers/projects/static_site_editor_controller.rb3
-rw-r--r--app/controllers/projects/tree_controller.rb18
-rw-r--r--app/controllers/projects/variables_controller.rb4
-rw-r--r--app/controllers/projects/wikis_controller.rb1
-rw-r--r--app/controllers/projects_controller.rb9
-rw-r--r--app/controllers/registrations/experience_levels_controller.rb9
-rw-r--r--app/controllers/registrations_controller.rb8
-rw-r--r--app/controllers/root_controller.rb5
-rw-r--r--app/controllers/search_controller.rb15
-rw-r--r--app/controllers/snippets/blobs_controller.rb7
-rw-r--r--app/controllers/snippets_controller.rb2
-rw-r--r--app/controllers/users_controller.rb7
101 files changed, 1164 insertions, 483 deletions
diff --git a/app/controllers/admin/application_settings_controller.rb b/app/controllers/admin/application_settings_controller.rb
index 94c82c25357..41a6616d10c 100644
--- a/app/controllers/admin/application_settings_controller.rb
+++ b/app/controllers/admin/application_settings_controller.rb
@@ -227,6 +227,7 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController
:raw_blob_request_limit,
:namespace_storage_size_limit,
:issues_create_limit,
+ :default_branch_name,
disabled_oauth_sign_in_sources: [],
import_sources: [],
repository_storages: [],
diff --git a/app/controllers/admin/clusters_controller.rb b/app/controllers/admin/clusters_controller.rb
index 5b1902fad51..9a642e53d86 100644
--- a/app/controllers/admin/clusters_controller.rb
+++ b/app/controllers/admin/clusters_controller.rb
@@ -10,6 +10,11 @@ class Admin::ClustersController < Clusters::ClustersController
def clusterable
@clusterable ||= InstanceClusterablePresenter.fabricate(Clusters::Instance.new, current_user: current_user)
end
-end
-Admin::ClustersController.prepend_if_ee('EE::Admin::ClustersController')
+ def metrics_dashboard_params
+ {
+ cluster: cluster,
+ cluster_type: :admin
+ }
+ end
+end
diff --git a/app/controllers/admin/jobs_controller.rb b/app/controllers/admin/jobs_controller.rb
index a3a18a115e9..7b50a45a9cd 100644
--- a/app/controllers/admin/jobs_controller.rb
+++ b/app/controllers/admin/jobs_controller.rb
@@ -1,6 +1,8 @@
# frozen_string_literal: true
class Admin::JobsController < Admin::ApplicationController
+ BUILDS_PER_PAGE = 30
+
def index
# We need all builds for tabs counters
@all_builds = Ci::JobsFinder.new(current_user: current_user).execute
@@ -8,7 +10,7 @@ class Admin::JobsController < Admin::ApplicationController
@scope = params[:scope]
@builds = Ci::JobsFinder.new(current_user: current_user, params: params).execute
@builds = @builds.eager_load_everything
- @builds = @builds.page(params[:page]).per(30)
+ @builds = @builds.page(params[:page]).per(BUILDS_PER_PAGE).without_count
end
def cancel_all
diff --git a/app/controllers/admin/services_controller.rb b/app/controllers/admin/services_controller.rb
index 08ef992e604..e0137accd2d 100644
--- a/app/controllers/admin/services_controller.rb
+++ b/app/controllers/admin/services_controller.rb
@@ -4,13 +4,18 @@ class Admin::ServicesController < Admin::ApplicationController
include ServiceParams
before_action :service, only: [:edit, :update]
+ before_action :whitelist_query_limiting, only: [:index]
+ before_action only: :edit do
+ push_frontend_feature_flag(:integration_form_refactor, default_enabled: true)
+ end
def index
@services = Service.find_or_create_templates.sort_by(&:title)
+ @existing_instance_types = Service.instances.pluck(:type) # rubocop: disable CodeReuse/ActiveRecord
end
def edit
- unless service.present?
+ if service.nil? || Service.instance_exists_for?(service.type)
redirect_to admin_application_settings_services_path,
alert: "Service is unknown or it doesn't exist"
end
@@ -34,4 +39,8 @@ class Admin::ServicesController < Admin::ApplicationController
@service ||= Service.find_by(id: params[:id], template: true)
end
# rubocop: enable CodeReuse/ActiveRecord
+
+ def whitelist_query_limiting
+ Gitlab::QueryLimiting.whitelist('https://gitlab.com/gitlab-org/gitlab/-/issues/220357')
+ end
end
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index 79a164a5574..2595b646964 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -22,6 +22,7 @@ class ApplicationController < ActionController::Base
include Impersonation
include Gitlab::Logging::CloudflareHelper
include Gitlab::Utils::StrongMemoize
+ include ControllerWithFeatureCategory
before_action :authenticate_user!, except: [:route_not_found]
before_action :enforce_terms!, if: :should_enforce_terms?
@@ -305,7 +306,7 @@ class ApplicationController < ActionController::Base
return if session[:impersonator_id] || !current_user&.allow_password_authentication?
if current_user&.password_expired?
- return redirect_to new_profile_password_path
+ redirect_to new_profile_password_path
end
end
@@ -329,13 +330,6 @@ class ApplicationController < ActionController::Base
end
end
- def event_filter
- @event_filter ||=
- EventFilter.new(params[:event_filter].presence || cookies[:event_filter]).tap do |new_event_filter|
- cookies[:event_filter] = new_event_filter.filter
- end
- end
-
# JSON for infinite scroll via Pager object
def pager_json(partial, count, locals = {})
html = render_to_string(
@@ -370,7 +364,7 @@ class ApplicationController < ActionController::Base
def require_email
if current_user && current_user.temp_oauth_email? && session[:impersonator_id].nil?
- return redirect_to profile_path, notice: _('Please complete your profile with email address')
+ redirect_to profile_path, notice: _('Please complete your profile with email address')
end
end
diff --git a/app/controllers/autocomplete_controller.rb b/app/controllers/autocomplete_controller.rb
index 0df201ab506..99fa17e202a 100644
--- a/app/controllers/autocomplete_controller.rb
+++ b/app/controllers/autocomplete_controller.rb
@@ -4,10 +4,6 @@ class AutocompleteController < ApplicationController
skip_before_action :authenticate_user!, only: [:users, :award_emojis, :merge_request_target_branches]
def users
- project = Autocomplete::ProjectFinder
- .new(current_user, params)
- .execute
-
group = Autocomplete::GroupFinder
.new(current_user, project, params)
.execute
@@ -50,8 +46,20 @@ class AutocompleteController < ApplicationController
end
end
+ def deploy_keys_with_owners
+ deploy_keys = DeployKeys::CollectKeysService.new(project, current_user).execute
+
+ render json: DeployKeySerializer.new.represent(deploy_keys, { with_owner: true, user: current_user })
+ end
+
private
+ def project
+ @project ||= Autocomplete::ProjectFinder
+ .new(current_user, params)
+ .execute
+ end
+
def target_branch_params
params.permit(:group_id, :project_id).select { |_, v| v.present? }
end
diff --git a/app/controllers/chaos_controller.rb b/app/controllers/chaos_controller.rb
index ac008165c16..e0d1f313fc7 100644
--- a/app/controllers/chaos_controller.rb
+++ b/app/controllers/chaos_controller.rb
@@ -45,7 +45,6 @@ class ChaosController < ActionController::Base
unless Devise.secure_compare(chaos_secret_configured, chaos_secret_request)
render plain: "To experience chaos, please set a valid `X-Chaos-Secret` header or `token` param",
status: :unauthorized
- return
end
end
diff --git a/app/controllers/clusters/clusters_controller.rb b/app/controllers/clusters/clusters_controller.rb
index 46dec5f3287..2e8b3d764ca 100644
--- a/app/controllers/clusters/clusters_controller.rb
+++ b/app/controllers/clusters/clusters_controller.rb
@@ -2,6 +2,8 @@
class Clusters::ClustersController < Clusters::BaseController
include RoutableActions
+ include Metrics::Dashboard::PrometheusApiProxy
+ include MetricsDashboard
before_action :cluster, only: [:cluster_status, :show, :update, :destroy, :clear_cache]
before_action :generate_gcp_authorize_url, only: [:new]
@@ -290,6 +292,29 @@ class Clusters::ClustersController < Clusters::BaseController
@gcp_cluster = cluster.present(current_user: current_user)
end
+ def proxyable
+ cluster.cluster
+ end
+
+ # During first iteration of dashboard variables implementation
+ # cluster health case was omitted. Existing service for now is tied to
+ # environment, which is not always present for cluster health dashboard.
+ # It is planned to break coupling to environment https://gitlab.com/gitlab-org/gitlab/-/issues/213833.
+ # It is also planned to move cluster health to metrics dashboard section https://gitlab.com/gitlab-org/gitlab/-/issues/220214
+ # but for now I've used dummy class to stub variable substitution service, as there are no variables
+ # in cluster health dashboard
+ def proxy_variable_substitution_service
+ @empty_service ||= Class.new(BaseService) do
+ def initialize(proxyable, params)
+ @proxyable, @params = proxyable, params
+ end
+
+ def execute
+ success(params: @params)
+ end
+ end
+ end
+
def user_cluster
cluster = Clusters::BuildService.new(clusterable.subject).execute
cluster.build_platform_kubernetes
diff --git a/app/controllers/concerns/controller_with_feature_category.rb b/app/controllers/concerns/controller_with_feature_category.rb
new file mode 100644
index 00000000000..f8985cf0950
--- /dev/null
+++ b/app/controllers/concerns/controller_with_feature_category.rb
@@ -0,0 +1,45 @@
+# frozen_string_literal: true
+
+module ControllerWithFeatureCategory
+ extend ActiveSupport::Concern
+ include Gitlab::ClassAttributes
+
+ class_methods do
+ def feature_category(category, config = {})
+ validate_config!(config)
+
+ category_config = Config.new(category, config[:only], config[:except], config[:if], config[:unless])
+ # Add the config to the beginning. That way, the last defined one takes precedence.
+ feature_category_configuration.unshift(category_config)
+ end
+
+ def feature_category_for_action(action)
+ category_config = feature_category_configuration.find { |config| config.matches?(action) }
+
+ category_config&.category || superclass_feature_category_for_action(action)
+ end
+
+ private
+
+ def validate_config!(config)
+ invalid_keys = config.keys - [:only, :except, :if, :unless]
+ if invalid_keys.any?
+ raise ArgumentError, "unknown arguments: #{invalid_keys} "
+ end
+
+ if config.key?(:only) && config.key?(:except)
+ raise ArgumentError, "cannot configure both `only` and `except`"
+ end
+ end
+
+ def feature_category_configuration
+ class_attributes[:feature_category_config] ||= []
+ end
+
+ def superclass_feature_category_for_action(action)
+ return unless superclass.respond_to?(:feature_category_for_action)
+
+ superclass.feature_category_for_action(action)
+ end
+ end
+end
diff --git a/app/controllers/concerns/controller_with_feature_category/config.rb b/app/controllers/concerns/controller_with_feature_category/config.rb
new file mode 100644
index 00000000000..624691ee4f6
--- /dev/null
+++ b/app/controllers/concerns/controller_with_feature_category/config.rb
@@ -0,0 +1,38 @@
+# frozen_string_literal: true
+
+module ControllerWithFeatureCategory
+ class Config
+ attr_reader :category
+
+ def initialize(category, only, except, if_proc, unless_proc)
+ @category = category.to_sym
+ @only, @except = only&.map(&:to_s), except&.map(&:to_s)
+ @if_proc, @unless_proc = if_proc, unless_proc
+ end
+
+ def matches?(action)
+ included?(action) && !excluded?(action) &&
+ if_proc?(action) && !unless_proc?(action)
+ end
+
+ private
+
+ attr_reader :only, :except, :if_proc, :unless_proc
+
+ def if_proc?(action)
+ if_proc.nil? || if_proc.call(action)
+ end
+
+ def unless_proc?(action)
+ unless_proc.present? && unless_proc.call(action)
+ end
+
+ def included?(action)
+ only.nil? || only.include?(action)
+ end
+
+ def excluded?(action)
+ except.present? && except.include?(action)
+ end
+ end
+end
diff --git a/app/controllers/concerns/filters_events.rb b/app/controllers/concerns/filters_events.rb
new file mode 100644
index 00000000000..c82d0318fd3
--- /dev/null
+++ b/app/controllers/concerns/filters_events.rb
@@ -0,0 +1,14 @@
+# frozen_string_literal: true
+
+module FiltersEvents
+ def event_filter
+ @event_filter ||= new_event_filter.tap { |ef| cookies[:event_filter] = ef.filter }
+ end
+
+ private
+
+ def new_event_filter
+ active_filter = params[:event_filter].presence || cookies[:event_filter]
+ EventFilter.new(active_filter)
+ end
+end
diff --git a/app/controllers/concerns/integrations_actions.rb b/app/controllers/concerns/integrations_actions.rb
index cc9db7936e8..46febc44807 100644
--- a/app/controllers/concerns/integrations_actions.rb
+++ b/app/controllers/concerns/integrations_actions.rb
@@ -8,6 +8,9 @@ module IntegrationsActions
before_action :not_found, unless: :integrations_enabled?
before_action :integration, only: [:edit, :update, :test]
+ before_action only: :edit do
+ push_frontend_feature_flag(:integration_form_refactor, default_enabled: true)
+ end
end
def edit
@@ -51,9 +54,8 @@ module IntegrationsActions
end
def integration
- # Using instance variable `@service` still required as it's used in ServiceParams
- # and app/views/shared/_service_settings.html.haml. Should be removed once
- # those 2 are refactored to use `@integration`.
+ # Using instance variable `@service` still required as it's used in ServiceParams.
+ # Should be removed once that is refactored to use `@integration`.
@integration = @service ||= find_or_initialize_integration(params[:id]) # rubocop:disable Gitlab/ModuleWithInstanceVariables
end
diff --git a/app/controllers/concerns/issuable_actions.rb b/app/controllers/concerns/issuable_actions.rb
index 98fa8202e25..c4dbce00593 100644
--- a/app/controllers/concerns/issuable_actions.rb
+++ b/app/controllers/concerns/issuable_actions.rb
@@ -110,9 +110,13 @@ module IssuableActions
def bulk_update
result = Issuable::BulkUpdateService.new(parent, current_user, bulk_update_params).execute(resource_name)
- quantity = result[:count]
- render json: { notice: "#{quantity} #{resource_name.pluralize(quantity)} updated" }
+ if result.success?
+ quantity = result.payload[:count]
+ render json: { notice: "#{quantity} #{resource_name.pluralize(quantity)} updated" }
+ elsif result.error?
+ render json: { errors: result.message }, status: result.http_status
+ end
end
# rubocop:disable CodeReuse/ActiveRecord
@@ -193,13 +197,13 @@ module IssuableActions
def authorize_destroy_issuable!
unless can?(current_user, :"destroy_#{issuable.to_ability_name}", issuable)
- return access_denied!
+ access_denied!
end
end
def authorize_admin_issuable!
unless can?(current_user, :"admin_#{resource_name}", parent)
- return access_denied!
+ access_denied!
end
end
diff --git a/app/controllers/concerns/issuable_collections.rb b/app/controllers/concerns/issuable_collections.rb
index 9ef067e8797..4f61e5ed711 100644
--- a/app/controllers/concerns/issuable_collections.rb
+++ b/app/controllers/concerns/issuable_collections.rb
@@ -81,34 +81,36 @@ module IssuableCollections
# rubocop:disable Gitlab/ModuleWithInstanceVariables
def finder_options
- params[:state] = default_state if params[:state].blank?
-
- options = {
- scope: params[:scope],
- state: params[:state],
- confidential: Gitlab::Utils.to_boolean(params[:confidential]),
- sort: set_sort_order
- }
-
- # Used by view to highlight active option
- @sort = options[:sort]
-
- # When a user looks for an exact iid, we do not filter by search but only by iid
- if params[:search] =~ /^#(?<iid>\d+)\z/
- options[:iids] = Regexp.last_match[:iid]
- params[:search] = nil
+ strong_memoize(:finder_options) do
+ params[:state] = default_state if params[:state].blank?
+
+ options = {
+ scope: params[:scope],
+ state: params[:state],
+ confidential: Gitlab::Utils.to_boolean(params[:confidential]),
+ sort: set_sort_order
+ }
+
+ # Used by view to highlight active option
+ @sort = options[:sort]
+
+ # When a user looks for an exact iid, we do not filter by search but only by iid
+ if params[:search] =~ /^#(?<iid>\d+)\z/
+ options[:iids] = Regexp.last_match[:iid]
+ params[:search] = nil
+ end
+
+ if @project
+ options[:project_id] = @project.id
+ options[:attempt_project_search_optimizations] = true
+ elsif @group
+ options[:group_id] = @group.id
+ options[:include_subgroups] = true
+ options[:attempt_group_search_optimizations] = true
+ end
+
+ params.permit(finder_type.valid_params).merge(options)
end
-
- if @project
- options[:project_id] = @project.id
- options[:attempt_project_search_optimizations] = true
- elsif @group
- options[:group_id] = @group.id
- options[:include_subgroups] = true
- options[:attempt_group_search_optimizations] = true
- end
-
- params.permit(finder_type.valid_params).merge(options)
end
# rubocop:enable Gitlab/ModuleWithInstanceVariables
@@ -147,7 +149,10 @@ module IssuableCollections
when 'Issue'
common_attributes + [:project, project: :namespace]
when 'MergeRequest'
- common_attributes + [:target_project, :latest_merge_request_diff, source_project: :route, head_pipeline: :project, target_project: :namespace]
+ common_attributes + [
+ :target_project, :latest_merge_request_diff, :approvals, :approved_by_users,
+ source_project: :route, head_pipeline: :project, target_project: :namespace
+ ]
end
end
# rubocop:enable Gitlab/ModuleWithInstanceVariables
diff --git a/app/controllers/concerns/known_sign_in.rb b/app/controllers/concerns/known_sign_in.rb
index c0b9605de58..cacc7e4628f 100644
--- a/app/controllers/concerns/known_sign_in.rb
+++ b/app/controllers/concerns/known_sign_in.rb
@@ -2,19 +2,34 @@
module KnownSignIn
include Gitlab::Utils::StrongMemoize
+ include CookiesHelper
+
+ KNOWN_SIGN_IN_COOKIE = :known_sign_in
+ KNOWN_SIGN_IN_COOKIE_EXPIRY = 14.days
private
def verify_known_sign_in
- return unless current_user
+ return unless Gitlab::CurrentSettings.notify_on_unknown_sign_in? && current_user
+
+ notify_user unless known_device? || known_remote_ip?
- notify_user unless known_remote_ip?
+ update_cookie
end
def known_remote_ip?
known_ip_addresses.include?(request.remote_ip)
end
+ def known_device?
+ cookies.encrypted[KNOWN_SIGN_IN_COOKIE] == current_user.id
+ end
+
+ def update_cookie
+ set_secure_cookie(KNOWN_SIGN_IN_COOKIE, current_user.id,
+ type: COOKIE_TYPE_ENCRYPTED, httponly: true, expires: KNOWN_SIGN_IN_COOKIE_EXPIRY)
+ end
+
def sessions
strong_memoize(:session) do
ActiveSession.list(current_user).reject(&:is_impersonated)
diff --git a/app/controllers/concerns/membership_actions.rb b/app/controllers/concerns/membership_actions.rb
index 4ab02005b45..8c7f156f7f8 100644
--- a/app/controllers/concerns/membership_actions.rb
+++ b/app/controllers/concerns/membership_actions.rb
@@ -31,7 +31,10 @@ module MembershipActions
def destroy
member = membershipable.members_and_requesters.find(params[:id])
- Members::DestroyService.new(current_user).execute(member)
+ # !! is used in case unassign_issuables contains empty string which would result in nil
+ unassign_issuables = !!ActiveRecord::Type::Boolean.new.cast(params.delete(:unassign_issuables))
+
+ Members::DestroyService.new(current_user).execute(member, unassign_issuables: unassign_issuables)
respond_to do |format|
format.html do
diff --git a/app/controllers/concerns/metrics/dashboard/prometheus_api_proxy.rb b/app/controllers/concerns/metrics/dashboard/prometheus_api_proxy.rb
new file mode 100644
index 00000000000..e0e3f628cc5
--- /dev/null
+++ b/app/controllers/concerns/metrics/dashboard/prometheus_api_proxy.rb
@@ -0,0 +1,53 @@
+# frozen_string_literal: true
+
+module Metrics::Dashboard::PrometheusApiProxy
+ extend ActiveSupport::Concern
+ include RenderServiceResults
+
+ included do
+ before_action :authorize_read_prometheus!, only: [:prometheus_proxy]
+ end
+
+ def prometheus_proxy
+ variable_substitution_result =
+ proxy_variable_substitution_service.new(proxyable, permit_params).execute
+
+ if variable_substitution_result[:status] == :error
+ return error_response(variable_substitution_result)
+ end
+
+ prometheus_result = Prometheus::ProxyService.new(
+ proxyable,
+ proxy_method,
+ proxy_path,
+ variable_substitution_result[:params]
+ ).execute
+
+ return continue_polling_response if prometheus_result.nil?
+ return error_response(prometheus_result) if prometheus_result[:status] == :error
+
+ success_response(prometheus_result)
+ end
+
+ private
+
+ def proxyable
+ raise NotImplementedError, "#{self.class} must implement method: #{__callee__}"
+ end
+
+ def proxy_variable_substitution_service
+ raise NotImplementedError, "#{self.class} must implement method: #{__callee__}"
+ end
+
+ def permit_params
+ params.permit!
+ end
+
+ def proxy_method
+ request.method
+ end
+
+ def proxy_path
+ params[:proxy_path]
+ end
+end
diff --git a/app/controllers/concerns/metrics_dashboard.rb b/app/controllers/concerns/metrics_dashboard.rb
index 1aea0e294a5..28d0692d748 100644
--- a/app/controllers/concerns/metrics_dashboard.rb
+++ b/app/controllers/concerns/metrics_dashboard.rb
@@ -13,7 +13,7 @@ module MetricsDashboard
result = dashboard_finder.find(
project_for_dashboard,
current_user,
- metrics_dashboard_params.to_h.symbolize_keys
+ decoded_params
)
if result
@@ -41,7 +41,7 @@ module MetricsDashboard
end
def amend_dashboard(dashboard)
- project_dashboard = project_for_dashboard && !dashboard[:system_dashboard]
+ project_dashboard = project_for_dashboard && !dashboard[:out_of_the_box_dashboard]
dashboard[:can_edit] = project_dashboard ? can_edit?(dashboard) : false
dashboard[:project_blob_path] = project_dashboard ? dashboard_project_blob_path(dashboard) : nil
@@ -114,4 +114,14 @@ module MetricsDashboard
json: result.slice(:all_dashboards, :message, :status)
}
end
+
+ def decoded_params
+ params = metrics_dashboard_params
+
+ if params[:dashboard_path]
+ params[:dashboard_path] = CGI.unescape(params[:dashboard_path])
+ end
+
+ params
+ end
end
diff --git a/app/controllers/concerns/notes_actions.rb b/app/controllers/concerns/notes_actions.rb
index d3dfb1813e4..f4fc7decb60 100644
--- a/app/controllers/concerns/notes_actions.rb
+++ b/app/controllers/concerns/notes_actions.rb
@@ -5,6 +5,11 @@ module NotesActions
include Gitlab::Utils::StrongMemoize
extend ActiveSupport::Concern
+ # last_fetched_at is an integer number of microseconds, which is the same
+ # precision as PostgreSQL "timestamp" fields. It's important for them to have
+ # identical precision for accurate pagination
+ MICROSECOND = 1_000_000
+
included do
before_action :set_polling_interval_header, only: [:index]
before_action :require_noteable!, only: [:index, :create]
@@ -13,30 +18,20 @@ module NotesActions
end
def index
- notes_json = { notes: [], last_fetched_at: Time.current.to_i }
-
- notes = notes_finder
- .execute
- .inc_relations_for_view
-
- if notes_filter != UserPreference::NOTES_FILTERS[:only_comments]
- notes =
- ResourceEvents::MergeIntoNotesService
- .new(noteable, current_user, last_fetched_at: last_fetched_at)
- .execute(notes)
- end
-
+ notes, meta = gather_notes
notes = prepare_notes_for_rendering(notes)
notes = notes.select { |n| n.readable_by?(current_user) }
-
- notes_json[:notes] =
+ notes =
if use_note_serializer?
note_serializer.represent(notes)
else
notes.map { |note| note_json(note) }
end
- render json: notes_json
+ # We know there's more data, so tell the frontend to poll again after 1ms
+ set_polling_interval_header(interval: 1) if meta[:more]
+
+ render json: meta.merge(notes: notes)
end
# rubocop:disable Gitlab/ModuleWithInstanceVariables
@@ -101,6 +96,48 @@ module NotesActions
private
+ # Lower bound (last_fetched_at as specified in the request) is already set in
+ # the finder. Here, we select between returning all notes since then, or a
+ # page's worth of notes.
+ def gather_notes
+ if Feature.enabled?(:paginated_notes, project)
+ gather_some_notes
+ else
+ gather_all_notes
+ end
+ end
+
+ def gather_all_notes
+ now = Time.current
+ notes = merge_resource_events(notes_finder.execute.inc_relations_for_view)
+
+ [notes, { last_fetched_at: (now.to_i * MICROSECOND) + now.usec }]
+ end
+
+ def gather_some_notes
+ paginator = Gitlab::UpdatedNotesPaginator.new(
+ notes_finder.execute.inc_relations_for_view,
+ last_fetched_at: last_fetched_at
+ )
+
+ notes = paginator.notes
+
+ # Fetch all the synthetic notes in the same time range as the real notes.
+ # Although we don't limit the number, their text is under our control so
+ # should be fairly cheap to process.
+ notes = merge_resource_events(notes, fetch_until: paginator.next_fetched_at)
+
+ [notes, paginator.metadata]
+ end
+
+ def merge_resource_events(notes, fetch_until: nil)
+ return notes if notes_filter == UserPreference::NOTES_FILTERS[:only_comments]
+
+ ResourceEvents::MergeIntoNotesService
+ .new(noteable, current_user, last_fetched_at: last_fetched_at, fetch_until: fetch_until)
+ .execute(notes)
+ end
+
def note_html(note)
render_to_string(
"shared/notes/_note",
@@ -226,11 +263,11 @@ module NotesActions
end
def update_note_params
- params.require(:note).permit(:note)
+ params.require(:note).permit(:note, :position)
end
- def set_polling_interval_header
- Gitlab::PollingInterval.set_header(response, interval: 6_000)
+ def set_polling_interval_header(interval: 6000)
+ Gitlab::PollingInterval.set_header(response, interval: interval)
end
def noteable
@@ -242,7 +279,14 @@ module NotesActions
end
def last_fetched_at
- request.headers['X-Last-Fetched-At']
+ strong_memoize(:last_fetched_at) do
+ microseconds = request.headers['X-Last-Fetched-At'].to_i
+
+ seconds = microseconds / MICROSECOND
+ frac = microseconds % MICROSECOND
+
+ Time.zone.at(seconds, frac)
+ end
end
def notes_filter
diff --git a/app/controllers/concerns/renders_member_access.rb b/app/controllers/concerns/renders_member_access.rb
index 955ac1a1bc8..745830181c1 100644
--- a/app/controllers/concerns/renders_member_access.rb
+++ b/app/controllers/concerns/renders_member_access.rb
@@ -7,12 +7,6 @@ module RendersMemberAccess
groups
end
- def prepare_projects_for_rendering(projects)
- preload_max_member_access_for_collection(Project, projects)
-
- projects
- end
-
private
# rubocop: disable CodeReuse/ActiveRecord
diff --git a/app/controllers/concerns/renders_projects_list.rb b/app/controllers/concerns/renders_projects_list.rb
new file mode 100644
index 00000000000..be45c676ad6
--- /dev/null
+++ b/app/controllers/concerns/renders_projects_list.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: true
+
+module RendersProjectsList
+ def prepare_projects_for_rendering(projects)
+ preload_max_member_access_for_collection(Project, projects)
+
+ # Call the forks count method on every project, so the BatchLoader would load them all at
+ # once when the entities are rendered
+ projects.each(&:forks_count)
+
+ projects
+ end
+end
diff --git a/app/controllers/concerns/service_params.rb b/app/controllers/concerns/service_params.rb
index e78fa8f8250..a19c43a227a 100644
--- a/app/controllers/concerns/service_params.rb
+++ b/app/controllers/concerns/service_params.rb
@@ -22,8 +22,8 @@ module ServiceParams
:comment_on_event_enabled,
:comment_detail,
:confidential_issues_events,
+ :confluence_url,
:default_irc_uri,
- :description,
:device,
:disable_diffs,
:drone_url,
@@ -31,6 +31,7 @@ module ServiceParams
:external_wiki_url,
:google_iap_service_account_json,
:google_iap_audience_client_id,
+ :inherit_from_id,
# We're using `issues_events` and `merge_requests_events`
# in the view so we still need to explicitly state them
# here. `Service#event_names` would only give
@@ -61,7 +62,6 @@ module ServiceParams
:sound,
:subdomain,
:teamcity_url,
- :title,
:token,
:type,
:url,
diff --git a/app/controllers/concerns/snippets/blobs_actions.rb b/app/controllers/concerns/snippets/blobs_actions.rb
new file mode 100644
index 00000000000..db56ce8f193
--- /dev/null
+++ b/app/controllers/concerns/snippets/blobs_actions.rb
@@ -0,0 +1,53 @@
+# frozen_string_literal: true
+
+module Snippets::BlobsActions
+ extend ActiveSupport::Concern
+
+ include Gitlab::Utils::StrongMemoize
+ include ExtractsRef
+ include Snippets::SendBlob
+
+ included do
+ before_action :authorize_read_snippet!, only: [:raw]
+ before_action :ensure_repository
+ before_action :ensure_blob
+ end
+
+ def raw
+ send_snippet_blob(snippet, blob)
+ end
+
+ private
+
+ def repository_container
+ snippet
+ end
+
+ # rubocop:disable Gitlab/ModuleWithInstanceVariables
+ def blob
+ strong_memoize(:blob) do
+ assign_ref_vars
+
+ next unless @commit
+
+ @repo.blob_at(@commit.id, @path)
+ end
+ end
+ # rubocop:enable Gitlab/ModuleWithInstanceVariables
+
+ def ensure_blob
+ render_404 unless blob
+ end
+
+ def ensure_repository
+ unless snippet.repo_exists?
+ Gitlab::AppLogger.error(message: "Snippet raw blob attempt with no repo", snippet: snippet.id)
+
+ respond_422
+ end
+ end
+
+ def snippet_id
+ params[:snippet_id]
+ end
+end
diff --git a/app/controllers/concerns/snippets/send_blob.rb b/app/controllers/concerns/snippets/send_blob.rb
new file mode 100644
index 00000000000..4f432430aaa
--- /dev/null
+++ b/app/controllers/concerns/snippets/send_blob.rb
@@ -0,0 +1,22 @@
+# frozen_string_literal: true
+
+module Snippets::SendBlob
+ include SendsBlob
+
+ def send_snippet_blob(snippet, blob)
+ workhorse_set_content_type!
+
+ send_blob(
+ snippet.repository,
+ blob,
+ inline: content_disposition == 'inline',
+ allow_caching: snippet.public?
+ )
+ end
+
+ private
+
+ def content_disposition
+ @disposition ||= params[:inline] == 'false' ? 'attachment' : 'inline'
+ end
+end
diff --git a/app/controllers/concerns/snippets_actions.rb b/app/controllers/concerns/snippets_actions.rb
index 51fc12398d9..048b18c5c61 100644
--- a/app/controllers/concerns/snippets_actions.rb
+++ b/app/controllers/concerns/snippets_actions.rb
@@ -2,11 +2,13 @@
module SnippetsActions
extend ActiveSupport::Concern
- include SendsBlob
+
include RendersNotes
include RendersBlob
include PaginatedCollection
include Gitlab::NoteableMetadata
+ include Snippets::SendBlob
+ include SnippetsSort
included do
skip_before_action :verify_authenticity_token,
@@ -25,6 +27,10 @@ module SnippetsActions
render 'edit'
end
+ # This endpoint is being replaced by Snippets::BlobController#raw
+ # Support for old raw links will be maintainted via this action but
+ # it will only return the first blob found,
+ # see: https://gitlab.com/gitlab-org/gitlab/-/issues/217775
def raw
workhorse_set_content_type!
@@ -39,12 +45,7 @@ module SnippetsActions
filename: Snippet.sanitized_file_name(blob.name)
)
else
- send_blob(
- snippet.repository,
- blob,
- inline: content_disposition == 'inline',
- allow_caching: snippet.public?
- )
+ send_snippet_blob(snippet, blob)
end
end
@@ -106,10 +107,6 @@ module SnippetsActions
private
- def content_disposition
- @disposition ||= params[:inline] == 'false' ? 'attachment' : 'inline'
- end
-
# rubocop:disable Gitlab/ModuleWithInstanceVariables
def blob
return unless snippet
diff --git a/app/controllers/concerns/snippets_sort.rb b/app/controllers/concerns/snippets_sort.rb
new file mode 100644
index 00000000000..f122c843af7
--- /dev/null
+++ b/app/controllers/concerns/snippets_sort.rb
@@ -0,0 +1,9 @@
+# frozen_string_literal: true
+
+module SnippetsSort
+ extend ActiveSupport::Concern
+
+ def sort_param
+ params[:sort].presence || 'updated_desc'
+ end
+end
diff --git a/app/controllers/concerns/wiki_actions.rb b/app/controllers/concerns/wiki_actions.rb
index 7eef12fadfe..a5182000f5b 100644
--- a/app/controllers/concerns/wiki_actions.rb
+++ b/app/controllers/concerns/wiki_actions.rb
@@ -1,6 +1,8 @@
# frozen_string_literal: true
module WikiActions
+ include DiffHelper
+ include PreviewMarkdown
include SendsBlob
include Gitlab::Utils::StrongMemoize
extend ActiveSupport::Concern
@@ -11,16 +13,23 @@ module WikiActions
before_action :authorize_admin_wiki!, only: :destroy
before_action :wiki
- before_action :page, only: [:show, :edit, :update, :history, :destroy]
+ before_action :page, only: [:show, :edit, :update, :history, :destroy, :diff]
before_action :load_sidebar, except: [:pages]
+ before_action :set_content_class
before_action only: [:show, :edit, :update] do
@valid_encoding = valid_encoding?
end
before_action only: [:edit, :update], unless: :valid_encoding? do
- redirect_to wiki_page_path(wiki, page)
+ if params[:id].present?
+ redirect_to wiki_page_path(wiki, page || params[:id])
+ else
+ redirect_to wiki_path(wiki)
+ end
end
+
+ helper_method :view_file_button, :diff_file_html_data
end
def new
@@ -133,6 +142,19 @@ module WikiActions
# rubocop:enable Gitlab/ModuleWithInstanceVariables
# rubocop:disable Gitlab/ModuleWithInstanceVariables
+ def diff
+ return render_404 unless page
+
+ apply_diff_view_cookie!
+
+ @diffs = page.diffs(diff_options)
+ @diff_notes_disabled = true
+
+ render 'shared/wikis/diff'
+ end
+ # rubocop:disable Gitlab/ModuleWithInstanceVariables
+
+ # rubocop:disable Gitlab/ModuleWithInstanceVariables
def destroy
WikiPages::DestroyService.new(container: container, current_user: current_user).execute(page)
@@ -203,7 +225,7 @@ module WikiActions
def page_params
keys = [:id]
- keys << :version_id if params[:action] == 'show'
+ keys << :version_id if %w[show diff].include?(params[:action])
params.values_at(*keys)
end
@@ -229,4 +251,25 @@ module WikiActions
wiki.repository.blob_at(commit.id, params[:id])
end
end
+
+ def set_content_class
+ @content_class = 'limit-container-width' unless fluid_layout # rubocop:disable Gitlab/ModuleWithInstanceVariables
+ end
+
+ # Override CommitsHelper#view_file_button
+ def view_file_button(commit_sha, *args)
+ path = wiki_page_path(wiki, page, version_id: page.version.id)
+
+ helpers.link_to(path, class: 'btn') do
+ helpers.raw(_('View page @ ')) + helpers.content_tag(:span, Commit.truncate_sha(commit_sha), class: 'commit-sha')
+ end
+ end
+
+ # Override DiffHelper#diff_file_html_data
+ def diff_file_html_data(_project, _diff_file_path, diff_commit_id)
+ {
+ blob_diff_path: wiki_page_path(wiki, page, action: :diff, version_id: diff_commit_id),
+ view: diff_view
+ }
+ end
end
diff --git a/app/controllers/dashboard/projects_controller.rb b/app/controllers/dashboard/projects_controller.rb
index 25c48fadf49..ad64b6c4f94 100644
--- a/app/controllers/dashboard/projects_controller.rb
+++ b/app/controllers/dashboard/projects_controller.rb
@@ -3,9 +3,10 @@
class Dashboard::ProjectsController < Dashboard::ApplicationController
include ParamsBackwardCompatibility
include RendersMemberAccess
- include OnboardingExperimentHelper
+ include RendersProjectsList
include SortingHelper
include SortingPreference
+ include FiltersEvents
prepend_before_action(only: [:index]) { authenticate_sessionless_user!(:rss) }
before_action :set_non_archived_param
diff --git a/app/controllers/dashboard/snippets_controller.rb b/app/controllers/dashboard/snippets_controller.rb
index aa09fcdbe61..a8ca3dbd0e7 100644
--- a/app/controllers/dashboard/snippets_controller.rb
+++ b/app/controllers/dashboard/snippets_controller.rb
@@ -3,6 +3,7 @@
class Dashboard::SnippetsController < Dashboard::ApplicationController
include PaginatedCollection
include Gitlab::NoteableMetadata
+ include SnippetsSort
skip_cross_project_access_check :index
@@ -11,7 +12,7 @@ class Dashboard::SnippetsController < Dashboard::ApplicationController
.new(current_user, author: current_user)
.execute
- @snippets = SnippetsFinder.new(current_user, author: current_user, scope: params[:scope])
+ @snippets = SnippetsFinder.new(current_user, author: current_user, scope: params[:scope], sort: sort_param)
.execute
.page(params[:page])
.inc_author
diff --git a/app/controllers/dashboard/todos_controller.rb b/app/controllers/dashboard/todos_controller.rb
index 8a8064b24c2..db40b0bed77 100644
--- a/app/controllers/dashboard/todos_controller.rb
+++ b/app/controllers/dashboard/todos_controller.rb
@@ -3,11 +3,14 @@
class Dashboard::TodosController < Dashboard::ApplicationController
include ActionView::Helpers::NumberHelper
include PaginatedCollection
+ include Analytics::UniqueVisitsHelper
before_action :authorize_read_project!, only: :index
before_action :authorize_read_group!, only: :index
before_action :find_todos, only: [:index, :destroy_all]
+ track_unique_visits :index, target_id: 'u_analytics_todos'
+
def index
@sort = params[:sort]
@todos = @todos.page(params[:page])
diff --git a/app/controllers/dashboard_controller.rb b/app/controllers/dashboard_controller.rb
index dd9e6488bc5..07cc31fb7d3 100644
--- a/app/controllers/dashboard_controller.rb
+++ b/app/controllers/dashboard_controller.rb
@@ -2,6 +2,7 @@
class DashboardController < Dashboard::ApplicationController
include IssuableCollectionsAction
+ include FiltersEvents
prepend_before_action(only: [:issues]) { authenticate_sessionless_user!(:rss) }
prepend_before_action(only: [:issues_calendar]) { authenticate_sessionless_user!(:ics) }
diff --git a/app/controllers/explore/projects_controller.rb b/app/controllers/explore/projects_controller.rb
index 705a586d614..f1f41e67a4c 100644
--- a/app/controllers/explore/projects_controller.rb
+++ b/app/controllers/explore/projects_controller.rb
@@ -4,6 +4,7 @@ class Explore::ProjectsController < Explore::ApplicationController
include PageLimiter
include ParamsBackwardCompatibility
include RendersMemberAccess
+ include RendersProjectsList
include SortingHelper
include SortingPreference
diff --git a/app/controllers/groups/application_controller.rb b/app/controllers/groups/application_controller.rb
index 84c8d7ada43..9c2e361e92f 100644
--- a/app/controllers/groups/application_controller.rb
+++ b/app/controllers/groups/application_controller.rb
@@ -30,25 +30,25 @@ class Groups::ApplicationController < ApplicationController
def authorize_admin_group!
unless can?(current_user, :admin_group, group)
- return render_404
+ render_404
end
end
def authorize_create_deploy_token!
unless can?(current_user, :create_deploy_token, group)
- return render_404
+ render_404
end
end
def authorize_destroy_deploy_token!
unless can?(current_user, :destroy_deploy_token, group)
- return render_404
+ render_404
end
end
def authorize_admin_group_member!
unless can?(current_user, :admin_group_member, group)
- return render_403
+ render_403
end
end
diff --git a/app/controllers/groups/boards_controller.rb b/app/controllers/groups/boards_controller.rb
index c618ee8566a..23d4f0d24e9 100644
--- a/app/controllers/groups/boards_controller.rb
+++ b/app/controllers/groups/boards_controller.rb
@@ -8,7 +8,6 @@ class Groups::BoardsController < Groups::ApplicationController
before_action :assign_endpoint_vars
before_action do
push_frontend_feature_flag(:multi_select_board, default_enabled: true)
- push_frontend_feature_flag(:sfc_issue_boards, default_enabled: true)
push_frontend_feature_flag(:boards_with_swimlanes, group, default_enabled: false)
end
diff --git a/app/controllers/groups/clusters_controller.rb b/app/controllers/groups/clusters_controller.rb
index 2165dee45fb..33bfc24885f 100644
--- a/app/controllers/groups/clusters_controller.rb
+++ b/app/controllers/groups/clusters_controller.rb
@@ -17,6 +17,12 @@ class Groups::ClustersController < Clusters::ClustersController
def group
@group ||= find_routable!(Group, params[:group_id] || params[:id])
end
-end
-Groups::ClustersController.prepend_if_ee('EE::Groups::ClustersController')
+ def metrics_dashboard_params
+ {
+ cluster: cluster,
+ cluster_type: :group,
+ group: group
+ }
+ end
+end
diff --git a/app/controllers/groups/runners_controller.rb b/app/controllers/groups/runners_controller.rb
index 635c248024e..edebffe2912 100644
--- a/app/controllers/groups/runners_controller.rb
+++ b/app/controllers/groups/runners_controller.rb
@@ -23,9 +23,13 @@ class Groups::RunnersController < Groups::ApplicationController
end
def destroy
- @runner.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
+ @runner.destroy
- redirect_to group_settings_ci_cd_path(@group, anchor: 'runners-settings'), status: :found
+ redirect_to group_settings_ci_cd_path(@group, anchor: 'runners-settings'), status: :found
+ end
end
def resume
@@ -47,7 +51,9 @@ class Groups::RunnersController < Groups::ApplicationController
private
def runner
- @runner ||= @group.runners.find(params[:id])
+ @runner ||= Ci::RunnersFinder.new(current_user: current_user, group: @group, params: {}).execute
+ .except(:limit, :offset)
+ .find(params[:id])
end
def runner_params
diff --git a/app/controllers/groups/settings/ci_cd_controller.rb b/app/controllers/groups/settings/ci_cd_controller.rb
index 18f336eae78..bf3a38ce57b 100644
--- a/app/controllers/groups/settings/ci_cd_controller.rb
+++ b/app/controllers/groups/settings/ci_cd_controller.rb
@@ -11,7 +11,15 @@ module Groups
end
before_action :define_variables, only: [:show]
+ NUMBER_OF_RUNNERS_PER_PAGE = 4
+
def show
+ runners_finder = Ci::RunnersFinder.new(current_user: current_user, group: @group, params: params)
+ # We need all runners for count
+ @all_group_runners = runners_finder.execute.except(:limit, :offset)
+ @group_runners = runners_finder.execute.page(params[:page]).per(NUMBER_OF_RUNNERS_PER_PAGE)
+
+ @sort = runners_finder.sort_key
end
def update
diff --git a/app/controllers/groups/variables_controller.rb b/app/controllers/groups/variables_controller.rb
index 11e3cfb01e4..02b015e8e53 100644
--- a/app/controllers/groups/variables_controller.rb
+++ b/app/controllers/groups/variables_controller.rb
@@ -9,7 +9,7 @@ module Groups
def show
respond_to do |format|
format.json do
- render status: :ok, json: { variables: GroupVariableSerializer.new.represent(@group.variables) }
+ render status: :ok, json: { variables: ::Ci::GroupVariableSerializer.new.represent(@group.variables) }
end
end
end
@@ -29,7 +29,7 @@ module Groups
private
def render_group_variables
- render status: :ok, json: { variables: GroupVariableSerializer.new.represent(@group.variables) }
+ render status: :ok, json: { variables: ::Ci::GroupVariableSerializer.new.represent(@group.variables) }
end
def render_error
diff --git a/app/controllers/groups_controller.rb b/app/controllers/groups_controller.rb
index fba374dbb44..2162d397da3 100644
--- a/app/controllers/groups_controller.rb
+++ b/app/controllers/groups_controller.rb
@@ -7,6 +7,7 @@ class GroupsController < Groups::ApplicationController
include PreviewMarkdown
include RecordUserLastActivity
include SendFileUpload
+ include FiltersEvents
extend ::Gitlab::Utils::Override
respond_to :html
diff --git a/app/controllers/ide_controller.rb b/app/controllers/ide_controller.rb
index 2bf7bdd1ae0..2c17f5b5542 100644
--- a/app/controllers/ide_controller.rb
+++ b/app/controllers/ide_controller.rb
@@ -8,6 +8,7 @@ class IdeController < ApplicationController
before_action do
push_frontend_feature_flag(:build_service_proxy)
+ push_frontend_feature_flag(:schema_linting)
end
def index
diff --git a/app/controllers/import/base_controller.rb b/app/controllers/import/base_controller.rb
index afdea4f7c9d..bc05030f8af 100644
--- a/app/controllers/import/base_controller.rb
+++ b/app/controllers/import/base_controller.rb
@@ -30,7 +30,7 @@ class Import::BaseController < ApplicationController
end
def incompatible_repos
- []
+ raise NotImplementedError
end
def provider_name
@@ -87,15 +87,6 @@ class Import::BaseController < ApplicationController
end
# rubocop: enable CodeReuse/ActiveRecord
- # rubocop: disable CodeReuse/ActiveRecord
- def find_jobs(import_type)
- current_user.created_projects
- .with_import_state
- .where(import_type: import_type)
- .to_json(only: [:id], methods: [:import_status])
- end
- # rubocop: enable CodeReuse/ActiveRecord
-
# deprecated: being replaced by app/services/import/base_service.rb
def find_or_create_namespace(names, owner)
names = params[:target_namespace].presence || names
diff --git a/app/controllers/import/bitbucket_controller.rb b/app/controllers/import/bitbucket_controller.rb
index 4886aeb5e3f..0ffd9ef8bdd 100644
--- a/app/controllers/import/bitbucket_controller.rb
+++ b/app/controllers/import/bitbucket_controller.rb
@@ -22,23 +22,8 @@ class Import::BitbucketController < Import::BaseController
redirect_to status_import_bitbucket_url
end
- # rubocop: disable CodeReuse/ActiveRecord
def status
- return super if Feature.enabled?(:new_import_ui)
-
- bitbucket_client = Bitbucket::Client.new(credentials)
- repos = bitbucket_client.repos(filter: sanitized_filter_param)
- @repos, @incompatible_repos = repos.partition { |repo| repo.valid? }
-
- @already_added_projects = find_already_added_projects('bitbucket')
- already_added_projects_names = @already_added_projects.pluck(:import_source)
-
- @repos.to_a.reject! { |repo| already_added_projects_names.include?(repo.full_name) }
- end
- # rubocop: enable CodeReuse/ActiveRecord
-
- def jobs
- render json: find_jobs('bitbucket')
+ super
end
def realtime_changes
diff --git a/app/controllers/import/bitbucket_server_controller.rb b/app/controllers/import/bitbucket_server_controller.rb
index 9aa8110257d..bee78cb3283 100644
--- a/app/controllers/import/bitbucket_server_controller.rb
+++ b/app/controllers/import/bitbucket_server_controller.rb
@@ -7,6 +7,7 @@ class Import::BitbucketServerController < Import::BaseController
before_action :verify_bitbucket_server_import_enabled
before_action :bitbucket_auth, except: [:new, :configure]
+ before_action :normalize_import_params, only: [:create]
before_action :validate_import_params, only: [:create]
rescue_from BitbucketServer::Connection::ConnectionError, with: :bitbucket_connection_error
@@ -34,48 +35,25 @@ class Import::BitbucketServerController < Import::BaseController
return render json: { errors: _("Project %{project_repo} could not be found") % { project_repo: "#{@project_key}/#{@repo_slug}" } }, status: :unprocessable_entity
end
- project_name = params[:new_name].presence || repo.name
- namespace_path = params[:new_namespace].presence || current_user.username
- target_namespace = find_or_create_namespace(namespace_path, current_user)
+ result = Import::BitbucketServerService.new(client, current_user, params).execute(credentials)
- if current_user.can?(:create_projects, target_namespace)
- project = Gitlab::BitbucketServerImport::ProjectCreator.new(@project_key, @repo_slug, repo, project_name, target_namespace, current_user, credentials).execute
-
- if project.persisted?
- render json: ProjectSerializer.new.represent(project, serializer: :import)
- else
- render json: { errors: project_save_error(project) }, status: :unprocessable_entity
- end
+ if result[:status] == :success
+ render json: ProjectSerializer.new.represent(result[:project], serializer: :import)
else
- render json: { errors: _('This namespace has already been taken! Please choose another one.') }, status: :unprocessable_entity
+ render json: { errors: result[:message] }, status: result[:http_status]
end
end
def configure
session[personal_access_token_key] = params[:personal_access_token]
- session[bitbucket_server_username_key] = params[:bitbucket_username]
+ session[bitbucket_server_username_key] = params[:bitbucket_server_username]
session[bitbucket_server_url_key] = params[:bitbucket_server_url]
redirect_to status_import_bitbucket_server_path
end
- # rubocop: disable CodeReuse/ActiveRecord
def status
- return super if Feature.enabled?(:new_import_ui)
-
- @collection = client.repos(page_offset: page_offset, limit: limit_per_page, filter: sanitized_filter_param)
- @repos, @incompatible_repos = @collection.partition { |repo| repo.valid? }
-
- # Use the import URL to filter beyond what BaseService#find_already_added_projects
- @already_added_projects = filter_added_projects('bitbucket_server', @repos.map(&:browse_url))
- already_added_projects_names = @already_added_projects.pluck(:import_source)
-
- @repos.reject! { |repo| already_added_projects_names.include?(repo.browse_url) }
- end
- # rubocop: enable CodeReuse/ActiveRecord
-
- def jobs
- render json: find_jobs('bitbucket_server')
+ super
end
def realtime_changes
@@ -126,9 +104,15 @@ class Import::BitbucketServerController < Import::BaseController
@bitbucket_repos ||= client.repos(page_offset: page_offset, limit: limit_per_page, filter: sanitized_filter_param).to_a
end
+ def normalize_import_params
+ project_key, repo_slug = params[:repo_id].split('/')
+ params[:bitbucket_server_project] = project_key
+ params[:bitbucket_server_repo] = repo_slug
+ end
+
def validate_import_params
- @project_key = params[:project]
- @repo_slug = params[:repository]
+ @project_key = params[:bitbucket_server_project]
+ @repo_slug = params[:bitbucket_server_repo]
return render_validation_error('Missing project key') unless @project_key.present? && @repo_slug.present?
return render_validation_error('Missing repository slug') unless @repo_slug.present?
diff --git a/app/controllers/import/fogbugz_controller.rb b/app/controllers/import/fogbugz_controller.rb
index 91779a5d6cc..a34bc9c953f 100644
--- a/app/controllers/import/fogbugz_controller.rb
+++ b/app/controllers/import/fogbugz_controller.rb
@@ -50,14 +50,7 @@ class Import::FogbugzController < Import::BaseController
return redirect_to new_import_fogbugz_path
end
- return super if Feature.enabled?(:new_import_ui)
-
- @repos = client.repos
-
- @already_added_projects = find_already_added_projects('fogbugz')
- already_added_projects_names = @already_added_projects.pluck(:import_source)
-
- @repos.reject! { |repo| already_added_projects_names.include? repo.name }
+ super
end
# rubocop: enable CodeReuse/ActiveRecord
@@ -65,10 +58,6 @@ class Import::FogbugzController < Import::BaseController
super
end
- def jobs
- render json: find_jobs('fogbugz')
- end
-
def create
repo = client.repo(params[:repo_id])
fb_session = { uri: session[:fogbugz_uri], token: session[:fogbugz_token] }
@@ -96,6 +85,11 @@ class Import::FogbugzController < Import::BaseController
end
# rubocop: enable CodeReuse/ActiveRecord
+ override :incompatible_repos
+ def incompatible_repos
+ []
+ end
+
override :provider_name
def provider_name
:fogbugz
diff --git a/app/controllers/import/gitea_controller.rb b/app/controllers/import/gitea_controller.rb
index 42c23fb29a7..efeff8439e4 100644
--- a/app/controllers/import/gitea_controller.rb
+++ b/app/controllers/import/gitea_controller.rb
@@ -21,15 +21,17 @@ class Import::GiteaController < Import::GithubController
super
end
- private
+ protected
- def host_key
- :"#{provider}_host_url"
+ override :provider_name
+ def provider_name
+ :gitea
end
- override :provider
- def provider
- :gitea
+ private
+
+ def host_key
+ :"#{provider_name}_host_url"
end
override :provider_url
diff --git a/app/controllers/import/github_controller.rb b/app/controllers/import/github_controller.rb
index 097edcd6075..ac6b8c06d66 100644
--- a/app/controllers/import/github_controller.rb
+++ b/app/controllers/import/github_controller.rb
@@ -1,6 +1,8 @@
# frozen_string_literal: true
class Import::GithubController < Import::BaseController
+ extend ::Gitlab::Utils::Override
+
include ImportHelper
include ActionView::Helpers::SanitizeHelper
@@ -34,18 +36,11 @@ class Import::GithubController < Import::BaseController
# Improving in https://gitlab.com/gitlab-org/gitlab-foss/issues/55585
client_repos
- respond_to do |format|
- format.json do
- render json: { imported_projects: serialized_imported_projects,
- provider_repos: serialized_provider_repos,
- namespaces: serialized_namespaces }
- end
- format.html
- end
+ super
end
def create
- result = Import::GithubService.new(client, current_user, import_params).execute(access_params, provider)
+ result = Import::GithubService.new(client, current_user, import_params).execute(access_params, provider_name)
if result[:status] == :success
render json: serialized_imported_projects(result[:project])
@@ -55,44 +50,51 @@ class Import::GithubController < Import::BaseController
end
def realtime_changes
- Gitlab::PollingInterval.set_header(response, interval: 3_000)
-
- render json: already_added_projects.to_json(only: [:id], methods: [:import_status])
+ super
end
- private
+ protected
- def import_params
- params.permit(permitted_import_params)
- end
+ # rubocop: disable CodeReuse/ActiveRecord
+ override :importable_repos
+ def importable_repos
+ already_added_projects_names = already_added_projects.pluck(:import_source)
- def permitted_import_params
- [:repo_id, :new_name, :target_namespace]
+ client_repos.reject { |repo| already_added_projects_names.include?(repo.full_name) }
end
+ # rubocop: enable CodeReuse/ActiveRecord
- def serialized_imported_projects(projects = already_added_projects)
- ProjectSerializer.new.represent(projects, serializer: :import, provider_url: provider_url)
+ override :incompatible_repos
+ def incompatible_repos
+ []
end
- def serialized_provider_repos
- repos = client_repos.reject { |repo| already_added_project_names.include? repo.full_name }
- Import::ProviderRepoSerializer.new(current_user: current_user).represent(repos, provider: provider, provider_url: provider_url)
+ override :provider_name
+ def provider_name
+ :github
end
- def serialized_namespaces
- NamespaceSerializer.new.represent(namespaces)
+ override :provider_url
+ def provider_url
+ strong_memoize(:provider_url) do
+ provider = Gitlab::Auth::OAuth::Provider.config_for('github')
+
+ provider&.dig('url').presence || 'https://github.com'
+ end
end
- def already_added_projects
- @already_added_projects ||= filtered(find_already_added_projects(provider))
+ private
+
+ def import_params
+ params.permit(permitted_import_params)
end
- def already_added_project_names
- @already_added_projects_names ||= already_added_projects.pluck(:import_source) # rubocop:disable CodeReuse/ActiveRecord
+ def permitted_import_params
+ [:repo_id, :new_name, :target_namespace]
end
- def namespaces
- current_user.manageable_groups_with_routes
+ def serialized_imported_projects(projects = already_added_projects)
+ ProjectSerializer.new.represent(projects, serializer: :import, provider_url: provider_url)
end
def expire_etag_cache
@@ -118,29 +120,29 @@ class Import::GithubController < Import::BaseController
end
def import_enabled?
- __send__("#{provider}_import_enabled?") # rubocop:disable GitlabSecurity/PublicSend
+ __send__("#{provider_name}_import_enabled?") # rubocop:disable GitlabSecurity/PublicSend
end
def realtime_changes_path
- public_send("realtime_changes_import_#{provider}_path", format: :json) # rubocop:disable GitlabSecurity/PublicSend
+ public_send("realtime_changes_import_#{provider_name}_path", format: :json) # rubocop:disable GitlabSecurity/PublicSend
end
def new_import_url
- public_send("new_import_#{provider}_url", extra_import_params) # rubocop:disable GitlabSecurity/PublicSend
+ public_send("new_import_#{provider_name}_url", extra_import_params) # rubocop:disable GitlabSecurity/PublicSend
end
def status_import_url
- public_send("status_import_#{provider}_url", extra_import_params) # rubocop:disable GitlabSecurity/PublicSend
+ public_send("status_import_#{provider_name}_url", extra_import_params) # rubocop:disable GitlabSecurity/PublicSend
end
def callback_import_url
- public_send("users_import_#{provider}_callback_url", extra_import_params) # rubocop:disable GitlabSecurity/PublicSend
+ public_send("users_import_#{provider_name}_callback_url", extra_import_params) # rubocop:disable GitlabSecurity/PublicSend
end
def provider_unauthorized
session[access_token_key] = nil
redirect_to new_import_url,
- alert: "Access denied to your #{Gitlab::ImportSources.title(provider.to_s)} account."
+ alert: "Access denied to your #{Gitlab::ImportSources.title(provider_name.to_s)} account."
end
def provider_rate_limit(exception)
@@ -151,29 +153,16 @@ class Import::GithubController < Import::BaseController
end
def access_token_key
- :"#{provider}_access_token"
+ :"#{provider_name}_access_token"
end
def access_params
{ github_access_token: session[access_token_key] }
end
- # The following methods are overridden in subclasses
- def provider
- :github
- end
-
- def provider_url
- strong_memoize(:provider_url) do
- provider = Gitlab::Auth::OAuth::Provider.config_for('github')
-
- provider&.dig('url').presence || 'https://github.com'
- end
- end
-
# rubocop: disable CodeReuse/ActiveRecord
def logged_in_with_provider?
- current_user.identities.exists?(provider: provider)
+ current_user.identities.exists?(provider: provider_name)
end
# rubocop: enable CodeReuse/ActiveRecord
@@ -202,12 +191,6 @@ class Import::GithubController < Import::BaseController
def filter_attribute
:name
end
-
- def filtered(collection)
- return collection unless sanitized_filter_param
-
- collection.select { |item| item[filter_attribute].include?(sanitized_filter_param) }
- end
end
Import::GithubController.prepend_if_ee('EE::Import::GithubController')
diff --git a/app/controllers/import/gitlab_controller.rb b/app/controllers/import/gitlab_controller.rb
index a95a67e208c..cc68eb02741 100644
--- a/app/controllers/import/gitlab_controller.rb
+++ b/app/controllers/import/gitlab_controller.rb
@@ -16,21 +16,8 @@ class Import::GitlabController < Import::BaseController
redirect_to status_import_gitlab_url
end
- # rubocop: disable CodeReuse/ActiveRecord
def status
- return super if Feature.enabled?(:new_import_ui)
-
- @repos = client.projects(starting_page: 1, page_limit: MAX_PROJECT_PAGES, per_page: PER_PAGE_PROJECTS)
-
- @already_added_projects = find_already_added_projects('gitlab')
- already_added_projects_names = @already_added_projects.pluck(:import_source)
-
- @repos = @repos.to_a.reject { |repo| already_added_projects_names.include? repo["path_with_namespace"] }
- end
- # rubocop: enable CodeReuse/ActiveRecord
-
- def jobs
- render json: find_jobs('gitlab')
+ super
end
def create
@@ -63,6 +50,11 @@ class Import::GitlabController < Import::BaseController
end
# rubocop: enable CodeReuse/ActiveRecord
+ override :incompatible_repos
+ def incompatible_repos
+ []
+ end
+
override :provider_name
def provider_name
:gitlab
diff --git a/app/controllers/instance_statistics/cohorts_controller.rb b/app/controllers/instance_statistics/cohorts_controller.rb
index 4b4e39db2e1..0de62a56b01 100644
--- a/app/controllers/instance_statistics/cohorts_controller.rb
+++ b/app/controllers/instance_statistics/cohorts_controller.rb
@@ -1,8 +1,12 @@
# frozen_string_literal: true
class InstanceStatistics::CohortsController < InstanceStatistics::ApplicationController
+ include Analytics::UniqueVisitsHelper
+
before_action :authenticate_usage_ping_enabled_or_admin!
+ track_unique_visits :index, target_id: 'i_analytics_cohorts'
+
def index
if Gitlab::CurrentSettings.usage_ping_enabled
cohorts_results = Rails.cache.fetch('cohorts', expires_in: 1.day) do
diff --git a/app/controllers/instance_statistics/dev_ops_score_controller.rb b/app/controllers/instance_statistics/dev_ops_score_controller.rb
index 238f7fa7707..b98a1bf7f99 100644
--- a/app/controllers/instance_statistics/dev_ops_score_controller.rb
+++ b/app/controllers/instance_statistics/dev_ops_score_controller.rb
@@ -1,6 +1,10 @@
# frozen_string_literal: true
class InstanceStatistics::DevOpsScoreController < InstanceStatistics::ApplicationController
+ include Analytics::UniqueVisitsHelper
+
+ track_unique_visits :index, target_id: 'i_analytics_dev_ops_score'
+
# rubocop: disable CodeReuse/ActiveRecord
def index
@metric = DevOpsScore::Metric.order(:created_at).last&.present
diff --git a/app/controllers/invites_controller.rb b/app/controllers/invites_controller.rb
index a78d87eceea..5bd9ac7f275 100644
--- a/app/controllers/invites_controller.rb
+++ b/app/controllers/invites_controller.rb
@@ -1,12 +1,17 @@
# frozen_string_literal: true
class InvitesController < ApplicationController
+ include Gitlab::Utils::StrongMemoize
+
before_action :member
skip_before_action :authenticate_user!, only: :decline
+ helper_method :member?, :current_user_matches_invite?
+
respond_to :html
def show
+ accept if skip_invitation_prompt?
end
def accept
@@ -38,6 +43,20 @@ class InvitesController < ApplicationController
private
+ def skip_invitation_prompt?
+ !member? && current_user_matches_invite?
+ end
+
+ def current_user_matches_invite?
+ @member.invite_email == current_user.email
+ end
+
+ def member?
+ strong_memoize(:is_member) do
+ @member.source.users.include?(current_user)
+ end
+ end
+
def member
return @member if defined?(@member)
diff --git a/app/controllers/oauth/applications_controller.rb b/app/controllers/oauth/applications_controller.rb
index 2c3e60d12b7..6532501733a 100644
--- a/app/controllers/oauth/applications_controller.rb
+++ b/app/controllers/oauth/applications_controller.rb
@@ -17,6 +17,8 @@ class Oauth::ApplicationsController < Doorkeeper::ApplicationsController
before_action :add_gon_variables
before_action :load_scopes, only: [:index, :create, :edit, :update]
+ around_action :set_locale
+
helper_method :can?
layout 'profile'
@@ -70,4 +72,8 @@ class Oauth::ApplicationsController < Doorkeeper::ApplicationsController
params[:owner] = current_user
end
end
+
+ def set_locale(&block)
+ Gitlab::I18n.with_user_locale(current_user, &block)
+ end
end
diff --git a/app/controllers/omniauth_callbacks_controller.rb b/app/controllers/omniauth_callbacks_controller.rb
index 4c595313cb6..706a4843117 100644
--- a/app/controllers/omniauth_callbacks_controller.rb
+++ b/app/controllers/omniauth_callbacks_controller.rb
@@ -200,7 +200,7 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController
def fail_login(user)
error_message = user.errors.full_messages.to_sentence
- return redirect_to omniauth_error_path(oauth['provider'], error: error_message)
+ redirect_to omniauth_error_path(oauth['provider'], error: error_message)
end
def fail_auth0_login
diff --git a/app/controllers/profiles/keys_controller.rb b/app/controllers/profiles/keys_controller.rb
index b9cb71ae89a..99e1b9027fa 100644
--- a/app/controllers/profiles/keys_controller.rb
+++ b/app/controllers/profiles/keys_controller.rb
@@ -1,8 +1,6 @@
# frozen_string_literal: true
class Profiles::KeysController < Profiles::ApplicationController
- skip_before_action :authenticate_user!, only: [:get_keys]
-
def index
@keys = current_user.keys.order_id_desc
@key = Key.new
@@ -33,25 +31,6 @@ class Profiles::KeysController < Profiles::ApplicationController
end
end
- # Get all keys of a user(params[:username]) in a text format
- # Helpful for sysadmins to put in respective servers
- def get_keys
- if params[:username].present?
- begin
- user = UserFinder.new(params[:username]).find_by_username
- if user.present?
- render plain: user.all_ssh_keys.join("\n")
- else
- return render_404
- end
- rescue => e
- render html: e.message
- end
- else
- return render_404
- end
- end
-
private
def key_params
diff --git a/app/controllers/profiles/personal_access_tokens_controller.rb b/app/controllers/profiles/personal_access_tokens_controller.rb
index f1c07cd9a1d..30f25e8fdaa 100644
--- a/app/controllers/profiles/personal_access_tokens_controller.rb
+++ b/app/controllers/profiles/personal_access_tokens_controller.rb
@@ -40,14 +40,18 @@ class Profiles::PersonalAccessTokensController < Profiles::ApplicationController
params.require(:personal_access_token).permit(:name, :expires_at, scopes: [])
end
- # rubocop: disable CodeReuse/ActiveRecord
def set_index_vars
@scopes = Gitlab::Auth.available_scopes_for(current_user)
@inactive_personal_access_tokens = finder(state: 'inactive').execute
- @active_personal_access_tokens = finder(state: 'active').execute.order(:expires_at)
+ @active_personal_access_tokens = active_personal_access_tokens
@new_personal_access_token = PersonalAccessToken.redis_getdel(current_user.id)
end
- # rubocop: enable CodeReuse/ActiveRecord
+
+ def active_personal_access_tokens
+ finder(state: 'active', sort: 'expires_at_asc').execute
+ end
end
+
+Profiles::PersonalAccessTokensController.prepend_if_ee('EE::Profiles::PersonalAccessTokensController')
diff --git a/app/controllers/profiles/preferences_controller.rb b/app/controllers/profiles/preferences_controller.rb
index 1477d79c911..8653fe3b6ed 100644
--- a/app/controllers/profiles/preferences_controller.rb
+++ b/app/controllers/profiles/preferences_controller.rb
@@ -48,6 +48,7 @@ class Profiles::PreferencesController < Profiles::ApplicationController
:time_display_relative,
:time_format_in_24h,
:show_whitespace_in_diffs,
+ :view_diffs_file_by_file,
:tab_width,
:sourcegraph_enabled,
:render_whitespace_in_code
diff --git a/app/controllers/projects/application_controller.rb b/app/controllers/projects/application_controller.rb
index b1f285f76d7..518d414be1b 100644
--- a/app/controllers/projects/application_controller.rb
+++ b/app/controllers/projects/application_controller.rb
@@ -42,7 +42,7 @@ class Projects::ApplicationController < ApplicationController
def authorize_action!(action)
unless can?(current_user, action, project)
- return access_denied!
+ access_denied!
end
end
@@ -81,10 +81,6 @@ class Projects::ApplicationController < ApplicationController
end
end
- def apply_diff_view_cookie!
- set_secure_cookie(:diff_view, params.delete(:view), permanent: true) if params[:view].present?
- end
-
def require_pages_enabled!
not_found unless @project.pages_available?
end
diff --git a/app/controllers/projects/blob_controller.rb b/app/controllers/projects/blob_controller.rb
index 14dca1bdc30..7f14522e61b 100644
--- a/app/controllers/projects/blob_controller.rb
+++ b/app/controllers/projects/blob_controller.rb
@@ -9,6 +9,7 @@ class Projects::BlobController < Projects::ApplicationController
include ActionView::Helpers::SanitizeHelper
include RedirectsForMissingPathOnTree
include SourcegraphDecorator
+ include DiffHelper
prepend_before_action :authenticate_user!, only: [:edit]
@@ -129,7 +130,7 @@ class Projects::BlobController < Projects::ApplicationController
end
end
- return redirect_to_tree_root_for_missing_path(@project, @ref, @path)
+ redirect_to_tree_root_for_missing_path(@project, @ref, @path)
end
end
@@ -207,14 +208,14 @@ class Projects::BlobController < Projects::ApplicationController
def set_last_commit_sha
@last_commit_sha = Gitlab::Git::Commit
- .last_for_path(@repository, @ref, @path).sha
+ .last_for_path(@repository, @ref, @path, literal_pathspec: true).sha
end
def show_html
environment_params = @repository.branch_exists?(@ref) ? { ref: @ref } : { commit: @commit }
environment_params[:find_latest] = true
@environment = EnvironmentsFinder.new(@project, current_user, environment_params).execute.last
- @last_commit = @repository.last_commit_for_path(@commit.id, @blob.path)
+ @last_commit = @repository.last_commit_for_path(@commit.id, @blob.path, literal_pathspec: true)
@code_navigation_path = Gitlab::CodeNavigationPath.new(@project, @blob.commit_id).full_json_path_for(@blob.path)
render 'show'
diff --git a/app/controllers/projects/boards_controller.rb b/app/controllers/projects/boards_controller.rb
index 8fa823e0be1..db05da0bb7f 100644
--- a/app/controllers/projects/boards_controller.rb
+++ b/app/controllers/projects/boards_controller.rb
@@ -9,7 +9,6 @@ class Projects::BoardsController < Projects::ApplicationController
before_action :assign_endpoint_vars
before_action do
push_frontend_feature_flag(:multi_select_board, default_enabled: true)
- push_frontend_feature_flag(:sfc_issue_boards, default_enabled: true)
end
private
diff --git a/app/controllers/projects/ci/lints_controller.rb b/app/controllers/projects/ci/lints_controller.rb
index b50afa12da0..73b3eb9c205 100644
--- a/app/controllers/projects/ci/lints_controller.rb
+++ b/app/controllers/projects/ci/lints_controller.rb
@@ -14,7 +14,7 @@ class Projects::Ci::LintsController < Projects::ApplicationController
@errors = result.errors
if result.valid?
- @config_processor = result.content
+ @config_processor = result.config
@stages = @config_processor.stages
@builds = @config_processor.builds
@jobs = @config_processor.jobs
diff --git a/app/controllers/projects/clusters_controller.rb b/app/controllers/projects/clusters_controller.rb
index 079d30127d6..8acf5235c1a 100644
--- a/app/controllers/projects/clusters_controller.rb
+++ b/app/controllers/projects/clusters_controller.rb
@@ -23,6 +23,13 @@ class Projects::ClustersController < Clusters::ClustersController
def repository
@repository ||= project.repository
end
-end
-Projects::ClustersController.prepend_if_ee('EE::Projects::ClustersController')
+ def metrics_dashboard_params
+ params.permit(:embedded, :group, :title, :y_label).merge(
+ {
+ cluster: cluster,
+ cluster_type: :project
+ }
+ )
+ end
+end
diff --git a/app/controllers/projects/confluences_controller.rb b/app/controllers/projects/confluences_controller.rb
new file mode 100644
index 00000000000..d563b34a362
--- /dev/null
+++ b/app/controllers/projects/confluences_controller.rb
@@ -0,0 +1,14 @@
+# frozen_string_literal: true
+
+class Projects::ConfluencesController < Projects::ApplicationController
+ before_action :ensure_confluence
+
+ def show
+ end
+
+ private
+
+ def ensure_confluence
+ render_404 unless project.has_confluence?
+ end
+end
diff --git a/app/controllers/projects/cycle_analytics_controller.rb b/app/controllers/projects/cycle_analytics_controller.rb
index f13c75ac4cc..898d888c978 100644
--- a/app/controllers/projects/cycle_analytics_controller.rb
+++ b/app/controllers/projects/cycle_analytics_controller.rb
@@ -4,10 +4,13 @@ class Projects::CycleAnalyticsController < Projects::ApplicationController
include ActionView::Helpers::DateHelper
include ActionView::Helpers::TextHelper
include CycleAnalyticsParams
+ include Analytics::UniqueVisitsHelper
before_action :whitelist_query_limiting, only: [:show]
before_action :authorize_read_cycle_analytics!
+ track_unique_visits :show, target_id: 'p_analytics_valuestream'
+
def show
@cycle_analytics = ::CycleAnalytics::ProjectLevel.new(@project, options: options(cycle_analytics_project_params))
diff --git a/app/controllers/projects/deployments_controller.rb b/app/controllers/projects/deployments_controller.rb
index 766e2f86ea2..1344cf775e4 100644
--- a/app/controllers/projects/deployments_controller.rb
+++ b/app/controllers/projects/deployments_controller.rb
@@ -1,7 +1,6 @@
# frozen_string_literal: true
class Projects::DeploymentsController < Projects::ApplicationController
- before_action :authorize_read_environment!
before_action :authorize_read_deployment!
# rubocop: disable CodeReuse/ActiveRecord
diff --git a/app/controllers/projects/environments/prometheus_api_controller.rb b/app/controllers/projects/environments/prometheus_api_controller.rb
index 98fcc594d6e..f0bb5360f84 100644
--- a/app/controllers/projects/environments/prometheus_api_controller.rb
+++ b/app/controllers/projects/environments/prometheus_api_controller.rb
@@ -1,51 +1,17 @@
# frozen_string_literal: true
class Projects::Environments::PrometheusApiController < Projects::ApplicationController
- include RenderServiceResults
+ include Metrics::Dashboard::PrometheusApiProxy
- before_action :authorize_read_prometheus!
- before_action :environment
-
- def proxy
- variable_substitution_result =
- variable_substitution_service.new(environment, permit_params).execute
-
- if variable_substitution_result[:status] == :error
- return error_response(variable_substitution_result)
- end
-
- prometheus_result = Prometheus::ProxyService.new(
- environment,
- proxy_method,
- proxy_path,
- variable_substitution_result[:params]
- ).execute
-
- return continue_polling_response if prometheus_result.nil?
- return error_response(prometheus_result) if prometheus_result[:status] == :error
-
- success_response(prometheus_result)
- end
+ before_action :proxyable
private
- def variable_substitution_service
- Prometheus::ProxyVariableSubstitutionService
- end
-
- def permit_params
- params.permit!
- end
-
- def environment
- @environment ||= project.environments.find(params[:id])
+ def proxyable
+ @proxyable ||= project.environments.find(params[:id])
end
- def proxy_method
- request.method
- end
-
- def proxy_path
- params[:proxy_path]
+ def proxy_variable_substitution_service
+ Prometheus::ProxyVariableSubstitutionService
end
end
diff --git a/app/controllers/projects/environments_controller.rb b/app/controllers/projects/environments_controller.rb
index 4d774123ef1..d5da24a76de 100644
--- a/app/controllers/projects/environments_controller.rb
+++ b/app/controllers/projects/environments_controller.rb
@@ -1,6 +1,10 @@
# frozen_string_literal: true
class Projects::EnvironmentsController < Projects::ApplicationController
+ # Metrics dashboard code is getting decoupled from environments and is being moved
+ # into app/controllers/projects/metrics_dashboard_controller.rb
+ # See https://gitlab.com/gitlab-org/gitlab/-/issues/226002 for more details.
+
include MetricsDashboard
layout 'project'
diff --git a/app/controllers/projects/forks_controller.rb b/app/controllers/projects/forks_controller.rb
index ebc81976529..b93f6384e0c 100644
--- a/app/controllers/projects/forks_controller.rb
+++ b/app/controllers/projects/forks_controller.rb
@@ -3,6 +3,7 @@
class Projects::ForksController < Projects::ApplicationController
include ContinueParams
include RendersMemberAccess
+ include RendersProjectsList
include Gitlab::Utils::StrongMemoize
# Authorize
diff --git a/app/controllers/projects/graphs_controller.rb b/app/controllers/projects/graphs_controller.rb
index a8b90f8685f..9b889f9e837 100644
--- a/app/controllers/projects/graphs_controller.rb
+++ b/app/controllers/projects/graphs_controller.rb
@@ -2,12 +2,15 @@
class Projects::GraphsController < Projects::ApplicationController
include ExtractsPath
+ include Analytics::UniqueVisitsHelper
# Authorize
before_action :require_non_empty_project
before_action :assign_ref_vars
before_action :authorize_read_repository_graphs!
+ track_unique_visits :charts, target_id: 'p_analytics_repo'
+
def show
respond_to do |format|
format.html
diff --git a/app/controllers/projects/imports_controller.rb b/app/controllers/projects/imports_controller.rb
index 67a7daf8445..deba71c9dd3 100644
--- a/app/controllers/projects/imports_controller.rb
+++ b/app/controllers/projects/imports_controller.rb
@@ -5,7 +5,8 @@ class Projects::ImportsController < Projects::ApplicationController
include ImportUrlParams
# Authorize
- before_action :authorize_admin_project!
+ before_action :authorize_admin_project!, only: [:new, :create]
+ before_action :require_namespace_project_creation_permission, only: :show
before_action :require_no_repo, only: [:new, :create]
before_action :redirect_if_progress, only: [:new, :create]
before_action :redirect_if_no_import, only: :show
@@ -51,6 +52,10 @@ class Projects::ImportsController < Projects::ApplicationController
end
end
+ def require_namespace_project_creation_permission
+ render_404 unless current_user.can?(:admin_project, @project) || current_user.can?(:create_projects, @project.namespace)
+ end
+
def redirect_if_progress
if @project.import_in_progress?
redirect_to project_import_path(@project)
diff --git a/app/controllers/projects/incident_management/pager_duty_incidents_controller.rb b/app/controllers/projects/incident_management/pager_duty_incidents_controller.rb
new file mode 100644
index 00000000000..dac1640dd08
--- /dev/null
+++ b/app/controllers/projects/incident_management/pager_duty_incidents_controller.rb
@@ -0,0 +1,35 @@
+# frozen_string_literal: true
+
+module Projects
+ module IncidentManagement
+ class PagerDutyIncidentsController < Projects::ApplicationController
+ respond_to :json
+
+ skip_before_action :verify_authenticity_token
+ skip_before_action :project
+
+ prepend_before_action :project_without_auth
+
+ def create
+ result = webhook_processor.execute(params[:token])
+
+ head result.http_status
+ end
+
+ private
+
+ def project_without_auth
+ @project ||= Project
+ .find_by_full_path("#{params[:namespace_id]}/#{params[:project_id]}")
+ end
+
+ def webhook_processor
+ ::IncidentManagement::PagerDuty::ProcessWebhookService.new(project, nil, payload)
+ end
+
+ def payload
+ @payload ||= params.permit![:pager_duty_incident].to_h
+ end
+ end
+ end
+end
diff --git a/app/controllers/projects/issues_controller.rb b/app/controllers/projects/issues_controller.rb
index 693329848de..12b5a538bc9 100644
--- a/app/controllers/projects/issues_controller.rb
+++ b/app/controllers/projects/issues_controller.rb
@@ -11,11 +11,11 @@ class Projects::IssuesController < Projects::ApplicationController
include RecordUserLastActivity
def issue_except_actions
- %i[index calendar new create bulk_update import_csv export_csv]
+ %i[index calendar new create bulk_update import_csv export_csv service_desk]
end
def set_issuables_index_only_actions
- %i[index calendar]
+ %i[index calendar service_desk]
end
prepend_before_action(only: [:index]) { authenticate_sessionless_user!(:rss) }
@@ -46,10 +46,17 @@ class Projects::IssuesController < Projects::ApplicationController
before_action do
push_frontend_feature_flag(:vue_issuable_sidebar, project.group)
+ push_frontend_feature_flag(:tribute_autocomplete, @project)
+ push_frontend_feature_flag(:vue_issuables_list, project)
end
before_action only: :show do
push_frontend_feature_flag(:real_time_issue_sidebar, @project)
+ push_frontend_feature_flag(:confidential_apollo_sidebar, @project)
+ end
+
+ before_action only: :index do
+ push_frontend_feature_flag(:scoped_labels, @project)
end
around_action :allow_gitaly_ref_name_caching, only: [:discussions]
@@ -216,6 +223,11 @@ class Projects::IssuesController < Projects::ApplicationController
redirect_to project_issues_path(project)
end
+ def service_desk
+ @issues = @issuables # rubocop:disable Gitlab/ModuleWithInstanceVariables
+ @users.push(User.support_bot) # rubocop:disable Gitlab/ModuleWithInstanceVariables
+ end
+
protected
def sorting_field
@@ -313,6 +325,17 @@ class Projects::IssuesController < Projects::ApplicationController
private
+ def finder_options
+ options = super
+
+ return options unless service_desk?
+
+ options.reject! { |key| key == 'author_username' || key == 'author_id' }
+ options[:author_id] = User.support_bot
+
+ options
+ end
+
def branch_link(branch)
project_compare_path(project, from: project.default_branch, to: branch[:name])
end
@@ -330,6 +353,10 @@ class Projects::IssuesController < Projects::ApplicationController
def rate_limiter
::Gitlab::ApplicationRateLimiter
end
+
+ def service_desk?
+ action_name == 'service_desk'
+ end
end
Projects::IssuesController.prepend_if_ee('EE::Projects::IssuesController')
diff --git a/app/controllers/projects/jobs_controller.rb b/app/controllers/projects/jobs_controller.rb
index e1f6cbe3dca..3f7f8da3478 100644
--- a/app/controllers/projects/jobs_controller.rb
+++ b/app/controllers/projects/jobs_controller.rb
@@ -11,9 +11,6 @@ class Projects::JobsController < Projects::ApplicationController
before_action :authorize_erase_build!, only: [:erase]
before_action :authorize_use_build_terminal!, only: [:terminal, :terminal_websocket_authorize]
before_action :verify_api_request!, only: :terminal_websocket_authorize
- before_action only: [:show] do
- push_frontend_feature_flag(:job_log_json, project, default_enabled: true)
- end
before_action :authorize_create_proxy_build!, only: :proxy_websocket_authorize
before_action :verify_proxy_request!, only: :proxy_websocket_authorize
@@ -55,15 +52,10 @@ class Projects::JobsController < Projects::ApplicationController
format.json do
build.trace.being_watched!
- # TODO: when the feature flag is removed we should not pass
- # content_format to serialize method.
- content_format = Feature.enabled?(:job_log_json, @project, default_enabled: true) ? :json : :html
-
build_trace = Ci::BuildTrace.new(
build: @build,
stream: stream,
- state: params[:state],
- content_format: content_format)
+ state: params[:state])
render json: BuildTraceSerializer
.new(project: @project, current_user: @current_user)
diff --git a/app/controllers/projects/logs_controller.rb b/app/controllers/projects/logs_controller.rb
index ba509235417..b9027b3a2cb 100644
--- a/app/controllers/projects/logs_controller.rb
+++ b/app/controllers/projects/logs_controller.rb
@@ -2,15 +2,16 @@
module Projects
class LogsController < Projects::ApplicationController
+ include ::Gitlab::Utils::StrongMemoize
+
before_action :authorize_read_pod_logs!
- before_action :environment
before_action :ensure_deployments, only: %i(k8s elasticsearch)
def index
- if environment.nil?
- render :empty_logs
- else
+ if environment || cluster
render :index
+ else
+ render :empty_logs
end
end
@@ -39,8 +40,9 @@ module Projects
end
end
- def index_params
- params.permit(:environment_name)
+ # cluster is selected either via environment or directly by id
+ def cluster_params
+ params.permit(:environment_name, :cluster_id)
end
def k8s_params
@@ -52,22 +54,36 @@ module Projects
end
def environment
- @environment ||= if index_params.key?(:environment_name)
- EnvironmentsFinder.new(project, current_user, name: index_params[:environment_name]).find.first
- else
- project.default_environment
- end
+ strong_memoize(:environment) do
+ if cluster_params.key?(:environment_name)
+ EnvironmentsFinder.new(project, current_user, name: cluster_params[:environment_name]).find.first
+ else
+ project.default_environment
+ end
+ end
end
def cluster
- environment.deployment_platform&.cluster
+ strong_memoize(:cluster) do
+ if gitlab_managed_apps_logs?
+ clusters = ClusterAncestorsFinder.new(project, current_user).execute
+ clusters.find { |cluster| cluster.id == cluster_params[:cluster_id].to_i }
+ else
+ environment&.deployment_platform&.cluster
+ end
+ end
end
def namespace
- environment.deployment_namespace
+ if gitlab_managed_apps_logs?
+ Gitlab::Kubernetes::Helm::NAMESPACE
+ else
+ environment.deployment_namespace
+ end
end
def ensure_deployments
+ return if gitlab_managed_apps_logs?
return if cluster && namespace.present?
render status: :bad_request, json: {
@@ -75,5 +91,9 @@ module Projects
message: _('Environment does not have deployments')
}
end
+
+ def gitlab_managed_apps_logs?
+ cluster_params.key?(:cluster_id)
+ end
end
end
diff --git a/app/controllers/projects/merge_requests/application_controller.rb b/app/controllers/projects/merge_requests/application_controller.rb
index b7e99cb7ed0..0bb4e0fb5ee 100644
--- a/app/controllers/projects/merge_requests/application_controller.rb
+++ b/app/controllers/projects/merge_requests/application_controller.rb
@@ -48,12 +48,9 @@ class Projects::MergeRequests::ApplicationController < Projects::ApplicationCont
end
def set_pipeline_variables
- @pipelines =
- if can?(current_user, :read_pipeline, @merge_request.source_project)
- @merge_request.all_pipelines
- else
- Ci::Pipeline.none
- end
+ @pipelines = Ci::PipelinesForMergeRequestFinder
+ .new(@merge_request, current_user)
+ .execute
end
def close_merge_request_if_no_source_project
diff --git a/app/controllers/projects/merge_requests/creations_controller.rb b/app/controllers/projects/merge_requests/creations_controller.rb
index 28aa1b300aa..3e077c1af37 100644
--- a/app/controllers/projects/merge_requests/creations_controller.rb
+++ b/app/controllers/projects/merge_requests/creations_controller.rb
@@ -32,13 +32,13 @@ class Projects::MergeRequests::CreationsController < Projects::MergeRequests::Ap
end
def pipelines
- @pipelines = @merge_request.all_pipelines
+ @pipelines = Ci::PipelinesForMergeRequestFinder.new(@merge_request, current_user).execute
Gitlab::PollingInterval.set_header(response, interval: 10_000)
render json: {
pipelines: PipelineSerializer
- .new(project: @project, current_user: @current_user)
+ .new(project: @project, current_user: current_user)
.represent(@pipelines)
}
end
diff --git a/app/controllers/projects/merge_requests/diffs_controller.rb b/app/controllers/projects/merge_requests/diffs_controller.rb
index 1bf143c9a91..98b0abc89e9 100644
--- a/app/controllers/projects/merge_requests/diffs_controller.rb
+++ b/app/controllers/projects/merge_requests/diffs_controller.rb
@@ -8,6 +8,7 @@ class Projects::MergeRequests::DiffsController < Projects::MergeRequests::Applic
before_action :commit
before_action :define_diff_vars
before_action :define_diff_comment_vars, except: [:diffs_batch, :diffs_metadata]
+ before_action :update_diff_discussion_positions!
around_action :allow_gitaly_ref_name_caching
@@ -171,4 +172,12 @@ class Projects::MergeRequests::DiffsController < Projects::MergeRequests::Applic
@notes.concat(draft_notes)
end
+
+ def update_diff_discussion_positions!
+ return unless Feature.enabled?(:merge_ref_head_comments, @merge_request.target_project, default_enabled: true)
+ return unless Feature.enabled?(:merge_red_head_comments_position_on_demand, @merge_request.target_project, default_enabled: true)
+ return if @merge_request.has_any_diff_note_positions?
+
+ Discussions::CaptureDiffNotePositionsService.new(@merge_request).execute
+ end
end
diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb
index 6c1ffc35276..e65e5531b88 100644
--- a/app/controllers/projects/merge_requests_controller.rb
+++ b/app/controllers/projects/merge_requests_controller.rb
@@ -35,15 +35,23 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
push_frontend_feature_flag(:mr_commit_neighbor_nav, @project, default_enabled: true)
push_frontend_feature_flag(:multiline_comments, @project)
push_frontend_feature_flag(:file_identifier_hash)
- push_frontend_feature_flag(:batch_suggestions, @project)
+ push_frontend_feature_flag(:batch_suggestions, @project, default_enabled: true)
end
before_action do
push_frontend_feature_flag(:vue_issuable_sidebar, @project.group)
+ push_frontend_feature_flag(:junit_pipeline_view, @project.group)
end
around_action :allow_gitaly_ref_name_caching, only: [:index, :show, :discussions]
+ feature_category :source_code_management,
+ unless: -> (action) { action.ends_with?("_reports") }
+ feature_category :code_testing,
+ only: [:test_reports, :coverage_reports, :terraform_reports]
+ feature_category :accessibility_testing,
+ only: [:accessibility_reports]
+
def index
@merge_requests = @issuables
@@ -76,7 +84,9 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
@issuable_sidebar = serializer.represent(@merge_request, serializer: 'sidebar')
@current_user_data = UserSerializer.new(project: @project).represent(current_user, {}, MergeRequestUserEntity).to_json
@show_whitespace_default = current_user.nil? || current_user.show_whitespace_in_diffs
+ @file_by_file_default = Feature.enabled?(:view_diffs_file_by_file) && current_user&.view_diffs_file_by_file
@coverage_path = coverage_reports_project_merge_request_path(@project, @merge_request, format: :json) if @merge_request.has_coverage_reports?
+ @endpoint_metadata_url = endpoint_metadata_url(@project, @merge_request)
set_pipeline_variables
@@ -108,8 +118,8 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
# or from cache if already merged
@commits =
set_commits_for_rendering(
- @merge_request.recent_commits.with_latest_pipeline(@merge_request.source_branch),
- commits_count: @merge_request.commits_count
+ @merge_request.recent_commits.with_latest_pipeline(@merge_request.source_branch).with_markdown_cache,
+ commits_count: @merge_request.commits_count
)
render json: { html: view_to_html_string('projects/merge_requests/_commits') }
@@ -178,7 +188,7 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
end
def update
- @merge_request = ::MergeRequests::UpdateService.new(project, current_user, merge_request_params).execute(@merge_request)
+ @merge_request = ::MergeRequests::UpdateService.new(project, current_user, merge_request_update_params).execute(@merge_request)
respond_to do |format|
format.html do
@@ -312,6 +322,10 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
private
+ def merge_request_update_params
+ merge_request_params.merge!(params.permit(:merge_request_diff_head_sha))
+ end
+
def head_pipeline
strong_memoize(:head_pipeline) do
pipeline = @merge_request.head_pipeline
@@ -422,6 +436,13 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
def authorize_read_actual_head_pipeline!
return render_404 unless can?(current_user, :read_build, merge_request.actual_head_pipeline)
end
+
+ def endpoint_metadata_url(project, merge_request)
+ params = request.query_parameters
+ params[:view] = cookies[:diff_view] if params[:view].blank? && cookies[:diff_view].present?
+
+ diffs_metadata_project_json_merge_request_path(project, merge_request, 'json', params)
+ end
end
Projects::MergeRequestsController.prepend_if_ee('EE::Projects::MergeRequestsController')
diff --git a/app/controllers/projects/metrics_dashboard_controller.rb b/app/controllers/projects/metrics_dashboard_controller.rb
new file mode 100644
index 00000000000..235ee1dfbf2
--- /dev/null
+++ b/app/controllers/projects/metrics_dashboard_controller.rb
@@ -0,0 +1,33 @@
+# frozen_string_literal: true
+module Projects
+ class MetricsDashboardController < Projects::ApplicationController
+ # Metrics dashboard code is in the process of being decoupled from environments
+ # and is getting moved to this controller. Some code may be duplicated from
+ # app/controllers/projects/environments_controller.rb
+ # See https://gitlab.com/gitlab-org/gitlab/-/issues/226002 for more details.
+
+ before_action :authorize_metrics_dashboard!
+ before_action do
+ push_frontend_feature_flag(:prometheus_computed_alerts)
+ end
+
+ def show
+ if environment
+ render 'projects/environments/metrics'
+ else
+ render_404
+ end
+ end
+
+ private
+
+ def environment
+ @environment ||=
+ if params[:environment]
+ project.environments.find(params[:environment])
+ else
+ project.default_environment
+ end
+ end
+ end
+end
diff --git a/app/controllers/projects/pipelines/application_controller.rb b/app/controllers/projects/pipelines/application_controller.rb
new file mode 100644
index 00000000000..92887750813
--- /dev/null
+++ b/app/controllers/projects/pipelines/application_controller.rb
@@ -0,0 +1,24 @@
+# frozen_string_literal: true
+
+# Abstract class encapsulating common logic for creating new controllers in a pipeline context
+
+module Projects
+ module Pipelines
+ class ApplicationController < Projects::ApplicationController
+ include Gitlab::Utils::StrongMemoize
+
+ before_action :pipeline
+ before_action :authorize_read_pipeline!
+
+ private
+
+ def pipeline
+ strong_memoize(:pipeline) do
+ project.all_pipelines.find(params[:pipeline_id]).tap do |pipeline|
+ render_404 unless can?(current_user, :read_pipeline, pipeline)
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/app/controllers/projects/pipelines/stages_controller.rb b/app/controllers/projects/pipelines/stages_controller.rb
new file mode 100644
index 00000000000..ce08b49ce9f
--- /dev/null
+++ b/app/controllers/projects/pipelines/stages_controller.rb
@@ -0,0 +1,29 @@
+# frozen_string_literal: true
+
+module Projects
+ module Pipelines
+ class StagesController < Projects::Pipelines::ApplicationController
+ before_action :authorize_update_pipeline!
+
+ def play_manual
+ ::Ci::PlayManualStageService
+ .new(@project, current_user, pipeline: pipeline)
+ .execute(stage)
+
+ respond_to do |format|
+ format.json do
+ render json: StageSerializer
+ .new(project: @project, current_user: @current_user)
+ .represent(stage)
+ end
+ end
+ end
+
+ private
+
+ def stage
+ @pipeline_stage ||= pipeline.find_stage_by_name!(params[:stage_name])
+ end
+ end
+ end
+end
diff --git a/app/controllers/projects/pipelines/tests_controller.rb b/app/controllers/projects/pipelines/tests_controller.rb
new file mode 100644
index 00000000000..f03274bf32e
--- /dev/null
+++ b/app/controllers/projects/pipelines/tests_controller.rb
@@ -0,0 +1,59 @@
+# frozen_string_literal: true
+
+module Projects
+ module Pipelines
+ class TestsController < Projects::Pipelines::ApplicationController
+ before_action :validate_feature_flag!
+ before_action :authorize_read_build!
+ before_action :builds, only: [:show]
+
+ def summary
+ respond_to do |format|
+ format.json do
+ render json: TestReportSummarySerializer
+ .new(project: project, current_user: @current_user)
+ .represent(pipeline.test_report_summary)
+ end
+ end
+ end
+
+ def show
+ respond_to do |format|
+ format.json do
+ render json: TestSuiteSerializer
+ .new(project: project, current_user: @current_user)
+ .represent(test_suite, details: true)
+ end
+ end
+ end
+
+ private
+
+ def validate_feature_flag!
+ render_404 unless Feature.enabled?(:build_report_summary, project)
+ end
+
+ # rubocop: disable CodeReuse/ActiveRecord
+ def builds
+ pipeline.latest_builds.where(id: build_params)
+ end
+
+ def build_params
+ return [] unless params[:build_ids]
+
+ params[:build_ids].split(",")
+ end
+
+ def test_suite
+ if builds.present?
+ builds.map do |build|
+ build.collect_test_reports!(Gitlab::Ci::Reports::TestReports.new)
+ end.sum
+ else
+ render_404
+ end
+ end
+ # rubocop: enable CodeReuse/ActiveRecord
+ end
+ end
+end
diff --git a/app/controllers/projects/pipelines_controller.rb b/app/controllers/projects/pipelines_controller.rb
index 0b6c0db211e..d8e11ddd423 100644
--- a/app/controllers/projects/pipelines_controller.rb
+++ b/app/controllers/projects/pipelines_controller.rb
@@ -2,6 +2,7 @@
class Projects::PipelinesController < Projects::ApplicationController
include ::Gitlab::Utils::StrongMemoize
+ include Analytics::UniqueVisitsHelper
before_action :whitelist_query_limiting, only: [:create, :retry]
before_action :pipeline, except: [:index, :new, :create, :charts]
@@ -12,14 +13,20 @@ class Projects::PipelinesController < Projects::ApplicationController
before_action :authorize_update_pipeline!, only: [:retry, :cancel]
before_action do
push_frontend_feature_flag(:junit_pipeline_view, project)
+ push_frontend_feature_flag(:build_report_summary, project)
push_frontend_feature_flag(:filter_pipelines_search, project, default_enabled: true)
- push_frontend_feature_flag(:dag_pipeline_tab, project, default_enabled: false)
+ push_frontend_feature_flag(:dag_pipeline_tab, project, default_enabled: true)
push_frontend_feature_flag(:pipelines_security_report_summary, project)
end
before_action :ensure_pipeline, only: [:show]
+ # 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? }
+
around_action :allow_gitaly_ref_name_caching, only: [:index, :show]
+ track_unique_visits :charts, target_id: 'p_analytics_pipelines'
+
wrap_parameters Ci::Pipeline
POLLING_INTERVAL = 10_000
@@ -31,9 +38,6 @@ class Projects::PipelinesController < Projects::ApplicationController
.page(params[:page])
.per(30)
- @running_count = limited_pipelines_count(project, 'running')
- @pending_count = limited_pipelines_count(project, 'pending')
- @finished_count = limited_pipelines_count(project, 'finished')
@pipelines_count = limited_pipelines_count(project)
respond_to do |format|
@@ -44,10 +48,7 @@ class Projects::PipelinesController < Projects::ApplicationController
render json: {
pipelines: serialize_pipelines,
count: {
- all: @pipelines_count,
- running: @running_count,
- pending: @pending_count,
- finished: @finished_count
+ all: @pipelines_count
}
}
end
@@ -186,7 +187,7 @@ class Projects::PipelinesController < Projects::ApplicationController
format.json do
render json: TestReportSerializer
.new(current_user: @current_user)
- .represent(pipeline_test_report, project: project)
+ .represent(pipeline_test_report, project: project, details: true)
end
end
end
@@ -226,6 +227,12 @@ class Projects::PipelinesController < Projects::ApplicationController
render_404 unless pipeline
end
+ def redirect_for_legacy_scope_filter
+ return unless %w[running pending].include?(params[:scope])
+
+ redirect_to url_for(safe_params.except(:scope).merge(status: safe_params[:scope])), status: :moved_permanently
+ end
+
# rubocop: disable CodeReuse/ActiveRecord
def pipeline
@pipeline ||= if params[:id].blank? && params[:latest]
diff --git a/app/controllers/projects/refs_controller.rb b/app/controllers/projects/refs_controller.rb
index a2581e72257..db770d3e438 100644
--- a/app/controllers/projects/refs_controller.rb
+++ b/app/controllers/projects/refs_controller.rb
@@ -11,10 +11,6 @@ class Projects::RefsController < Projects::ApplicationController
before_action :assign_ref_vars
before_action :authorize_download_code!
- before_action only: [:logs_tree] do
- push_frontend_feature_flag(:vue_file_list_lfs_badge, default_enabled: true)
- end
-
def switch
respond_to do |format|
format.html do
@@ -57,22 +53,11 @@ class Projects::RefsController < Projects::ApplicationController
render json: logs
end
-
- # Deprecated due to https://gitlab.com/gitlab-org/gitlab/-/issues/36863
- # Will be removed soon https://gitlab.com/gitlab-org/gitlab/-/merge_requests/29895
- format.js do
- @logs, _ = tree_summary.summarize
- @more_log_url = more_url(tree_summary.next_offset) if tree_summary.more?
- end
end
end
private
- def more_url(offset)
- logs_file_project_ref_path(@project, @ref, @path, offset: offset)
- end
-
def validate_ref_id
return not_found! if params[:id].present? && params[:id] !~ Gitlab::PathRegex.git_reference_regex
end
diff --git a/app/controllers/projects/releases_controller.rb b/app/controllers/projects/releases_controller.rb
index d3285b64dab..d58755c2655 100644
--- a/app/controllers/projects/releases_controller.rb
+++ b/app/controllers/projects/releases_controller.rb
@@ -13,6 +13,7 @@ class Projects::ReleasesController < Projects::ApplicationController
push_frontend_feature_flag(:release_asset_link_type, project, default_enabled: true)
end
before_action :authorize_update_release!, only: %i[edit update]
+ before_action :authorize_create_release!, only: :new
def index
respond_to do |format|
@@ -25,11 +26,11 @@ class Projects::ReleasesController < Projects::ApplicationController
def show
return render_404 unless Feature.enabled?(:release_show_page, project, default_enabled: true)
+ end
- respond_to do |format|
- format.html do
- render :show
- end
+ def new
+ unless Feature.enabled?(:new_release_page, project)
+ redirect_to(new_project_tag_path(@project))
end
end
@@ -37,22 +38,12 @@ class Projects::ReleasesController < Projects::ApplicationController
redirect_to link.url
end
- protected
+ private
def releases
ReleasesFinder.new(@project, current_user).execute
end
- def edit
- respond_to do |format|
- format.html do
- render :edit
- end
- end
- end
-
- private
-
def authorize_update_release!
access_denied! unless can?(current_user, :update_release, release)
end
diff --git a/app/controllers/projects/service_desk_controller.rb b/app/controllers/projects/service_desk_controller.rb
new file mode 100644
index 00000000000..bcd190bbc2c
--- /dev/null
+++ b/app/controllers/projects/service_desk_controller.rb
@@ -0,0 +1,45 @@
+# frozen_string_literal: true
+
+class Projects::ServiceDeskController < Projects::ApplicationController
+ before_action :authorize_admin_project!
+
+ def show
+ json_response
+ end
+
+ def update
+ Projects::UpdateService.new(project, current_user, { service_desk_enabled: params[:service_desk_enabled] }).execute
+
+ result = ServiceDeskSettings::UpdateService.new(project, current_user, setting_params).execute
+
+ if result[:status] == :success
+ json_response
+ else
+ render json: { message: result[:message] }, status: :unprocessable_entity
+ end
+ end
+
+ private
+
+ def setting_params
+ params.permit(:issue_template_key, :outgoing_name, :project_key)
+ end
+
+ def json_response
+ respond_to do |format|
+ service_desk_settings = project.service_desk_setting
+
+ service_desk_attributes =
+ {
+ service_desk_address: project.service_desk_address,
+ service_desk_enabled: project.service_desk_enabled,
+ issue_template_key: service_desk_settings&.issue_template_key,
+ template_file_missing: service_desk_settings&.issue_template_missing?,
+ outgoing_name: service_desk_settings&.outgoing_name,
+ project_key: service_desk_settings&.project_key
+ }
+
+ format.json { render json: service_desk_attributes }
+ end
+ end
+end
diff --git a/app/controllers/projects/services_controller.rb b/app/controllers/projects/services_controller.rb
index 710ad546e64..6b7e253595c 100644
--- a/app/controllers/projects/services_controller.rb
+++ b/app/controllers/projects/services_controller.rb
@@ -12,7 +12,8 @@ class Projects::ServicesController < Projects::ApplicationController
before_action :set_deprecation_notice_for_prometheus_service, only: [:edit, :update]
before_action :redirect_deprecated_prometheus_service, only: [:update]
before_action only: :edit do
- push_frontend_feature_flag(:integration_form_refactor)
+ push_frontend_feature_flag(:integration_form_refactor, default_enabled: true)
+ push_frontend_feature_flag(:jira_issues_integration, @project, { default_enabled: true })
end
respond_to :html
@@ -20,17 +21,19 @@ class Projects::ServicesController < Projects::ApplicationController
layout "project_settings"
def edit
+ @admin_integration = Service.instance_for(service.type)
end
def update
@service.attributes = service_params[:service]
+ @service.inherit_from_id = nil if service_params[:service][:inherit_from_id].blank?
saved = @service.save(context: :manual_change)
respond_to do |format|
format.html do
if saved
- target_url = safe_redirect_path(params[:redirect_to]).presence || project_settings_integrations_path(@project)
+ target_url = safe_redirect_path(params[:redirect_to]).presence || edit_project_service_path(@project, @service)
redirect_to target_url, notice: success_message
else
render 'edit'
@@ -60,7 +63,7 @@ class Projects::ServicesController < Projects::ApplicationController
return { error: true, message: _('Validations failed.'), service_response: @service.errors.full_messages.join(','), test_failed: false }
end
- result = Integrations::Test::ProjectService.new(@service, current_user, params[:event]).execute
+ result = ::Integrations::Test::ProjectService.new(@service, current_user, params[:event]).execute
unless result[:success]
return { error: true, message: _('Test failed.'), service_response: result[:message].to_s, test_failed: true }
diff --git a/app/controllers/projects/settings/operations_controller.rb b/app/controllers/projects/settings/operations_controller.rb
index c2292511e0f..d7a6f1b0139 100644
--- a/app/controllers/projects/settings/operations_controller.rb
+++ b/app/controllers/projects/settings/operations_controller.rb
@@ -6,13 +6,13 @@ module Projects
before_action :authorize_admin_operations!
before_action :authorize_read_prometheus_alerts!, only: [:reset_alerting_token]
- respond_to :json, only: [:reset_alerting_token]
+ before_action do
+ push_frontend_feature_flag(:pagerduty_webhook, project)
+ end
- helper_method :error_tracking_setting
+ respond_to :json, only: [:reset_alerting_token, :reset_pagerduty_token]
- def show
- render locals: { prometheus_service: prometheus_service }
- end
+ helper_method :error_tracking_setting
def update
result = ::Projects::Operations::UpdateService.new(project, current_user, update_params).execute
@@ -42,14 +42,29 @@ module Projects
end
end
+ def reset_pagerduty_token
+ result = ::Projects::Operations::UpdateService
+ .new(project, current_user, pagerduty_token_params)
+ .execute
+
+ if result[:status] == :success
+ pagerduty_token = project.incident_management_setting&.pagerduty_token
+ webhook_url = project_incidents_pagerduty_url(project, token: pagerduty_token)
+
+ render json: { pagerduty_webhook_url: webhook_url, pagerduty_token: pagerduty_token }
+ else
+ render json: {}, status: :unprocessable_entity
+ end
+ end
+
private
def alerting_params
{ alerting_setting_attributes: { regenerate_token: true } }
end
- def prometheus_service
- project.find_or_initialize_service(::PrometheusService.to_param)
+ def pagerduty_token_params
+ { incident_management_setting_attributes: { regenerate_token: true } }
end
def render_update_response(result)
diff --git a/app/controllers/projects/snippets/blobs_controller.rb b/app/controllers/projects/snippets/blobs_controller.rb
new file mode 100644
index 00000000000..148fc7c96f8
--- /dev/null
+++ b/app/controllers/projects/snippets/blobs_controller.rb
@@ -0,0 +1,5 @@
+# frozen_string_literal: true
+
+class Projects::Snippets::BlobsController < Projects::Snippets::ApplicationController
+ include Snippets::BlobsActions
+end
diff --git a/app/controllers/projects/snippets_controller.rb b/app/controllers/projects/snippets_controller.rb
index 5ee6abef804..49840e847f2 100644
--- a/app/controllers/projects/snippets_controller.rb
+++ b/app/controllers/projects/snippets_controller.rb
@@ -15,11 +15,11 @@ class Projects::SnippetsController < Projects::Snippets::ApplicationController
before_action :authorize_admin_snippet!, only: [:destroy]
def index
- @snippet_counts = Snippets::CountService
+ @snippet_counts = ::Snippets::CountService
.new(current_user, project: @project)
.execute
- @snippets = SnippetsFinder.new(current_user, project: @project, scope: params[:scope])
+ @snippets = SnippetsFinder.new(current_user, project: @project, scope: params[:scope], sort: sort_param)
.execute
.page(params[:page])
.inc_author
@@ -35,7 +35,7 @@ class Projects::SnippetsController < Projects::Snippets::ApplicationController
def create
create_params = snippet_params.merge(spammable_params)
- service_response = Snippets::CreateService.new(project, current_user, create_params).execute
+ service_response = ::Snippets::CreateService.new(project, current_user, create_params).execute
@snippet = service_response.payload[:snippet]
handle_repository_error(:new)
diff --git a/app/controllers/projects/stages_controller.rb b/app/controllers/projects/stages_controller.rb
deleted file mode 100644
index c8db5b1277f..00000000000
--- a/app/controllers/projects/stages_controller.rb
+++ /dev/null
@@ -1,25 +0,0 @@
-# frozen_string_literal: true
-
-class Projects::StagesController < Projects::PipelinesController
- before_action :authorize_update_pipeline!
-
- def play_manual
- ::Ci::PlayManualStageService
- .new(@project, current_user, pipeline: pipeline)
- .execute(stage)
-
- respond_to do |format|
- format.json do
- render json: StageSerializer
- .new(project: @project, current_user: @current_user)
- .represent(stage)
- end
- end
- end
-
- private
-
- def stage
- @pipeline_stage ||= pipeline.find_stage_by_name!(params[:stage_name])
- end
-end
diff --git a/app/controllers/projects/static_site_editor_controller.rb b/app/controllers/projects/static_site_editor_controller.rb
index 74f28c3da67..9ec50ff8196 100644
--- a/app/controllers/projects/static_site_editor_controller.rb
+++ b/app/controllers/projects/static_site_editor_controller.rb
@@ -9,6 +9,9 @@ class Projects::StaticSiteEditorController < Projects::ApplicationController
prepend_before_action :authenticate_user!, only: [:show]
before_action :assign_ref_and_path, only: [:show]
before_action :authorize_edit_tree!, only: [:show]
+ before_action do
+ push_frontend_feature_flag(:sse_image_uploads)
+ end
def show
@config = Gitlab::StaticSiteEditor::Config.new(@repository, @ref, @path, params[:return_url])
diff --git a/app/controllers/projects/tree_controller.rb b/app/controllers/projects/tree_controller.rb
index 9cb345724cc..638e1a05c18 100644
--- a/app/controllers/projects/tree_controller.rb
+++ b/app/controllers/projects/tree_controller.rb
@@ -15,26 +15,14 @@ class Projects::TreeController < Projects::ApplicationController
before_action :authorize_download_code!
before_action :authorize_edit_tree!, only: [:create_dir]
- before_action only: [:show] do
- push_frontend_feature_flag(:vue_file_list_lfs_badge, default_enabled: true)
- end
-
def show
- return render_404 unless @repository.commit(@ref)
+ return render_404 unless @commit
if tree.entries.empty?
if @repository.blob_at(@commit.id, @path)
- return redirect_to project_blob_path(@project, File.join(@ref, @path))
+ redirect_to project_blob_path(@project, File.join(@ref, @path))
elsif @path.present?
- return redirect_to_tree_root_for_missing_path(@project, @ref, @path)
- end
- end
-
- respond_to do |format|
- format.html do
- lfs_blob_ids if Feature.disabled?(:vue_file_list, @project, default_enabled: true)
-
- @last_commit = @repository.last_commit_for_path(@commit.id, @tree.path) || @commit
+ redirect_to_tree_root_for_missing_path(@project, @ref, @path)
end
end
end
diff --git a/app/controllers/projects/variables_controller.rb b/app/controllers/projects/variables_controller.rb
index 1dffc57fcf0..2cc030d18fc 100644
--- a/app/controllers/projects/variables_controller.rb
+++ b/app/controllers/projects/variables_controller.rb
@@ -6,7 +6,7 @@ class Projects::VariablesController < Projects::ApplicationController
def show
respond_to do |format|
format.json do
- render status: :ok, json: { variables: VariableSerializer.new.represent(@project.variables) }
+ render status: :ok, json: { variables: ::Ci::VariableSerializer.new.represent(@project.variables) }
end
end
end
@@ -26,7 +26,7 @@ class Projects::VariablesController < Projects::ApplicationController
private
def render_variables
- render status: :ok, json: { variables: VariableSerializer.new.represent(@project.variables) }
+ render status: :ok, json: { variables: ::Ci::VariableSerializer.new.represent(@project.variables) }
end
def render_error
diff --git a/app/controllers/projects/wikis_controller.rb b/app/controllers/projects/wikis_controller.rb
index 85e643aa212..d0aa733cadb 100644
--- a/app/controllers/projects/wikis_controller.rb
+++ b/app/controllers/projects/wikis_controller.rb
@@ -2,7 +2,6 @@
class Projects::WikisController < Projects::ApplicationController
include WikiActions
- include PreviewMarkdown
alias_method :container, :project
diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb
index f0ddd62e996..a5666cb70ac 100644
--- a/app/controllers/projects_controller.rb
+++ b/app/controllers/projects_controller.rb
@@ -8,6 +8,7 @@ class ProjectsController < Projects::ApplicationController
include SendFileUpload
include RecordUserLastActivity
include ImportUrlParams
+ include FiltersEvents
prepend_before_action(only: [:show]) { authenticate_sessionless_user!(:rss) }
@@ -21,7 +22,6 @@ class ProjectsController < Projects::ApplicationController
before_action :assign_ref_vars, if: -> { action_name == 'show' && repo_exists? }
before_action :tree,
if: -> { action_name == 'show' && repo_exists? && project_view_files? }
- before_action :lfs_blob_ids, if: :show_blob_ids?, only: :show
before_action :project_export_enabled, only: [:export, :download_export, :remove_export, :generate_new_export]
before_action :present_project, only: [:edit]
before_action :authorize_download_code!, only: [:refs]
@@ -38,6 +38,7 @@ class ProjectsController < Projects::ApplicationController
before_action only: [:new, :create] do
frontend_experimentation_tracking_data(:new_create_project_ui, 'click_tab')
push_frontend_feature_flag(:new_create_project_ui) if experiment_enabled?(:new_create_project_ui)
+ push_frontend_feature_flag(:service_desk_custom_address, @project)
end
layout :determine_layout
@@ -301,10 +302,6 @@ class ProjectsController < Projects::ApplicationController
private
- def show_blob_ids?
- repo_exists? && project_view_files? && Feature.disabled?(:vue_file_list, @project, default_enabled: true)
- end
-
# Render project landing depending of which features are available
# So if page is not available in the list it renders the next page
#
@@ -395,6 +392,7 @@ class ProjectsController < Projects::ApplicationController
:initialize_with_readme,
:autoclose_referenced_issues,
:suggestion_commit_message,
+ :service_desk_enabled,
project_feature_attributes: %i[
builds_access_level
@@ -409,6 +407,7 @@ class ProjectsController < Projects::ApplicationController
],
project_setting_attributes: %i[
show_default_award_emojis
+ squash_option
]
]
end
diff --git a/app/controllers/registrations/experience_levels_controller.rb b/app/controllers/registrations/experience_levels_controller.rb
index 515d6b3f9aa..97239b1bbac 100644
--- a/app/controllers/registrations/experience_levels_controller.rb
+++ b/app/controllers/registrations/experience_levels_controller.rb
@@ -33,12 +33,13 @@ module Registrations
def hide_advanced_issues
return unless current_user.user_preference.novice?
+ return unless learn_gitlab.available?
- settings = cookies[:onboarding_issues_settings]
- return unless settings
+ Boards::UpdateService.new(learn_gitlab.project, current_user, label_ids: [learn_gitlab.label.id]).execute(learn_gitlab.board)
+ end
- modified_settings = Gitlab::Json.parse(settings).merge(hideAdvanced: true)
- cookies[:onboarding_issues_settings] = modified_settings.to_json
+ def learn_gitlab
+ @learn_gitlab ||= LearnGitlab.new(current_user)
end
end
end
diff --git a/app/controllers/registrations_controller.rb b/app/controllers/registrations_controller.rb
index 6ab2924a8b5..b1c1fe3ba74 100644
--- a/app/controllers/registrations_controller.rb
+++ b/app/controllers/registrations_controller.rb
@@ -64,8 +64,8 @@ class RegistrationsController < Devise::RegistrationsController
if result[:status] == :success
track_experiment_event(:signup_flow, 'end') # We want this event to be tracked when the user is _in_ the experimental group
- track_experiment_event(:onboarding_issues, 'signed_up') if ::Gitlab.com? && !helpers.in_subscription_flow? && !helpers.in_invitation_flow?
- return redirect_to new_users_sign_up_group_path if experiment_enabled?(:onboarding_issues) && !helpers.in_subscription_flow? && !helpers.in_invitation_flow?
+ track_experiment_event(:onboarding_issues, 'signed_up') if ::Gitlab.com? && show_onboarding_issues_experiment?
+ return redirect_to new_users_sign_up_group_path if experiment_enabled?(:onboarding_issues) && show_onboarding_issues_experiment?
set_flash_message! :notice, :signed_up
redirect_to path_for_signed_in_user(current_user)
@@ -210,6 +210,10 @@ class RegistrationsController < Devise::RegistrationsController
'devise'
end
end
+
+ def show_onboarding_issues_experiment?
+ !helpers.in_subscription_flow? && !helpers.in_invitation_flow? && !helpers.in_oauth_flow?
+ end
end
RegistrationsController.prepend_if_ee('EE::RegistrationsController')
diff --git a/app/controllers/root_controller.rb b/app/controllers/root_controller.rb
index 24452f9a188..14469877e14 100644
--- a/app/controllers/root_controller.rb
+++ b/app/controllers/root_controller.rb
@@ -13,10 +13,15 @@ class RootController < Dashboard::ProjectsController
before_action :redirect_unlogged_user, if: -> { current_user.nil? }
before_action :redirect_logged_user, if: -> { current_user.present? }
+ # We only need to load the projects when the user is logged in but did not
+ # configure a dashboard. In which case we render projects. We can do that straight
+ # from the #index action.
+ skip_before_action :projects
def index
# n+1: https://gitlab.com/gitlab-org/gitlab-foss/issues/40260
Gitlab::GitalyClient.allow_n_plus_1_calls do
+ projects
super
end
end
diff --git a/app/controllers/search_controller.rb b/app/controllers/search_controller.rb
index 217f08dd648..ff6d9350a5c 100644
--- a/app/controllers/search_controller.rb
+++ b/app/controllers/search_controller.rb
@@ -51,6 +51,21 @@ class SearchController < ApplicationController
render json: { count: count }
end
+ # rubocop: disable CodeReuse/ActiveRecord
+ def autocomplete
+ term = params[:term]
+
+ if params[:project_id].present?
+ @project = Project.find_by(id: params[:project_id])
+ @project = nil unless can?(current_user, :read_project, @project)
+ end
+
+ @ref = params[:project_ref] if params[:project_ref].present?
+
+ render json: search_autocomplete_opts(term).to_json
+ end
+ # rubocop: enable CodeReuse/ActiveRecord
+
private
def preload_method
diff --git a/app/controllers/snippets/blobs_controller.rb b/app/controllers/snippets/blobs_controller.rb
new file mode 100644
index 00000000000..d7c4bbcf8f2
--- /dev/null
+++ b/app/controllers/snippets/blobs_controller.rb
@@ -0,0 +1,7 @@
+# frozen_string_literal: true
+
+class Snippets::BlobsController < Snippets::ApplicationController
+ include Snippets::BlobsActions
+
+ skip_before_action :authenticate_user!, only: [:raw]
+end
diff --git a/app/controllers/snippets_controller.rb b/app/controllers/snippets_controller.rb
index 87d87390e57..e68b821459d 100644
--- a/app/controllers/snippets_controller.rb
+++ b/app/controllers/snippets_controller.rb
@@ -21,7 +21,7 @@ class SnippetsController < Snippets::ApplicationController
if params[:username].present?
@user = UserFinder.new(params[:username]).find_by_username!
- @snippets = SnippetsFinder.new(current_user, author: @user, scope: params[:scope])
+ @snippets = SnippetsFinder.new(current_user, author: @user, scope: params[:scope], sort: sort_param)
.execute
.page(params[:page])
.inc_author
diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb
index 5ee97885071..95ea31fa977 100644
--- a/app/controllers/users_controller.rb
+++ b/app/controllers/users_controller.rb
@@ -3,6 +3,7 @@
class UsersController < ApplicationController
include RoutableActions
include RendersMemberAccess
+ include RendersProjectsList
include ControllerWithCrossProjectAccessCheck
include Gitlab::NoteableMetadata
@@ -36,6 +37,12 @@ class UsersController < ApplicationController
end
end
+ # Get all keys of a user(params[:username]) in a text format
+ # Helpful for sysadmins to put in respective servers
+ def ssh_keys
+ render plain: user.all_ssh_keys.join("\n")
+ end
+
def activity
respond_to do |format|
format.html { render 'show' }