diff options
Diffstat (limited to 'app/controllers')
73 files changed, 431 insertions, 223 deletions
diff --git a/app/controllers/admin/application_settings_controller.rb b/app/controllers/admin/application_settings_controller.rb index 73f71f7ad55..c05153921fe 100644 --- a/app/controllers/admin/application_settings_controller.rb +++ b/app/controllers/admin/application_settings_controller.rb @@ -2,6 +2,7 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController include InternalRedirect + include ServicesHelper # NOTE: Use @application_setting in this controller when you need to access # application_settings after it has been modified. This is because the @@ -32,6 +33,8 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController end def integrations + return not_found unless instance_level_integrations? + @integrations = Service.find_or_initialize_all(Service.for_instance).sort_by(&:title) end diff --git a/app/controllers/admin/integrations_controller.rb b/app/controllers/admin/integrations_controller.rb index 1e2a99f7078..003a5d427f5 100644 --- a/app/controllers/admin/integrations_controller.rb +++ b/app/controllers/admin/integrations_controller.rb @@ -2,6 +2,7 @@ class Admin::IntegrationsController < Admin::ApplicationController include IntegrationsActions + include ServicesHelper private @@ -10,7 +11,7 @@ class Admin::IntegrationsController < Admin::ApplicationController end def integrations_enabled? - true + instance_level_integrations? end def scoped_edit_integration_path(integration) diff --git a/app/controllers/admin/runners_controller.rb b/app/controllers/admin/runners_controller.rb index 7a377a33d41..ba7e7d57b91 100644 --- a/app/controllers/admin/runners_controller.rb +++ b/app/controllers/admin/runners_controller.rb @@ -1,7 +1,9 @@ # frozen_string_literal: true class Admin::RunnersController < Admin::ApplicationController - before_action :runner, except: [:index, :tag_list] + include RunnerSetupScripts + + before_action :runner, except: [:index, :tag_list, :runner_setup_scripts] def index finder = Ci::RunnersFinder.new(current_user: current_user, params: params) @@ -53,6 +55,10 @@ class Admin::RunnersController < Admin::ApplicationController render json: ActsAsTaggableOn::TagSerializer.new.represent(tags) end + def runner_setup_scripts + private_runner_setup_scripts + end + private def runner diff --git a/app/controllers/admin/sessions_controller.rb b/app/controllers/admin/sessions_controller.rb index 0c0bbaf4d93..e0bee6f48ea 100644 --- a/app/controllers/admin/sessions_controller.rb +++ b/app/controllers/admin/sessions_controller.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true class Admin::SessionsController < ApplicationController - include Authenticates2FAForAdminMode + include AuthenticatesWithTwoFactorForAdminMode include InternalRedirect include RendersLdapServers diff --git a/app/controllers/admin/users_controller.rb b/app/controllers/admin/users_controller.rb index e19b09e1324..7f7a82a3032 100644 --- a/app/controllers/admin/users_controller.rb +++ b/app/controllers/admin/users_controller.rb @@ -10,6 +10,7 @@ class Admin::UsersController < Admin::ApplicationController def index @users = User.filter_items(params[:filter]).order_name_asc @users = @users.search_with_secondary_emails(params[:search_query]) if params[:search_query].present? + @users = @users.includes(:authorized_projects) # rubocop: disable CodeReuse/ActiveRecord @users = @users.sort_by_attribute(@sort = params[:sort]) @users = @users.page(params[:page]) end diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 5f05337e59e..e71652faa27 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -484,7 +484,7 @@ class ApplicationController < ActionController::Base def set_page_title_header # Per https://tools.ietf.org/html/rfc5987, headers need to be ISO-8859-1, not UTF-8 - response.headers['Page-Title'] = URI.escape(page_title('GitLab')) + response.headers['Page-Title'] = Addressable::URI.encode_component(page_title('GitLab')) end def set_current_admin(&block) diff --git a/app/controllers/boards/issues_controller.rb b/app/controllers/boards/issues_controller.rb index a18c80b996e..f5a9b9b61db 100644 --- a/app/controllers/boards/issues_controller.rb +++ b/app/controllers/boards/issues_controller.rb @@ -21,6 +21,8 @@ module Boards before_action :validate_id_list, only: [:bulk_move] before_action :can_move_issues?, only: [:bulk_move] + feature_category :boards + def index list_service = Boards::Issues::ListService.new(board_parent, current_user, filter_params) issues = issues_from(list_service) diff --git a/app/controllers/boards/lists_controller.rb b/app/controllers/boards/lists_controller.rb index 0b8469e8290..aecd287370f 100644 --- a/app/controllers/boards/lists_controller.rb +++ b/app/controllers/boards/lists_controller.rb @@ -8,6 +8,8 @@ module Boards before_action :authorize_read_list, only: [:index] skip_before_action :authenticate_user!, only: [:index] + feature_category :boards + def index lists = Boards::Lists::ListService.new(board.resource_parent, current_user).execute(board) @@ -42,7 +44,7 @@ module Boards list = board.lists.destroyable.find(params[:id]) service = Boards::Lists::DestroyService.new(board_parent, current_user) - if service.execute(list) + if service.execute(list).success? head :ok else head :unprocessable_entity diff --git a/app/controllers/clusters/clusters_controller.rb b/app/controllers/clusters/clusters_controller.rb index 7006c23321c..52719e90e04 100644 --- a/app/controllers/clusters/clusters_controller.rb +++ b/app/controllers/clusters/clusters_controller.rb @@ -180,13 +180,20 @@ class Clusters::ClustersController < Clusters::BaseController params.permit(:cleanup) end + def base_permitted_cluster_params + [ + :enabled, + :environment_scope, + :managed, + :namespace_per_environment + ] + end + def update_params if cluster.provided_by_user? params.require(:cluster).permit( - :enabled, + *base_permitted_cluster_params, :name, - :environment_scope, - :managed, :base_domain, :management_project_id, platform_kubernetes_attributes: [ @@ -198,9 +205,7 @@ class Clusters::ClustersController < Clusters::BaseController ) else params.require(:cluster).permit( - :enabled, - :environment_scope, - :managed, + *base_permitted_cluster_params, :base_domain, :management_project_id, platform_kubernetes_attributes: [ @@ -212,10 +217,8 @@ class Clusters::ClustersController < Clusters::BaseController def create_gcp_cluster_params params.require(:cluster).permit( - :enabled, + *base_permitted_cluster_params, :name, - :environment_scope, - :managed, provider_gcp_attributes: [ :gcp_project_id, :zone, @@ -232,10 +235,8 @@ class Clusters::ClustersController < Clusters::BaseController def create_aws_cluster_params params.require(:cluster).permit( - :enabled, + *base_permitted_cluster_params, :name, - :environment_scope, - :managed, provider_aws_attributes: [ :kubernetes_version, :key_name, @@ -255,10 +256,8 @@ class Clusters::ClustersController < Clusters::BaseController def create_user_cluster_params params.require(:cluster).permit( - :enabled, + *base_permitted_cluster_params, :name, - :environment_scope, - :managed, platform_kubernetes_attributes: [ :namespace, :api_url, diff --git a/app/controllers/concerns/authenticates_with_two_factor.rb b/app/controllers/concerns/authenticates_with_two_factor.rb index 9ff97f398f5..5c74d79951f 100644 --- a/app/controllers/concerns/authenticates_with_two_factor.rb +++ b/app/controllers/concerns/authenticates_with_two_factor.rb @@ -89,10 +89,7 @@ module AuthenticatesWithTwoFactor user.save! sign_in(user, message: :two_factor_authenticated, event: :authentication) else - user.increment_failed_attempts! - Gitlab::AppLogger.info("Failed Login: user=#{user.username} ip=#{request.remote_ip} method=OTP") - flash.now[:alert] = _('Invalid two-factor code.') - prompt_for_two_factor(user) + handle_two_factor_failure(user, 'OTP', _('Invalid two-factor code.')) end end @@ -101,7 +98,7 @@ module AuthenticatesWithTwoFactor if U2fRegistration.authenticate(user, u2f_app_id, user_params[:device_response], session[:challenge]) handle_two_factor_success(user) else - handle_two_factor_failure(user, 'U2F') + handle_two_factor_failure(user, 'U2F', _('Authentication via U2F device failed.')) end end @@ -109,7 +106,7 @@ module AuthenticatesWithTwoFactor if Webauthn::AuthenticateService.new(user, user_params[:device_response], session[:challenge]).execute handle_two_factor_success(user) else - handle_two_factor_failure(user, 'WebAuthn') + handle_two_factor_failure(user, 'WebAuthn', _('Authentication via WebAuthn device failed.')) end end @@ -152,13 +149,19 @@ module AuthenticatesWithTwoFactor sign_in(user, message: :two_factor_authenticated, event: :authentication) end - def handle_two_factor_failure(user, method) + def handle_two_factor_failure(user, method, message) user.increment_failed_attempts! + log_failed_two_factor(user, method, request.remote_ip) + Gitlab::AppLogger.info("Failed Login: user=#{user.username} ip=#{request.remote_ip} method=#{method}") - flash.now[:alert] = _('Authentication via %{method} device failed.') % { method: method } + flash.now[:alert] = message prompt_for_two_factor(user) end + def log_failed_two_factor(user, method, ip_address) + # overridden in EE + end + def handle_changed_user(user) clear_two_factor_attempt! @@ -173,3 +176,5 @@ module AuthenticatesWithTwoFactor Digest::SHA256.hexdigest(user.encrypted_password) != session[:user_password_hash] end end + +AuthenticatesWithTwoFactor.prepend_if_ee('EE::AuthenticatesWithTwoFactor') diff --git a/app/controllers/admin/concerns/authenticates_2fa_for_admin_mode.rb b/app/controllers/concerns/authenticates_with_two_factor_for_admin_mode.rb index 03783cd75a3..a8155f1e639 100644 --- a/app/controllers/admin/concerns/authenticates_2fa_for_admin_mode.rb +++ b/app/controllers/concerns/authenticates_with_two_factor_for_admin_mode.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -module Authenticates2FAForAdminMode +module AuthenticatesWithTwoFactorForAdminMode extend ActiveSupport::Concern included do @@ -52,11 +52,7 @@ module Authenticates2FAForAdminMode # The admin user has successfully passed 2fa, enable admin mode ignoring password enable_admin_mode else - user.increment_failed_attempts! - Gitlab::AppLogger.info("Failed Admin Mode Login: user=#{user.username} ip=#{request.remote_ip} method=OTP") - flash.now[:alert] = _('Invalid two-factor code.') - - admin_mode_prompt_for_two_factor(user) + admin_handle_two_factor_failure(user, 'OTP', _('Invalid two-factor code.')) end end @@ -64,7 +60,7 @@ module Authenticates2FAForAdminMode if U2fRegistration.authenticate(user, u2f_app_id, user_params[:device_response], session[:challenge]) admin_handle_two_factor_success else - admin_handle_two_factor_failure(user, 'U2F') + admin_handle_two_factor_failure(user, 'U2F', _('Authentication via U2F device failed.')) end end @@ -72,7 +68,7 @@ module Authenticates2FAForAdminMode if Webauthn::AuthenticateService.new(user, user_params[:device_response], session[:challenge]).execute admin_handle_two_factor_success else - admin_handle_two_factor_failure(user, 'WebAuthn') + admin_handle_two_factor_failure(user, 'WebAuthn', _('Authentication via WebAuthn device failed.')) end end @@ -100,11 +96,12 @@ module Authenticates2FAForAdminMode enable_admin_mode end - def admin_handle_two_factor_failure(user, method) + def admin_handle_two_factor_failure(user, method, message) user.increment_failed_attempts! - Gitlab::AppLogger.info("Failed Admin Mode Login: user=#{user.username} ip=#{request.remote_ip} method=#{method}") - flash.now[:alert] = _('Authentication via %{method} device failed.') % { method: method } + log_failed_two_factor(user, method, request.remote_ip) + Gitlab::AppLogger.info("Failed Admin Mode Login: user=#{user.username} ip=#{request.remote_ip} method=#{method}") + flash.now[:alert] = message admin_mode_prompt_for_two_factor(user) end end diff --git a/app/controllers/concerns/boards_actions.rb b/app/controllers/concerns/boards_actions.rb index 9d40b9e8c88..b382e338a78 100644 --- a/app/controllers/concerns/boards_actions.rb +++ b/app/controllers/concerns/boards_actions.rb @@ -9,7 +9,7 @@ module BoardsActions before_action :boards, only: :index before_action :board, only: :show - before_action :push_wip_limits, only: [:index, :show] + before_action :push_licensed_features, only: [:index, :show] before_action do push_frontend_feature_flag(:not_issuable_queries, parent, default_enabled: true) end @@ -29,7 +29,7 @@ module BoardsActions private # Noop on FOSS - def push_wip_limits + def push_licensed_features end def boards diff --git a/app/controllers/concerns/controller_with_feature_category.rb b/app/controllers/concerns/controller_with_feature_category.rb index f8985cf0950..c1ff9ef2e69 100644 --- a/app/controllers/concerns/controller_with_feature_category.rb +++ b/app/controllers/concerns/controller_with_feature_category.rb @@ -5,35 +5,38 @@ module ControllerWithFeatureCategory include Gitlab::ClassAttributes class_methods do - def feature_category(category, config = {}) - validate_config!(config) + def feature_category(category, actions = []) + feature_category_configuration[category] ||= [] + feature_category_configuration[category] += actions.map(&:to_s) - 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) + validate_config!(feature_category_configuration) end def feature_category_for_action(action) - category_config = feature_category_configuration.find { |config| config.matches?(action) } + category_config = feature_category_configuration.find do |_, actions| + actions.empty? || actions.include?(action) + end - category_config&.category || superclass_feature_category_for_action(action) + category_config&.first || 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} " + empty = config.find { |_, actions| actions.empty? } + duplicate_actions = config.values.flatten.group_by(&:itself).select { |_, v| v.count > 1 }.keys + + if config.length > 1 && empty + raise ArgumentError, "#{empty.first} is defined for all actions, but other categories are set" end - if config.key?(:only) && config.key?(:except) - raise ArgumentError, "cannot configure both `only` and `except`" + if duplicate_actions.any? + raise ArgumentError, "Actions have multiple feature categories: #{duplicate_actions.join(', ')}" end end def feature_category_configuration - class_attributes[:feature_category_config] ||= [] + class_attributes[:feature_category_config] ||= {} end def superclass_feature_category_for_action(action) diff --git a/app/controllers/concerns/controller_with_feature_category/config.rb b/app/controllers/concerns/controller_with_feature_category/config.rb deleted file mode 100644 index 624691ee4f6..00000000000 --- a/app/controllers/concerns/controller_with_feature_category/config.rb +++ /dev/null @@ -1,38 +0,0 @@ -# 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/enforces_two_factor_authentication.rb b/app/controllers/concerns/enforces_two_factor_authentication.rb index 02082f81598..bf38e4ad117 100644 --- a/app/controllers/concerns/enforces_two_factor_authentication.rb +++ b/app/controllers/concerns/enforces_two_factor_authentication.rb @@ -11,7 +11,7 @@ module EnforcesTwoFactorAuthentication extend ActiveSupport::Concern included do - before_action :check_two_factor_requirement + before_action :check_two_factor_requirement, except: [:route_not_found] # to include this in controllers inheriting from `ActionController::Metal` # we need to add this block diff --git a/app/controllers/concerns/integrations_actions.rb b/app/controllers/concerns/integrations_actions.rb index 6060dc729af..39f63bbaaec 100644 --- a/app/controllers/concerns/integrations_actions.rb +++ b/app/controllers/concerns/integrations_actions.rb @@ -20,7 +20,7 @@ module IntegrationsActions respond_to do |format| format.html do if saved - PropagateIntegrationWorker.perform_async(integration.id, false) + PropagateIntegrationWorker.perform_async(integration.id) redirect_to scoped_edit_integration_path(integration), notice: success_message else render 'shared/integrations/edit' diff --git a/app/controllers/concerns/issuable_collections_action.rb b/app/controllers/concerns/issuable_collections_action.rb index e3ac117660b..7ed66027da3 100644 --- a/app/controllers/concerns/issuable_collections_action.rb +++ b/app/controllers/concerns/issuable_collections_action.rb @@ -59,6 +59,9 @@ module IssuableCollectionsAction end def finder_options - super.merge(non_archived: true) + super.merge( + non_archived: true, + issue_types: Issue::TYPES_FOR_LIST + ) end end diff --git a/app/controllers/concerns/milestone_actions.rb b/app/controllers/concerns/milestone_actions.rb index 29138e7b014..6470c75dfbd 100644 --- a/app/controllers/concerns/milestone_actions.rb +++ b/app/controllers/concerns/milestone_actions.rb @@ -3,13 +3,25 @@ module MilestoneActions extend ActiveSupport::Concern + def issues + respond_to do |format| + format.html { redirect_to milestone_redirect_path } + format.json do + render json: tabs_json("shared/milestones/_issues_tab", { + issues: @milestone.sorted_issues(current_user), # rubocop:disable Gitlab/ModuleWithInstanceVariables + show_project_name: Gitlab::Utils.to_boolean(params[:show_project_name]) + }) + end + end + end + def merge_requests respond_to do |format| format.html { redirect_to milestone_redirect_path } format.json do render json: tabs_json("shared/milestones/_merge_requests_tab", { merge_requests: @milestone.sorted_merge_requests(current_user), # rubocop:disable Gitlab/ModuleWithInstanceVariables - show_project_name: true + show_project_name: Gitlab::Utils.to_boolean(params[:show_project_name]) }) end end diff --git a/app/controllers/concerns/multiple_boards_actions.rb b/app/controllers/concerns/multiple_boards_actions.rb index 95a6800f55c..370b8c72bfe 100644 --- a/app/controllers/concerns/multiple_boards_actions.rb +++ b/app/controllers/concerns/multiple_boards_actions.rb @@ -21,11 +21,13 @@ module MultipleBoardsActions end def create - board = Boards::CreateService.new(parent, current_user, board_params).execute + response = Boards::CreateService.new(parent, current_user, board_params).execute respond_to do |format| format.json do - if board.persisted? + board = response.payload + + if response.success? extra_json = { board_path: board_path(board) } render json: serialize_as_json(board).merge(extra_json) else diff --git a/app/controllers/concerns/redis_tracking.rb b/app/controllers/concerns/redis_tracking.rb index fa5eef981d1..fdd22cc0da0 100644 --- a/app/controllers/concerns/redis_tracking.rb +++ b/app/controllers/concerns/redis_tracking.rb @@ -26,7 +26,6 @@ module RedisTracking def track_unique_redis_hll_event(event_name, feature, feature_default_enabled) return unless metric_feature_enabled?(feature, feature_default_enabled) - return unless Gitlab::CurrentSettings.usage_ping_enabled? return unless visitor_id Gitlab::UsageDataCounters::HLLRedisCounter.track_event(visitor_id, event_name) diff --git a/app/controllers/concerns/runner_setup_scripts.rb b/app/controllers/concerns/runner_setup_scripts.rb new file mode 100644 index 00000000000..c0e657a32d1 --- /dev/null +++ b/app/controllers/concerns/runner_setup_scripts.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +module RunnerSetupScripts + extend ActiveSupport::Concern + + private + + def private_runner_setup_scripts(**kwargs) + instructions = Gitlab::Ci::RunnerInstructions.new(current_user: current_user, os: script_params[:os], arch: script_params[:arch], **kwargs) + output = { + install: instructions.install_script, + register: instructions.register_command + } + + if instructions.errors.any? + render json: { errors: instructions.errors }, status: :bad_request + else + render json: output + end + end + + def script_params + params.permit(:os, :arch) + end +end diff --git a/app/controllers/concerns/show_inherited_labels_checker.rb b/app/controllers/concerns/show_inherited_labels_checker.rb new file mode 100644 index 00000000000..acbea37a62e --- /dev/null +++ b/app/controllers/concerns/show_inherited_labels_checker.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +module ShowInheritedLabelsChecker + extend ActiveSupport::Concern + + private + + def show_inherited_labels?(include_ancestor_groups) + Feature.enabled?(:show_inherited_labels, @project || @group) || include_ancestor_groups # rubocop:disable Gitlab/ModuleWithInstanceVariables + end +end diff --git a/app/controllers/concerns/wiki_actions.rb b/app/controllers/concerns/wiki_actions.rb index 5a5b634da40..4d1684ec3a2 100644 --- a/app/controllers/concerns/wiki_actions.rb +++ b/app/controllers/concerns/wiki_actions.rb @@ -44,7 +44,7 @@ module WikiActions wiki.list_pages(sort: params[:sort], direction: params[:direction]) ).page(params[:page]) - @wiki_entries = WikiPage.group_by_directory(@wiki_pages) + @wiki_entries = WikiDirectory.group_pages(@wiki_pages) render 'shared/wikis/pages' end diff --git a/app/controllers/confirmations_controller.rb b/app/controllers/confirmations_controller.rb index a27c4027380..c42c9827eaf 100644 --- a/app/controllers/confirmations_controller.rb +++ b/app/controllers/confirmations_controller.rb @@ -3,6 +3,8 @@ class ConfirmationsController < Devise::ConfirmationsController include AcceptsPendingInvitations + feature_category :users + def almost_there flash[:notice] = nil render layout: "devise_empty" diff --git a/app/controllers/dashboard/groups_controller.rb b/app/controllers/dashboard/groups_controller.rb index f82cde8e10a..23ffcd50369 100644 --- a/app/controllers/dashboard/groups_controller.rb +++ b/app/controllers/dashboard/groups_controller.rb @@ -5,6 +5,8 @@ class Dashboard::GroupsController < Dashboard::ApplicationController skip_cross_project_access_check :index + feature_category :subgroups + def index groups = GroupsFinder.new(current_user, all_available: false).execute render_group_tree(groups) diff --git a/app/controllers/dashboard/labels_controller.rb b/app/controllers/dashboard/labels_controller.rb index 89d87c2d5c8..e3773f65744 100644 --- a/app/controllers/dashboard/labels_controller.rb +++ b/app/controllers/dashboard/labels_controller.rb @@ -1,6 +1,8 @@ # frozen_string_literal: true class Dashboard::LabelsController < Dashboard::ApplicationController + feature_category :issue_tracking + def index respond_to do |format| format.json { render json: LabelSerializer.new.represent_appearance(labels) } diff --git a/app/controllers/dashboard/milestones_controller.rb b/app/controllers/dashboard/milestones_controller.rb index 14f9a026688..e17b16c26a2 100644 --- a/app/controllers/dashboard/milestones_controller.rb +++ b/app/controllers/dashboard/milestones_controller.rb @@ -4,6 +4,8 @@ class Dashboard::MilestonesController < Dashboard::ApplicationController before_action :projects before_action :groups, only: :index + feature_category :issue_tracking + def index respond_to do |format| format.html do diff --git a/app/controllers/dashboard/projects_controller.rb b/app/controllers/dashboard/projects_controller.rb index 2bd6fd85381..f7a74f40e4b 100644 --- a/app/controllers/dashboard/projects_controller.rb +++ b/app/controllers/dashboard/projects_controller.rb @@ -14,6 +14,8 @@ class Dashboard::ProjectsController < Dashboard::ApplicationController before_action :projects, only: [:index] skip_cross_project_access_check :index, :starred + feature_category :projects + def index respond_to do |format| format.html do diff --git a/app/controllers/dashboard/snippets_controller.rb b/app/controllers/dashboard/snippets_controller.rb index a8ca3dbd0e7..6fe3d878639 100644 --- a/app/controllers/dashboard/snippets_controller.rb +++ b/app/controllers/dashboard/snippets_controller.rb @@ -7,6 +7,8 @@ class Dashboard::SnippetsController < Dashboard::ApplicationController skip_cross_project_access_check :index + feature_category :snippets + def index @snippet_counts = Snippets::CountService .new(current_user, author: current_user) diff --git a/app/controllers/dashboard/todos_controller.rb b/app/controllers/dashboard/todos_controller.rb index 4fc2f7b0571..0ae326b5d94 100644 --- a/app/controllers/dashboard/todos_controller.rb +++ b/app/controllers/dashboard/todos_controller.rb @@ -9,6 +9,8 @@ class Dashboard::TodosController < Dashboard::ApplicationController before_action :authorize_read_group!, only: :index before_action :find_todos, only: [:index, :destroy_all] + feature_category :issue_tracking + 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 07cc31fb7d3..a88cf64d842 100644 --- a/app/controllers/dashboard_controller.rb +++ b/app/controllers/dashboard_controller.rb @@ -15,6 +15,10 @@ class DashboardController < Dashboard::ApplicationController respond_to :html + feature_category :audit_events, [:activity] + feature_category :issue_tracking, [:issues, :issues_calendar] + feature_category :code_review, [:merge_requests] + def activity respond_to do |format| format.html diff --git a/app/controllers/explore/groups_controller.rb b/app/controllers/explore/groups_controller.rb index 67db797b80a..aa4196b1c18 100644 --- a/app/controllers/explore/groups_controller.rb +++ b/app/controllers/explore/groups_controller.rb @@ -3,6 +3,8 @@ class Explore::GroupsController < Explore::ApplicationController include GroupTree + feature_category :subgroups + def index render_group_tree GroupsFinder.new(current_user).execute end diff --git a/app/controllers/explore/projects_controller.rb b/app/controllers/explore/projects_controller.rb index b3fa089a712..42795e418a4 100644 --- a/app/controllers/explore/projects_controller.rb +++ b/app/controllers/explore/projects_controller.rb @@ -18,6 +18,8 @@ class Explore::ProjectsController < Explore::ApplicationController rescue_from PageOutOfBoundsError, with: :page_out_of_bounds + feature_category :projects + def index @projects = load_projects diff --git a/app/controllers/explore/snippets_controller.rb b/app/controllers/explore/snippets_controller.rb index 3a56a48e578..91ab18f2f55 100644 --- a/app/controllers/explore/snippets_controller.rb +++ b/app/controllers/explore/snippets_controller.rb @@ -3,6 +3,8 @@ class Explore::SnippetsController < Explore::ApplicationController include Gitlab::NoteableMetadata + feature_category :snippets + def index @snippets = SnippetsFinder.new(current_user, explore: true) .execute diff --git a/app/controllers/groups/group_links_controller.rb b/app/controllers/groups/group_links_controller.rb index c395b93f4e7..06c793b5c4c 100644 --- a/app/controllers/groups/group_links_controller.rb +++ b/app/controllers/groups/group_links_controller.rb @@ -24,6 +24,15 @@ class Groups::GroupLinksController < Groups::ApplicationController def update Groups::GroupLinks::UpdateService.new(@group_link).execute(group_link_params) + + if @group_link.expires? + render json: { + expires_in: helpers.distance_of_time_in_words_to_now(@group_link.expires_at), + expires_soon: @group_link.expires_soon? + } + else + render json: {} + end end def destroy diff --git a/app/controllers/groups/labels_controller.rb b/app/controllers/groups/labels_controller.rb index 1034ca6cd7b..97d9f8fcecd 100644 --- a/app/controllers/groups/labels_controller.rb +++ b/app/controllers/groups/labels_controller.rb @@ -2,6 +2,7 @@ class Groups::LabelsController < Groups::ApplicationController include ToggleSubscriptionAction + include ShowInheritedLabelsChecker before_action :label, only: [:edit, :update, :destroy] before_action :authorize_admin_labels!, only: [:new, :create, :edit, :update, :destroy] @@ -12,8 +13,9 @@ class Groups::LabelsController < Groups::ApplicationController def index respond_to do |format| format.html do - @labels = GroupLabelsFinder - .new(current_user, @group, params.merge(sort: sort)).execute + # at group level we do not want to list project labels, + # we only want `only_group_labels = false` when pulling labels for label filter dropdowns, fetched through json + @labels = available_labels(params.merge(only_group_labels: true)).page(params[:page]) end format.json do render json: LabelSerializer.new.represent_appearance(available_labels) @@ -60,13 +62,7 @@ class Groups::LabelsController < Groups::ApplicationController def destroy @label.destroy - - respond_to do |format| - format.html do - redirect_to group_labels_path(@group), status: :found, notice: "#{@label.name} deleted permanently" - end - format.js - end + redirect_to group_labels_path(@group), status: :found, notice: "#{@label.name} deleted permanently" end protected @@ -80,7 +76,7 @@ class Groups::LabelsController < Groups::ApplicationController end def label - @label ||= @group.labels.find(params[:id]) + @label ||= available_labels(params.merge(only_group_labels: true)).find(params[:id]) end alias_method :subscribable_resource, :label @@ -108,15 +104,17 @@ class Groups::LabelsController < Groups::ApplicationController session[:previous_labels_path] = URI(request.referer || '').path end - def available_labels + def available_labels(options = params) @available_labels ||= LabelsFinder.new( current_user, group_id: @group.id, - only_group_labels: params[:only_group_labels], - include_ancestor_groups: params[:include_ancestor_groups], - include_descendant_groups: params[:include_descendant_groups], - search: params[:search]).execute + only_group_labels: options[:only_group_labels], + include_ancestor_groups: show_inherited_labels?(params[:include_ancestor_groups]), + sort: sort, + subscribed: options[:subscribed], + include_descendant_groups: options[:include_descendant_groups], + search: options[:search]).execute end def sort diff --git a/app/controllers/groups/milestones_controller.rb b/app/controllers/groups/milestones_controller.rb index df3fb6b67c2..3f2894d378b 100644 --- a/app/controllers/groups/milestones_controller.rb +++ b/app/controllers/groups/milestones_controller.rb @@ -3,7 +3,7 @@ class Groups::MilestonesController < Groups::ApplicationController include MilestoneActions - before_action :milestone, only: [:edit, :show, :update, :merge_requests, :participants, :labels, :destroy] + before_action :milestone, only: [:edit, :show, :update, :issues, :merge_requests, :participants, :labels, :destroy] before_action :authorize_admin_milestones!, only: [:edit, :new, :create, :update, :destroy] before_action do push_frontend_feature_flag(:burnup_charts, @group) diff --git a/app/controllers/groups/registry/repositories_controller.rb b/app/controllers/groups/registry/repositories_controller.rb index 14651e0794a..87a62a8f9b0 100644 --- a/app/controllers/groups/registry/repositories_controller.rb +++ b/app/controllers/groups/registry/repositories_controller.rb @@ -2,6 +2,8 @@ module Groups module Registry class RepositoriesController < Groups::ApplicationController + include PackagesHelper + before_action :verify_container_registry_enabled! before_action :authorize_read_container_image! @@ -13,7 +15,7 @@ module Groups .execute .with_api_entity_associations - track_event(:list_repositories) + track_package_event(:list_repositories, :container) serializer = ContainerRepositoriesSerializer .new(current_user: current_user) diff --git a/app/controllers/groups/settings/ci_cd_controller.rb b/app/controllers/groups/settings/ci_cd_controller.rb index bf3a38ce57b..ceee049d824 100644 --- a/app/controllers/groups/settings/ci_cd_controller.rb +++ b/app/controllers/groups/settings/ci_cd_controller.rb @@ -3,6 +3,8 @@ module Groups module Settings class CiCdController < Groups::ApplicationController + include RunnerSetupScripts + skip_cross_project_access_check :show before_action :authorize_admin_group! before_action :authorize_update_max_artifacts_size!, only: [:update] @@ -49,6 +51,10 @@ module Groups redirect_to group_settings_ci_cd_path end + def runner_setup_scripts + private_runner_setup_scripts(group: group) + end + private def define_variables diff --git a/app/controllers/import/bulk_imports_controller.rb b/app/controllers/import/bulk_imports_controller.rb new file mode 100644 index 00000000000..58b9f8c0fbb --- /dev/null +++ b/app/controllers/import/bulk_imports_controller.rb @@ -0,0 +1,51 @@ +# frozen_string_literal: true + +class Import::BulkImportsController < ApplicationController + before_action :ensure_group_import_enabled + before_action :verify_blocked_uri, only: :status + + def configure + session[access_token_key] = params[access_token_key]&.strip + session[url_key] = params[url_key] + + redirect_to status_import_bulk_import_url + end + + private + + def import_params + params.permit(access_token_key, url_key) + end + + def ensure_group_import_enabled + render_404 unless Feature.enabled?(:bulk_import) + end + + def access_token_key + :bulk_import_gitlab_access_token + end + + def url_key + :bulk_import_gitlab_url + end + + def verify_blocked_uri + Gitlab::UrlBlocker.validate!( + session[url_key], + **{ + allow_localhost: allow_local_requests?, + allow_local_network: allow_local_requests?, + schemes: %w(http https) + } + ) + rescue Gitlab::UrlBlocker::BlockedUrlError => e + session[access_token_key] = nil + session[url_key] = nil + + redirect_to new_group_path, alert: _('Specified URL cannot be used: "%{reason}"') % { reason: e.message } + end + + def allow_local_requests? + Gitlab::CurrentSettings.allow_local_requests_from_web_hooks_and_services? + end +end diff --git a/app/controllers/import/fogbugz_controller.rb b/app/controllers/import/fogbugz_controller.rb index a34bc9c953f..bcbf5938e11 100644 --- a/app/controllers/import/fogbugz_controller.rb +++ b/app/controllers/import/fogbugz_controller.rb @@ -136,7 +136,7 @@ class Import::FogbugzController < Import::BaseController def verify_blocked_uri Gitlab::UrlBlocker.validate!( params[:uri], - { + **{ allow_localhost: allow_local_requests?, allow_local_network: allow_local_requests?, schemes: %w(http https) diff --git a/app/controllers/import/github_controller.rb b/app/controllers/import/github_controller.rb index 29fe34f0734..a1adc6e062a 100644 --- a/app/controllers/import/github_controller.rb +++ b/app/controllers/import/github_controller.rb @@ -108,7 +108,7 @@ class Import::GithubController < Import::BaseController @client ||= if Feature.enabled?(:remove_legacy_github_client) Gitlab::GithubImport::Client.new(session[access_token_key]) else - Gitlab::LegacyGithubImport::Client.new(session[access_token_key], client_options) + Gitlab::LegacyGithubImport::Client.new(session[access_token_key], **client_options) end end diff --git a/app/controllers/import/manifest_controller.rb b/app/controllers/import/manifest_controller.rb index 9c47e6d4b0b..fdca6da95c5 100644 --- a/app/controllers/import/manifest_controller.rb +++ b/app/controllers/import/manifest_controller.rb @@ -26,8 +26,7 @@ class Import::ManifestController < Import::BaseController manifest = Gitlab::ManifestImport::Manifest.new(params[:manifest].tempfile) if manifest.valid? - session[:manifest_import_repositories] = manifest.projects - session[:manifest_import_group_id] = group.id + manifest_import_metadata.save(manifest.projects, group.id) redirect_to status_import_manifest_path else @@ -96,12 +95,16 @@ class Import::ManifestController < Import::BaseController # rubocop: disable CodeReuse/ActiveRecord def group - @group ||= Group.find_by(id: session[:manifest_import_group_id]) + @group ||= Group.find_by(id: manifest_import_metadata.group_id) end # rubocop: enable CodeReuse/ActiveRecord + def manifest_import_metadata + @manifest_import_status ||= Gitlab::ManifestImport::Metadata.new(current_user, fallback: session) + end + def repositories - @repositories ||= session[:manifest_import_repositories] + @repositories ||= manifest_import_metadata.repositories end def find_jobs diff --git a/app/controllers/invites_controller.rb b/app/controllers/invites_controller.rb index aa9c7d01ba3..591ded7630c 100644 --- a/app/controllers/invites_controller.rb +++ b/app/controllers/invites_controller.rb @@ -4,6 +4,7 @@ class InvitesController < ApplicationController include Gitlab::Utils::StrongMemoize before_action :member + before_action :ensure_member_exists before_action :invite_details skip_before_action :authenticate_user!, only: :decline @@ -12,13 +13,14 @@ class InvitesController < ApplicationController respond_to :html def show - track_experiment('opened') + track_new_user_invite_experiment('opened') accept if skip_invitation_prompt? end def accept if member.accept_invite!(current_user) - track_experiment('accepted') + track_new_user_invite_experiment('accepted') + track_invitation_reminders_experiment('accepted') redirect_to invite_details[:path], notice: _("You have been granted %{member_human_access} access to %{title} %{name}.") % { member_human_access: member.human_access, title: invite_details[:title], name: invite_details[:name] } else @@ -28,6 +30,8 @@ class InvitesController < ApplicationController def decline if member.decline_invite! + return render layout: 'devise_experimental_onboarding_issues' if !current_user && member.invite_to_unknown_user? && member.created_by + path = if current_user dashboard_projects_path @@ -59,14 +63,16 @@ class InvitesController < ApplicationController end def member - return @member if defined?(@member) - - @token = params[:id] - @member = Member.find_by_invite_token(@token) + strong_memoize(:member) do + @token = params[:id] + Member.find_by_invite_token(@token) + end + end - return render_404 unless @member + def ensure_member_exists + return if member - @member + render_404 end def authenticate_user! @@ -76,10 +82,7 @@ class InvitesController < ApplicationController notice << "or create an account" if Gitlab::CurrentSettings.allow_signup? notice = notice.join(' ') + "." - # this is temporary finder instead of using member method due to render_404 possibility - # will be resolved via https://gitlab.com/gitlab-org/gitlab/-/issues/245325 - initial_member = Member.find_by_invite_token(params[:id]) - redirect_params = initial_member ? { invite_email: initial_member.invite_email } : {} + redirect_params = member ? { invite_email: member.invite_email } : {} store_location_for :user, request.fullpath @@ -87,31 +90,43 @@ class InvitesController < ApplicationController end def invite_details - @invite_details ||= case @member.source + @invite_details ||= case member.source when Project { - name: @member.source.full_name, - url: project_url(@member.source), + name: member.source.full_name, + url: project_url(member.source), title: _("project"), - path: project_path(@member.source) + path: project_path(member.source) } when Group { - name: @member.source.name, - url: group_url(@member.source), + name: member.source.name, + url: group_url(member.source), title: _("group"), - path: group_path(@member.source) + path: group_path(member.source) } end end - def track_experiment(action) + def track_new_user_invite_experiment(action) return unless params[:new_user_invite] property = params[:new_user_invite] == 'experiment' ? 'experiment_group' : 'control_group' + track_experiment(:invite_email, action, property) + end + + def track_invitation_reminders_experiment(action) + return unless Gitlab::Experimentation.enabled?(:invitation_reminders) + + property = Gitlab::Experimentation.enabled_for_attribute?(:invitation_reminders, member.invite_email) ? 'experimental_group' : 'control_group' + + track_experiment(:invitation_reminders, action, property) + end + + def track_experiment(experiment_key, action, property) Gitlab::Tracking.event( - Gitlab::Experimentation::EXPERIMENTS[:invite_email][:tracking_category], + Gitlab::Experimentation.experiment(experiment_key).tracking_category, action, property: property, label: Digest::MD5.hexdigest(member.to_global_id.to_s) diff --git a/app/controllers/omniauth_callbacks_controller.rb b/app/controllers/omniauth_callbacks_controller.rb index b798d6680bc..2708e6669e7 100644 --- a/app/controllers/omniauth_callbacks_controller.rb +++ b/app/controllers/omniauth_callbacks_controller.rb @@ -1,8 +1,7 @@ # frozen_string_literal: true class OmniauthCallbacksController < Devise::OmniauthCallbacksController - include AuthenticatesWithTwoFactor - include Authenticates2FAForAdminMode + include AuthenticatesWithTwoFactorForAdminMode include Devise::Controllers::Rememberable include AuthHelper include InitializesCurrentUserMode diff --git a/app/controllers/projects/blob_controller.rb b/app/controllers/projects/blob_controller.rb index 1568d9966dd..f0ac86d1581 100644 --- a/app/controllers/projects/blob_controller.rb +++ b/app/controllers/projects/blob_controller.rb @@ -33,8 +33,7 @@ class Projects::BlobController < Projects::ApplicationController before_action :set_last_commit_sha, only: [:edit, :update] before_action only: :show do - push_frontend_feature_flag(:code_navigation, @project, default_enabled: true) - push_frontend_feature_flag(:suggest_pipeline) if experiment_enabled?(:suggest_pipeline) + push_frontend_experiment(:suggest_pipeline) push_frontend_feature_flag(:gitlab_ci_yml_preview, @project, default_enabled: false) end diff --git a/app/controllers/projects/ci/daily_build_group_report_results_controller.rb b/app/controllers/projects/ci/daily_build_group_report_results_controller.rb index b36c5f1aea6..3d3b62fa797 100644 --- a/app/controllers/projects/ci/daily_build_group_report_results_controller.rb +++ b/app/controllers/projects/ci/daily_build_group_report_results_controller.rb @@ -6,7 +6,6 @@ class Projects::Ci::DailyBuildGroupReportResultsController < Projects::Applicati MAX_ITEMS = 1000 REPORT_WINDOW = 90.days - before_action :validate_feature_flag! before_action :authorize_read_build_report_results! before_action :validate_param_type! @@ -19,10 +18,6 @@ class Projects::Ci::DailyBuildGroupReportResultsController < Projects::Applicati private - def validate_feature_flag! - render_404 unless Feature.enabled?(:ci_download_daily_code_coverage, project, default_enabled: true) - end - def validate_param_type! respond_422 unless allowed_param_types.include?(param_type) end @@ -43,7 +38,7 @@ class Projects::Ci::DailyBuildGroupReportResultsController < Projects::Applicati end def report_results - Ci::DailyBuildGroupReportResultsFinder.new(finder_params).execute + Ci::DailyBuildGroupReportResultsFinder.new(**finder_params).execute end def finder_params diff --git a/app/controllers/projects/graphs_controller.rb b/app/controllers/projects/graphs_controller.rb index 9b889f9e837..91c07c37d2a 100644 --- a/app/controllers/projects/graphs_controller.rb +++ b/app/controllers/projects/graphs_controller.rb @@ -57,7 +57,6 @@ class Projects::GraphsController < Projects::ApplicationController end def get_daily_coverage_options - return unless Feature.enabled?(:ci_download_daily_code_coverage, @project, default_enabled: true) return unless can?(current_user, :read_build_report_results, project) date_today = Date.current diff --git a/app/controllers/projects/group_links_controller.rb b/app/controllers/projects/group_links_controller.rb index a30c455a7e4..f8ea6f834a3 100644 --- a/app/controllers/projects/group_links_controller.rb +++ b/app/controllers/projects/group_links_controller.rb @@ -21,8 +21,17 @@ class Projects::GroupLinksController < Projects::ApplicationController end def update - @group_link = @project.project_group_links.find(params[:id]) - Projects::GroupLinks::UpdateService.new(@group_link).execute(group_link_params) + group_link = @project.project_group_links.find(params[:id]) + Projects::GroupLinks::UpdateService.new(group_link).execute(group_link_params) + + if group_link.expires? + render json: { + expires_in: helpers.distance_of_time_in_words_to_now(group_link.expires_at), + expires_soon: group_link.expires_soon? + } + else + render json: {} + end end def destroy diff --git a/app/controllers/projects/incidents_controller.rb b/app/controllers/projects/incidents_controller.rb index 12cc4dde1f4..1c915842e61 100644 --- a/app/controllers/projects/incidents_controller.rb +++ b/app/controllers/projects/incidents_controller.rb @@ -1,8 +1,52 @@ # frozen_string_literal: true class Projects::IncidentsController < Projects::ApplicationController - before_action :authorize_read_incidents! + include IssuableActions + include Gitlab::Utils::StrongMemoize + + before_action :authorize_read_issue! + before_action :check_feature_flag, only: [:show] + before_action :load_incident, only: [:show] + + before_action do + push_frontend_feature_flag(:issues_incident_details, @project) + end def index end + + private + + def incident + strong_memoize(:incident) do + incident_finder + .execute + .inc_relations_for_view + .iid_in(params[:id]) + .without_order + .first + end + end + + def load_incident + @issue = incident # needed by rendered view + return render_404 unless can?(current_user, :read_issue, incident) + + @noteable = incident + @note = incident.project.notes.new(noteable: issuable) + end + + alias_method :issuable, :incident + + def incident_finder + IssuesFinder.new(current_user, project_id: @project.id, issue_types: :incident) + end + + def serializer + IssueSerializer.new(current_user: current_user, project: incident.project) + end + + def check_feature_flag + render_404 unless Feature.enabled?(:issues_incident_details, @project) + end end diff --git a/app/controllers/projects/issues_controller.rb b/app/controllers/projects/issues_controller.rb index 7f0d23b79ce..319a5183429 100644 --- a/app/controllers/projects/issues_controller.rb +++ b/app/controllers/projects/issues_controller.rb @@ -56,7 +56,7 @@ class Projects::IssuesController < Projects::ApplicationController end before_action only: :index do - push_frontend_feature_flag(:scoped_labels, @project) + push_frontend_feature_flag(:scoped_labels, @project, type: :licensed) end around_action :allow_gitaly_ref_name_caching, only: [:discussions] @@ -239,7 +239,7 @@ class Projects::IssuesController < Projects::ApplicationController return @issue if defined?(@issue) # The Sortable default scope causes performance issues when used with find_by - @issuable = @noteable = @issue ||= @project.issues.includes(author: :status).where(iid: params[:id]).reorder(nil).take! + @issuable = @noteable = @issue ||= @project.issues.inc_relations_for_view.iid_in(params[:id]).without_order.take! @note = @project.notes.new(noteable: @issuable) return render_404 unless can?(current_user, :read_issue, @issue) diff --git a/app/controllers/projects/jobs_controller.rb b/app/controllers/projects/jobs_controller.rb index 3f7f8da3478..a8ac20cf96b 100644 --- a/app/controllers/projects/jobs_controller.rb +++ b/app/controllers/projects/jobs_controller.rb @@ -28,11 +28,6 @@ class Projects::JobsController < Projects::ApplicationController # rubocop: disable CodeReuse/ActiveRecord def show - @pipeline = @build.pipeline - @builds = @pipeline.builds - .order('id DESC') - .present(current_user: current_user) - respond_to do |format| format.html format.json do diff --git a/app/controllers/projects/labels_controller.rb b/app/controllers/projects/labels_controller.rb index b7aeab8f5ff..ca2fad35451 100644 --- a/app/controllers/projects/labels_controller.rb +++ b/app/controllers/projects/labels_controller.rb @@ -2,6 +2,7 @@ class Projects::LabelsController < Projects::ApplicationController include ToggleSubscriptionAction + include ShowInheritedLabelsChecker before_action :check_issuables_available! before_action :label, only: [:edit, :update, :destroy, :promote] @@ -161,7 +162,7 @@ class Projects::LabelsController < Projects::ApplicationController @available_labels ||= LabelsFinder.new(current_user, project_id: @project.id, - include_ancestor_groups: params[:include_ancestor_groups], + include_ancestor_groups: show_inherited_labels?(params[:include_ancestor_groups]), search: params[:search], subscribed: params[:subscribed], sort: sort).execute diff --git a/app/controllers/projects/merge_requests/application_controller.rb b/app/controllers/projects/merge_requests/application_controller.rb index 921da788ad2..7b4024ed79c 100644 --- a/app/controllers/projects/merge_requests/application_controller.rb +++ b/app/controllers/projects/merge_requests/application_controller.rb @@ -35,6 +35,7 @@ class Projects::MergeRequests::ApplicationController < Projects::ApplicationCont :source_branch, :source_project_id, :state_event, + :wip_event, :squash, :target_branch, :target_project_id, diff --git a/app/controllers/projects/merge_requests/diffs_controller.rb b/app/controllers/projects/merge_requests/diffs_controller.rb index 8aacfdce094..28aef6f4328 100644 --- a/app/controllers/projects/merge_requests/diffs_controller.rb +++ b/app/controllers/projects/merge_requests/diffs_controller.rb @@ -64,7 +64,7 @@ class Projects::MergeRequests::DiffsController < Projects::MergeRequests::Applic render: ->(partial, locals) { view_to_html_string(partial, locals) } } - options = additional_attributes.merge(diff_view: Feature.enabled?(:unified_diff_lines, @merge_request.project) ? "inline" : diff_view) + options = additional_attributes.merge(diff_view: Feature.enabled?(:unified_diff_lines, @merge_request.project, default_enabled: true) ? "inline" : diff_view) if @merge_request.project.context_commits_enabled? options[:context_commits] = @merge_request.recent_context_commits diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb index 92785540172..8ca70602c89 100644 --- a/app/controllers/projects/merge_requests_controller.rb +++ b/app/controllers/projects/merge_requests_controller.rb @@ -27,9 +27,7 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo before_action :authenticate_user!, only: [:assign_related_issues] before_action :check_user_can_push_to_source_branch!, only: [:rebase] before_action only: [:show] do - push_frontend_feature_flag(:deploy_from_footer, @project, default_enabled: true) - push_frontend_feature_flag(:suggest_pipeline) if experiment_enabled?(:suggest_pipeline) - push_frontend_feature_flag(:code_navigation, @project, default_enabled: true) + push_frontend_experiment(:suggest_pipeline) push_frontend_feature_flag(:widget_visibility_polling, @project, default_enabled: true) push_frontend_feature_flag(:merge_ref_head_comments, @project, default_enabled: true) push_frontend_feature_flag(:mr_commit_neighbor_nav, @project, default_enabled: true) @@ -39,7 +37,7 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo push_frontend_feature_flag(:approvals_commented_by, @project, default_enabled: true) push_frontend_feature_flag(:hide_jump_to_next_unresolved_in_threads, default_enabled: true) push_frontend_feature_flag(:merge_request_widget_graphql, @project) - push_frontend_feature_flag(:unified_diff_lines, @project) + push_frontend_feature_flag(:unified_diff_lines, @project, default_enabled: true) push_frontend_feature_flag(:highlight_current_diff_row, @project) push_frontend_feature_flag(:default_merge_ref_for_diffs, @project) end @@ -52,12 +50,17 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo after_action :log_merge_request_show, only: [:show] - 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] + feature_category :code_review, [ + :assign_related_issues, :bulk_update, :cancel_auto_merge, + :ci_environments_status, :commit_change_content, :commits, + :context_commits, :destroy, :diff_for_path, :discussions, + :edit, :exposed_artifacts, :index, :merge, + :pipeline_status, :pipelines, :rebase, :remove_wip, :show, + :toggle_award_emoji, :toggle_subscription, :update + ] + + feature_category :code_testing, [:test_reports, :coverage_reports, :terraform_reports] + feature_category :accessibility_testing, [:accessibility_reports] def index @merge_requests = @issuables diff --git a/app/controllers/projects/milestones_controller.rb b/app/controllers/projects/milestones_controller.rb index 16d63cc184f..8049a17068b 100644 --- a/app/controllers/projects/milestones_controller.rb +++ b/app/controllers/projects/milestones_controller.rb @@ -5,7 +5,7 @@ class Projects::MilestonesController < Projects::ApplicationController include MilestoneActions before_action :check_issuables_available! - before_action :milestone, only: [:edit, :update, :destroy, :show, :merge_requests, :participants, :labels, :promote] + before_action :milestone, only: [:edit, :update, :destroy, :show, :issues, :merge_requests, :participants, :labels, :promote] before_action do push_frontend_feature_flag(:burnup_charts, @project) end @@ -14,7 +14,7 @@ class Projects::MilestonesController < Projects::ApplicationController before_action :authorize_read_milestone! # Allow admin milestone - before_action :authorize_admin_milestone!, except: [:index, :show, :merge_requests, :participants, :labels] + before_action :authorize_admin_milestone!, except: [:index, :show, :issues, :merge_requests, :participants, :labels] # Allow to promote milestone before_action :authorize_promote_milestone!, only: :promote diff --git a/app/controllers/projects/packages/packages_controller.rb b/app/controllers/projects/packages/packages_controller.rb index fc4ef7a01dc..302847eeaf5 100644 --- a/app/controllers/projects/packages/packages_controller.rb +++ b/app/controllers/projects/packages/packages_controller.rb @@ -5,20 +5,11 @@ module Projects class PackagesController < Projects::ApplicationController include PackagesAccess - before_action :authorize_destroy_package!, only: [:destroy] - def show @package = project.packages.find(params[:id]) @package_files = @package.package_files.recent @maven_metadatum = @package.maven_metadatum end - - def destroy - @package = project.packages.find(params[:id]) - @package.destroy - - redirect_to project_packages_path(@project), status: :found, notice: _('Package was removed') - end end end end diff --git a/app/controllers/projects/pipelines_controller.rb b/app/controllers/projects/pipelines_controller.rb index c1734d2cd8a..8676c90ca86 100644 --- a/app/controllers/projects/pipelines_controller.rb +++ b/app/controllers/projects/pipelines_controller.rb @@ -15,7 +15,8 @@ class Projects::PipelinesController < Projects::ApplicationController push_frontend_feature_flag(:filter_pipelines_search, project, default_enabled: true) push_frontend_feature_flag(:dag_pipeline_tab, project, default_enabled: true) push_frontend_feature_flag(:pipelines_security_report_summary, project) - push_frontend_feature_flag(:new_pipeline_form) + push_frontend_feature_flag(:new_pipeline_form, project) + push_frontend_feature_flag(:graphql_pipeline_header, project, type: :development, default_enabled: false) end before_action :ensure_pipeline, only: [:show] diff --git a/app/controllers/projects/protected_refs_controller.rb b/app/controllers/projects/protected_refs_controller.rb index 060403a9cd9..f1a7ac36138 100644 --- a/app/controllers/projects/protected_refs_controller.rb +++ b/app/controllers/projects/protected_refs_controller.rb @@ -62,7 +62,7 @@ class Projects::ProtectedRefsController < Projects::ApplicationController end def access_level_attributes - %i[access_level id _destroy] + %i[access_level id _destroy deploy_key_id] end end diff --git a/app/controllers/projects/registry/repositories_controller.rb b/app/controllers/projects/registry/repositories_controller.rb index 19d0cb9acdc..28a86ecc9f0 100644 --- a/app/controllers/projects/registry/repositories_controller.rb +++ b/app/controllers/projects/registry/repositories_controller.rb @@ -3,6 +3,8 @@ module Projects module Registry class RepositoriesController < ::Projects::Registry::ApplicationController + include PackagesHelper + before_action :authorize_update_container_image!, only: [:destroy] before_action :ensure_root_container_repository!, only: [:index] @@ -13,7 +15,7 @@ module Projects @images = ContainerRepositoriesFinder.new(user: current_user, subject: project, params: params.slice(:name)) .execute - track_event(:list_repositories) + track_package_event(:list_repositories, :container) serializer = ContainerRepositoriesSerializer .new(project: project, current_user: current_user) @@ -31,7 +33,7 @@ module Projects def destroy image.delete_scheduled! DeleteContainerRepositoryWorker.perform_async(current_user.id, image.id) # rubocop:disable CodeReuse/Worker - track_event(:delete_repository) + track_package_event(:delete_repository, :container) respond_to do |format| format.json { head :no_content } diff --git a/app/controllers/projects/registry/tags_controller.rb b/app/controllers/projects/registry/tags_controller.rb index c42e3f6bdba..ebdb668207f 100644 --- a/app/controllers/projects/registry/tags_controller.rb +++ b/app/controllers/projects/registry/tags_controller.rb @@ -3,12 +3,15 @@ module Projects module Registry class TagsController < ::Projects::Registry::ApplicationController + include PackagesHelper + before_action :authorize_destroy_container_image!, only: [:destroy] LIMIT = 15 def index - track_event(:list_tags) + track_package_event(:list_tags, :tag) + respond_to do |format| format.json do render json: ContainerTagsSerializer @@ -23,7 +26,7 @@ module Projects result = Projects::ContainerRepository::DeleteTagsService .new(image.project, current_user, tags: [params[:id]]) .execute(image) - track_event(:delete_tag) + track_package_event(:delete_tag, :tag) respond_to do |format| format.json { head(result[:status] == :success ? :ok : bad_request) } @@ -40,7 +43,7 @@ module Projects result = Projects::ContainerRepository::DeleteTagsService .new(image.project, current_user, tags: tag_names) .execute(image) - track_event(:delete_tag_bulk) + track_package_event(:delete_tag_bulk, :tag) respond_to do |format| format.json { head(result[:status] == :success ? :no_content : :bad_request) } diff --git a/app/controllers/projects/releases_controller.rb b/app/controllers/projects/releases_controller.rb index bd24aae980c..808e1c755ae 100644 --- a/app/controllers/projects/releases_controller.rb +++ b/app/controllers/projects/releases_controller.rb @@ -13,7 +13,7 @@ class Projects::ReleasesController < Projects::ApplicationController push_frontend_feature_flag(:release_asset_link_type, project, default_enabled: true) push_frontend_feature_flag(:graphql_release_data, project, default_enabled: true) push_frontend_feature_flag(:graphql_milestone_stats, project, default_enabled: true) - push_frontend_feature_flag(:graphql_releases_page, project, default_enabled: false) + push_frontend_feature_flag(:graphql_releases_page, project, default_enabled: true) end before_action :authorize_update_release!, only: %i[edit update] before_action :authorize_create_release!, only: :new diff --git a/app/controllers/projects/runners_controller.rb b/app/controllers/projects/runners_controller.rb index ca62f54813b..fb00156d320 100644 --- a/app/controllers/projects/runners_controller.rb +++ b/app/controllers/projects/runners_controller.rb @@ -50,6 +50,10 @@ class Projects::RunnersController < Projects::ApplicationController end def toggle_shared_runners + if Feature.enabled?(:disable_shared_runners_on_group, default_enabled: true) && !project.shared_runners_enabled && project.group && project.group.shared_runners_setting == 'disabled_and_unoverridable' + return redirect_to project_runners_path(@project), alert: _("Cannot enable shared runners because parent group does not allow it") + end + project.toggle!(:shared_runners_enabled) redirect_to project_settings_ci_cd_path(@project, anchor: 'js-runners-settings') diff --git a/app/controllers/projects/services_controller.rb b/app/controllers/projects/services_controller.rb index 9a69ef991dd..41ce834c658 100644 --- a/app/controllers/projects/services_controller.rb +++ b/app/controllers/projects/services_controller.rb @@ -12,7 +12,7 @@ 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(:jira_issues_integration, @project, { default_enabled: true }) + push_frontend_feature_flag(:jira_issues_integration, @project, type: :licensed, default_enabled: true) end respond_to :html diff --git a/app/controllers/projects/settings/ci_cd_controller.rb b/app/controllers/projects/settings/ci_cd_controller.rb index d0d100fd88c..b30f54acf90 100644 --- a/app/controllers/projects/settings/ci_cd_controller.rb +++ b/app/controllers/projects/settings/ci_cd_controller.rb @@ -3,15 +3,21 @@ module Projects module Settings class CiCdController < Projects::ApplicationController + include RunnerSetupScripts + before_action :authorize_admin_pipeline! before_action :define_variables before_action do push_frontend_feature_flag(:new_variables_ui, @project, default_enabled: true) push_frontend_feature_flag(:ajax_new_deploy_token, @project) - push_frontend_feature_flag(:ci_key_autocomplete, default_enabled: true) end def show + if Feature.enabled?(:ci_pipeline_triggers_settings_vue_ui, @project) + @triggers_json = ::Ci::TriggerSerializer.new.represent( + @project.triggers, current_user: current_user, project: @project + ).to_json + end end def update @@ -48,6 +54,10 @@ module Projects redirect_to namespace_project_settings_ci_cd_path end + def runner_setup_scripts + private_runner_setup_scripts(project: @project) + end + private def update_params @@ -116,6 +126,7 @@ module Projects def define_triggers_variables @triggers = @project.triggers .present(current_user: current_user) + @trigger = ::Ci::Trigger.new .present(current_user: current_user) end diff --git a/app/controllers/projects/settings/repository_controller.rb b/app/controllers/projects/settings/repository_controller.rb index 35ca9336613..182968b9a41 100644 --- a/app/controllers/projects/settings/repository_controller.rb +++ b/app/controllers/projects/settings/repository_controller.rb @@ -7,6 +7,7 @@ module Projects before_action :define_variables, only: [:create_deploy_token] before_action do push_frontend_feature_flag(:ajax_new_deploy_token, @project) + push_frontend_feature_flag(:deploy_keys_on_protected_branches, @project) end def show @@ -125,6 +126,7 @@ module Projects gon.push(protectable_tags_for_dropdown) gon.push(protectable_branches_for_dropdown) gon.push(access_levels_options) + gon.push(current_project_id: project.id) if project end end end diff --git a/app/controllers/projects/static_site_editor_controller.rb b/app/controllers/projects/static_site_editor_controller.rb index e97a8db0b79..f99ffe170b0 100644 --- a/app/controllers/projects/static_site_editor_controller.rb +++ b/app/controllers/projects/static_site_editor_controller.rb @@ -25,14 +25,30 @@ class Projects::StaticSiteEditorController < Projects::ApplicationController ).execute if service_response.success? - @data = service_response.payload + @data = serialize_necessary_payload_values_to_json(service_response.payload) else - respond_422 + # TODO: For now, if the service returns any error, the user is redirected + # to the root project page with the error message displayed as an alert. + # See https://gitlab.com/gitlab-org/gitlab/-/issues/213285#note_414808004 + # for discussion of plans to handle this via a page owned by the Static Site Editor. + flash[:alert] = service_response.message + redirect_to project_path(project) end end private + def serialize_necessary_payload_values_to_json(payload) + # This will convert booleans, Array-like and Hash-like objects to JSON + payload.transform_values do |value| + if value.is_a?(String) || value.is_a?(Integer) + value + else + value.to_json + end + end + end + def assign_ref_and_path @ref, @path = extract_ref(params.fetch(:id)) diff --git a/app/controllers/projects/tags_controller.rb b/app/controllers/projects/tags_controller.rb index 475ca8894e4..71effebf1c0 100644 --- a/app/controllers/projects/tags_controller.rb +++ b/app/controllers/projects/tags_controller.rb @@ -76,25 +76,10 @@ class Projects::TagsController < Projects::ApplicationController def destroy result = ::Tags::DestroyService.new(project, current_user).execute(params[:id]) - respond_to do |format| - if result[:status] == :success - format.html do - redirect_to project_tags_path(@project), status: :see_other - end - - format.js - else - @error = result[:message] - - format.html do - redirect_to project_tags_path(@project), - alert: @error, status: :see_other - end - - format.js do - render status: :ok - end - end + if result[:status] == :success + render json: result + else + render json: { message: result[:message] }, status: result[:return_code] end end diff --git a/app/controllers/runner_setup_controller.rb b/app/controllers/runner_setup_controller.rb new file mode 100644 index 00000000000..2cb204b729c --- /dev/null +++ b/app/controllers/runner_setup_controller.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +class RunnerSetupController < ApplicationController + def platforms + render json: Gitlab::Ci::RunnerInstructions::OS.merge(Gitlab::Ci::RunnerInstructions::OTHER_ENVIRONMENTS) + end +end diff --git a/app/controllers/search_controller.rb b/app/controllers/search_controller.rb index dedaf0c903a..b5e221a8894 100644 --- a/app/controllers/search_controller.rb +++ b/app/controllers/search_controller.rb @@ -8,7 +8,8 @@ class SearchController < ApplicationController SCOPE_PRELOAD_METHOD = { projects: :with_web_entity_associations, - issues: :with_web_entity_associations + issues: :with_web_entity_associations, + epics: :with_web_entity_associations }.freeze track_redis_hll_event :show, name: 'i_search_total', feature: :search_track_unique_users, feature_default_enabled: true @@ -96,8 +97,6 @@ class SearchController < ApplicationController end def eager_load_user_status - return if Feature.disabled?(:users_search, default_enabled: true) - @search_objects = @search_objects.eager_load(:status) # rubocop:disable CodeReuse/ActiveRecord end diff --git a/app/controllers/uploads_controller.rb b/app/controllers/uploads_controller.rb index 0b092d2622b..9510734bc9b 100644 --- a/app/controllers/uploads_controller.rb +++ b/app/controllers/uploads_controller.rb @@ -19,6 +19,7 @@ class UploadsController < ApplicationController rescue_from UnknownUploadModelError, with: :render_404 skip_before_action :authenticate_user! + skip_before_action :check_two_factor_requirement, only: [:show] before_action :upload_mount_satisfied? before_action :authorize_access!, only: [:show] before_action :authorize_create_access!, only: [:create, :authorize] diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index 75a861423ed..e7af60beade 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -106,7 +106,7 @@ class UsersController < ApplicationController def calendar_activities @calendar_date = Date.parse(params[:date]) rescue Date.today - @events = contributions_calendar.events_by_date(@calendar_date) + @events = contributions_calendar.events_by_date(@calendar_date).map(&:present) render 'calendar_activities', layout: false end |