diff options
Diffstat (limited to 'app/controllers')
72 files changed, 382 insertions, 217 deletions
diff --git a/app/controllers/admin/application_settings_controller.rb b/app/controllers/admin/application_settings_controller.rb index e05e87ffd89..6f21b123eb0 100644 --- a/app/controllers/admin/application_settings_controller.rb +++ b/app/controllers/admin/application_settings_controller.rb @@ -13,6 +13,10 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController before_action :disable_query_limiting, only: [:usage_data] + before_action do + push_frontend_feature_flag(:ci_variable_settings_graphql) + end + feature_category :not_owned, [ # rubocop:todo Gitlab/AvoidFeatureCategoryNotOwned :general, :reporting, :metrics_and_profiling, :network, :preferences, :update, :reset_health_check_token diff --git a/app/controllers/admin/applications_controller.rb b/app/controllers/admin/applications_controller.rb index a6a21cf3649..b0d7c8cb8f2 100644 --- a/app/controllers/admin/applications_controller.rb +++ b/app/controllers/admin/applications_controller.rb @@ -11,7 +11,6 @@ class Admin::ApplicationsController < Admin::ApplicationController def index applications = ApplicationsFinder.new.execute @applications = Kaminari.paginate_array(applications).page(params[:page]) - @application_counts = OauthAccessToken.distinct_resource_owner_counts(@applications) end def show diff --git a/app/controllers/admin/broadcast_messages_controller.rb b/app/controllers/admin/broadcast_messages_controller.rb index bf573d45852..a53e832329f 100644 --- a/app/controllers/admin/broadcast_messages_controller.rb +++ b/app/controllers/admin/broadcast_messages_controller.rb @@ -58,7 +58,6 @@ class Admin::BroadcastMessagesController < Admin::ApplicationController def broadcast_message_params params.require(:broadcast_message).permit(%i( - color theme ends_at message diff --git a/app/controllers/admin/ci/variables_controller.rb b/app/controllers/admin/ci/variables_controller.rb index d4b7d750759..7d643435ddb 100644 --- a/app/controllers/admin/ci/variables_controller.rb +++ b/app/controllers/admin/ci/variables_controller.rb @@ -31,7 +31,7 @@ class Admin::Ci::VariablesController < Admin::ApplicationController def render_instance_variables render status: :ok, - json: { + json: { variables: Ci::InstanceVariableSerializer.new.represent(variables) } end @@ -41,7 +41,7 @@ class Admin::Ci::VariablesController < Admin::ApplicationController end def variables_params - params.permit(variables_attributes: [*variable_params_attributes]) + params.permit(variables_attributes: Array(variable_params_attributes)) end def variable_params_attributes diff --git a/app/controllers/admin/dev_ops_report_controller.rb b/app/controllers/admin/dev_ops_report_controller.rb index 47e3337aed7..71ee19ddf39 100644 --- a/app/controllers/admin/dev_ops_report_controller.rb +++ b/app/controllers/admin/dev_ops_report_controller.rb @@ -1,11 +1,16 @@ # frozen_string_literal: true class Admin::DevOpsReportController < Admin::ApplicationController - include RedisTracking + include ProductAnalyticsTracking helper_method :show_adoption? - track_redis_hll_event :show, name: 'i_analytics_dev_ops_score', if: -> { should_track_devops_score? } + track_custom_event :show, + name: 'i_analytics_dev_ops_score', + action: 'perform_analytics_usage_action', + label: 'redis_hll_counters.analytics.analytics_total_unique_counts_monthly', + destinations: %i[redis_hll snowplow], + conditions: -> { should_track_devops_score? } feature_category :devops_reports @@ -24,6 +29,14 @@ class Admin::DevOpsReportController < Admin::ApplicationController def should_track_devops_score? true end + + def tracking_namespace_source + nil + end + + def tracking_project_source + nil + end end Admin::DevOpsReportController.prepend_mod_with('Admin::DevOpsReportController') diff --git a/app/controllers/admin/projects_controller.rb b/app/controllers/admin/projects_controller.rb index 6fd1e9bb70e..3f3c3581555 100644 --- a/app/controllers/admin/projects_controller.rb +++ b/app/controllers/admin/projects_controller.rb @@ -48,8 +48,8 @@ class Admin::ProjectsController < Admin::ApplicationController flash[:notice] = _("Project '%{project_name}' is in the process of being deleted.") % { project_name: @project.full_name } redirect_to admin_projects_path, status: :found - rescue Projects::DestroyService::DestroyError => ex - redirect_to admin_projects_path, status: :found, alert: ex.message + rescue Projects::DestroyService::DestroyError => e + redirect_to admin_projects_path, status: :found, alert: e.message end # rubocop: disable CodeReuse/ActiveRecord diff --git a/app/controllers/admin/runner_projects_controller.rb b/app/controllers/admin/runner_projects_controller.rb index 0165c6471db..7dbae565d07 100644 --- a/app/controllers/admin/runner_projects_controller.rb +++ b/app/controllers/admin/runner_projects_controller.rb @@ -9,7 +9,7 @@ class Admin::RunnerProjectsController < Admin::ApplicationController def create @runner = Ci::Runner.find(params[:runner_project][:runner_id]) - if ::Ci::Runners::AssignRunnerService.new(@runner, @project, current_user).execute + if ::Ci::Runners::AssignRunnerService.new(@runner, @project, current_user).execute.success? redirect_to edit_admin_runner_url(@runner), notice: s_('Runners|Runner assigned to project.') else redirect_to edit_admin_runner_url(@runner), alert: 'Failed adding runner to project' diff --git a/app/controllers/admin/system_info_controller.rb b/app/controllers/admin/system_info_controller.rb index f81b02ad31f..41f95addc66 100644 --- a/app/controllers/admin/system_info_controller.rb +++ b/app/controllers/admin/system_info_controller.rb @@ -37,8 +37,16 @@ class Admin::SystemInfoController < Admin::ApplicationController ].freeze def show - @cpus = Vmstat.cpu rescue nil - @memory = Vmstat.memory rescue nil + @cpus = begin + Vmstat.cpu + rescue StandardError + nil + end + @memory = begin + Vmstat.memory + rescue StandardError + nil + end mounts = Sys::Filesystem.mounts @disks = [] @@ -52,9 +60,9 @@ class Admin::SystemInfoController < Admin::ApplicationController disk = Sys::Filesystem.stat(mount.mount_point) @disks.push({ bytes_total: disk.bytes_total, - bytes_used: disk.bytes_used, - disk_name: mount.name, - mount_path: disk.path + bytes_used: disk.bytes_used, + disk_name: mount.name, + mount_path: disk.path }) rescue Sys::Filesystem::Error end diff --git a/app/controllers/admin/topics_controller.rb b/app/controllers/admin/topics_controller.rb index b451928e591..69bcfdf4791 100644 --- a/app/controllers/admin/topics_controller.rb +++ b/app/controllers/admin/topics_controller.rb @@ -45,6 +45,22 @@ class Admin::TopicsController < Admin::ApplicationController notice: _('Topic %{topic_name} was successfully removed.') % { topic_name: @topic.title_or_name } end + def merge + source_topic = Projects::Topic.find(merge_params[:source_topic_id]) + target_topic = Projects::Topic.find(merge_params[:target_topic_id]) + + begin + ::Topics::MergeService.new(source_topic, target_topic).execute + rescue ArgumentError => e + return render status: :bad_request, json: { type: :alert, message: e.message } + end + + message = _('Topic %{source_topic} was successfully merged into topic %{target_topic}.') + redirect_to admin_topics_path, + status: :found, + notice: message % { source_topic: source_topic.name, target_topic: target_topic.name } + end + private def topic @@ -63,4 +79,8 @@ class Admin::TopicsController < Admin::ApplicationController :title ] end + + def merge_params + params.permit([:source_topic_id, :target_topic_id]) + end end diff --git a/app/controllers/admin/usage_trends_controller.rb b/app/controllers/admin/usage_trends_controller.rb index 2cede1aec05..082b38ac3a8 100644 --- a/app/controllers/admin/usage_trends_controller.rb +++ b/app/controllers/admin/usage_trends_controller.rb @@ -1,9 +1,13 @@ # frozen_string_literal: true class Admin::UsageTrendsController < Admin::ApplicationController - include RedisTracking + include ProductAnalyticsTracking - track_redis_hll_event :index, name: 'i_analytics_instance_statistics' + track_custom_event :index, + name: 'i_analytics_instance_statistics', + action: 'perform_analytics_usage_action', + label: 'redis_hll_counters.analytics.analytics_total_unique_counts_monthly', + destinations: %i[redis_hll snowplow] feature_category :devops_reports @@ -11,4 +15,12 @@ class Admin::UsageTrendsController < Admin::ApplicationController def index end + + def tracking_namespace_source + @group + end + + def tracking_project_source + nil + end end diff --git a/app/controllers/admin/users_controller.rb b/app/controllers/admin/users_controller.rb index 874eb8985fb..5cc0c8f3970 100644 --- a/app/controllers/admin/users_controller.rb +++ b/app/controllers/admin/users_controller.rb @@ -88,7 +88,7 @@ class Admin::UsersController < Admin::ApplicationController result = Users::RejectService.new(current_user).execute(user) if result[:status] == :success - redirect_to admin_users_path, status: :found, notice: _("You've rejected %{user}" % { user: user.name }) + redirect_back_or_admin_user(notice: _("You've rejected %{user}" % { user: user.name })) else redirect_back_or_admin_user(alert: result[:message]) end diff --git a/app/controllers/autocomplete_controller.rb b/app/controllers/autocomplete_controller.rb index 6d1ffc1f2e8..88592efcec7 100644 --- a/app/controllers/autocomplete_controller.rb +++ b/app/controllers/autocomplete_controller.rb @@ -5,7 +5,6 @@ class AutocompleteController < ApplicationController skip_before_action :authenticate_user!, only: [:users, :award_emojis, :merge_request_target_branches] before_action :check_search_rate_limit!, only: [:users, :projects] - before_action :authorize_admin_project, only: :deploy_keys_with_owners feature_category :users, [:users, :user] feature_category :projects, [:projects] @@ -61,7 +60,9 @@ class AutocompleteController < ApplicationController end def deploy_keys_with_owners - deploy_keys = DeployKey.with_write_access_for_project(project) + deploy_keys = Autocomplete::DeployKeysWithWriteAccessFinder + .new(current_user, project) + .execute render json: DeployKeys::BasicDeployKeySerializer.new.represent( deploy_keys, { with_owner: true, user: current_user } @@ -70,10 +71,6 @@ class AutocompleteController < ApplicationController private - def authorize_admin_project - render_403 unless Ability.allowed?(current_user, :admin_project, project) - end - def project @project ||= Autocomplete::ProjectFinder .new(current_user, params) diff --git a/app/controllers/concerns/accepts_pending_invitations.rb b/app/controllers/concerns/accepts_pending_invitations.rb index 5601b7a7f79..53dec698fa0 100644 --- a/app/controllers/concerns/accepts_pending_invitations.rb +++ b/app/controllers/concerns/accepts_pending_invitations.rb @@ -3,12 +3,12 @@ module AcceptsPendingInvitations extend ActiveSupport::Concern - def accept_pending_invitations - return unless resource.active_for_authentication? + def accept_pending_invitations(user: resource) + return unless user.active_for_authentication? - if resource.pending_invitations.load.any? - resource.accept_pending_invitations! - clear_stored_location_for_resource + if user.pending_invitations.load.any? + user.accept_pending_invitations! + clear_stored_location_for(user: user) after_pending_invitations_hook end end @@ -17,8 +17,8 @@ module AcceptsPendingInvitations # no-op end - def clear_stored_location_for_resource - session_key = stored_location_key_for(resource) + def clear_stored_location_for(user:) + session_key = stored_location_key_for(user) session.delete(session_key) end diff --git a/app/controllers/concerns/creates_commit.rb b/app/controllers/concerns/creates_commit.rb index 0fb77e2aaf4..b6ba1b13cc3 100644 --- a/app/controllers/concerns/creates_commit.rb +++ b/app/controllers/concerns/creates_commit.rb @@ -98,8 +98,7 @@ module CreatesCommit project_new_merge_request_path( @project_to_commit_into, merge_request: { - source_project_id: @project_to_commit_into.id, - target_project_id: target_project.id, + target_project_id: @project_to_commit_into.default_merge_request_target.id, source_branch: @branch_name, target_branch: @start_branch } diff --git a/app/controllers/concerns/issuable_actions.rb b/app/controllers/concerns/issuable_actions.rb index a5e49b1b16a..f1d80e37674 100644 --- a/app/controllers/concerns/issuable_actions.rb +++ b/app/controllers/concerns/issuable_actions.rb @@ -171,7 +171,7 @@ module IssuableActions discussions = Discussion.build_collection(notes, issuable) if issuable.is_a?(MergeRequest) - render_cached(discussions, with: discussion_serializer, cache_context: -> (_) { discussion_cache_context }, context: self) + render_mr_discussions(discussions, discussion_serializer, discussion_cache_context) elsif issuable.is_a?(Issue) render json: discussion_serializer.represent(discussions, context: self) if stale?(etag: [discussion_cache_context, discussions]) else @@ -182,6 +182,20 @@ module IssuableActions private + def render_mr_discussions(discussions, serializer, cache_context) + return unless stale?(etag: [cache_context, discussions]) + + if Feature.enabled?(:disabled_mr_discussions_redis_cache, project) + render json: serializer.represent(discussions, context: self) + else + render_cached_discussions(discussions, serializer, cache_context) + end + end + + def render_cached_discussions(discussions, serializer, cache_context) + render_cached(discussions, with: serializer, cache_context: -> (_) { cache_context }, context: self) + end + def paginated_discussions return if params[:per_page].blank? return if issuable.instance_of?(MergeRequest) && Feature.disabled?(:paginated_mr_discussions, project) diff --git a/app/controllers/concerns/notes_actions.rb b/app/controllers/concerns/notes_actions.rb index 928c617471b..b595c3c6790 100644 --- a/app/controllers/concerns/notes_actions.rb +++ b/app/controllers/concerns/notes_actions.rb @@ -217,7 +217,8 @@ module NotesActions :note, :line_code, # LegacyDiffNote :position, # DiffNote - :confidential + :confidential, + :internal ).tap do |create_params| create_params.merge!( params.permit(:merge_request_diff_head_sha, :in_reply_to_discussion_id) diff --git a/app/controllers/concerns/product_analytics_tracking.rb b/app/controllers/concerns/product_analytics_tracking.rb index dc7ba8295b9..260b433cc6f 100644 --- a/app/controllers/concerns/product_analytics_tracking.rb +++ b/app/controllers/concerns/product_analytics_tracking.rb @@ -13,6 +13,14 @@ module ProductAnalyticsTracking route_events_to(destinations, name, &block) end end + + def track_custom_event(*controller_actions, name:, conditions: nil, action:, label:, destinations: [:redis_hll], &block) + custom_conditions = [:trackable_html_request?, *conditions] + + after_action only: controller_actions, if: custom_conditions do + route_custom_events_to(destinations, name, action, label, &block) + end + end end private @@ -25,13 +33,40 @@ module ProductAnalyticsTracking end end + def route_custom_events_to(destinations, name, action, label, &block) + track_unique_redis_hll_event(name, &block) if destinations.include?(:redis_hll) + + return unless destinations.include?(:snowplow) && event_enabled?(name) + + optional_arguments = { + namespace: tracking_namespace_source, + project: tracking_project_source + }.compact + + Gitlab::Tracking.event( + self.class.to_s, + action, + user: current_user, + property: name, + label: label, + **optional_arguments + ) + end + def event_enabled?(event) events_to_ff = { g_analytics_valuestream: :route_hll_to_snowplow, i_search_paid: :route_hll_to_snowplow_phase2, i_search_total: :route_hll_to_snowplow_phase2, - i_search_advanced: :route_hll_to_snowplow_phase2 + i_search_advanced: :route_hll_to_snowplow_phase2, + i_ecosystem_jira_service_list_issues: :route_hll_to_snowplow_phase2, + users_viewing_analytics_group_devops_adoption: :route_hll_to_snowplow_phase2, + i_analytics_dev_ops_adoption: :route_hll_to_snowplow_phase2, + i_analytics_dev_ops_score: :route_hll_to_snowplow_phase2, + p_analytics_merge_request: :route_hll_to_snowplow_phase2, + i_analytics_instance_statistics: :route_hll_to_snowplow_phase2, + g_analytics_contribution: :route_hll_to_snowplow_phase2 } Feature.enabled?(events_to_ff[event.to_sym], tracking_namespace_source) diff --git a/app/controllers/concerns/redis_tracking.rb b/app/controllers/concerns/redis_tracking.rb index c1135d2f759..445e72b8266 100644 --- a/app/controllers/concerns/redis_tracking.rb +++ b/app/controllers/concerns/redis_tracking.rb @@ -29,7 +29,7 @@ module RedisTracking private def track_unique_redis_hll_event(event_name, &block) - custom_id = block_given? ? yield(self) : nil + custom_id = block ? yield(self) : nil unique_id = custom_id || visitor_id diff --git a/app/controllers/concerns/uploads_actions.rb b/app/controllers/concerns/uploads_actions.rb index f914e804e18..e98d36854f1 100644 --- a/app/controllers/concerns/uploads_actions.rb +++ b/app/controllers/concerns/uploads_actions.rb @@ -143,10 +143,8 @@ module UploadsActions end def bypass_auth_checks_on_uploads? - if ::Feature.enabled?(:enforce_auth_checks_on_uploads, target_project) - if target_project && !target_project.public? && target_project.enforce_auth_checks_on_uploads? - return false - end + if target_project && !target_project.public? && target_project.enforce_auth_checks_on_uploads? + return false end action_name == 'show' && embeddable? diff --git a/app/controllers/groups/boards_controller.rb b/app/controllers/groups/boards_controller.rb index 0fbceb43be1..e64d838b7d1 100644 --- a/app/controllers/groups/boards_controller.rb +++ b/app/controllers/groups/boards_controller.rb @@ -10,8 +10,8 @@ class Groups::BoardsController < Groups::ApplicationController push_frontend_feature_flag(:board_multi_select, group) push_frontend_feature_flag(:realtime_labels, group) experiment(:prominent_create_board_btn, subject: current_user) do |e| - e.control { } - e.candidate { } + e.control {} + e.candidate {} end.run end diff --git a/app/controllers/groups/settings/ci_cd_controller.rb b/app/controllers/groups/settings/ci_cd_controller.rb index b1afac1f1c7..e164a834519 100644 --- a/app/controllers/groups/settings/ci_cd_controller.rb +++ b/app/controllers/groups/settings/ci_cd_controller.rb @@ -10,6 +10,9 @@ module Groups before_action :define_variables, only: [:show] before_action :push_licensed_features, only: [:show] before_action :assign_variables_to_gon, only: [:show] + before_action do + push_frontend_feature_flag(:ci_variable_settings_graphql, @group) + end feature_category :continuous_integration urgency :low diff --git a/app/controllers/groups/variables_controller.rb b/app/controllers/groups/variables_controller.rb index 1e23db9f32b..220b0b4509c 100644 --- a/app/controllers/groups/variables_controller.rb +++ b/app/controllers/groups/variables_controller.rb @@ -46,7 +46,7 @@ module Groups end def group_variables_params - params.permit(variables_attributes: [*variable_params_attributes]) + params.permit(variables_attributes: Array(variable_params_attributes)) end def variable_params_attributes diff --git a/app/controllers/groups_controller.rb b/app/controllers/groups_controller.rb index 327b4832f31..32b187c3260 100644 --- a/app/controllers/groups_controller.rb +++ b/app/controllers/groups_controller.rb @@ -34,6 +34,10 @@ class GroupsController < Groups::ApplicationController before_action :track_experiment_event, only: [:new] + before_action only: :issues do + push_force_frontend_feature_flag(:work_items, group.work_items_feature_flag_enabled?) + end + helper_method :captcha_required? skip_cross_project_access_check :index, :new, :create, :edit, :update, diff --git a/app/controllers/import/bulk_imports_controller.rb b/app/controllers/import/bulk_imports_controller.rb index 2d607fb7ff7..893c0b6ac54 100644 --- a/app/controllers/import/bulk_imports_controller.rb +++ b/app/controllers/import/bulk_imports_controller.rb @@ -47,7 +47,14 @@ class Import::BulkImportsController < ApplicationController end def create - responses = create_params.map { |entry| ::BulkImports::CreateService.new(current_user, entry, credentials).execute } + responses = create_params.map do |entry| + if entry[:destination_name] + entry[:destination_slug] ||= entry[:destination_name] + entry.delete(:destination_name) + end + + ::BulkImports::CreateService.new(current_user, entry, credentials).execute + end render json: responses.map { |response| { success: response.success?, id: response.payload[:id], message: response.message } } end @@ -100,6 +107,7 @@ class Import::BulkImportsController < ApplicationController source_type source_full_path destination_name + destination_slug destination_namespace ] end diff --git a/app/controllers/oauth/token_info_controller.rb b/app/controllers/oauth/token_info_controller.rb index 789356f4410..626184150bd 100644 --- a/app/controllers/oauth/token_info_controller.rb +++ b/app/controllers/oauth/token_info_controller.rb @@ -9,7 +9,7 @@ class Oauth::TokenInfoController < Doorkeeper::TokenInfoController # maintain backwards compatibility render json: token_json.merge( - 'scopes' => token_json[:scope], + 'scopes' => token_json[:scope], 'expires_in_seconds' => token_json[:expires_in] ), status: :ok else diff --git a/app/controllers/omniauth_callbacks_controller.rb b/app/controllers/omniauth_callbacks_controller.rb index 45decccfc36..817f272d458 100644 --- a/app/controllers/omniauth_callbacks_controller.rb +++ b/app/controllers/omniauth_callbacks_controller.rb @@ -6,6 +6,7 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController include AuthHelper include InitializesCurrentUserMode include KnownSignIn + include AcceptsPendingInvitations after_action :verify_known_sign_in @@ -25,7 +26,7 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController # the number of failed sign in attempts def failure if params[:username].present? && AuthHelper.form_based_provider?(failed_strategy.name) - user = User.by_login(params[:username]) + user = User.find_by_login(params[:username]) user&.increment_failed_attempts! log_failed_login(params[:username], failed_strategy.name) @@ -159,6 +160,7 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController def sign_in_user_flow(auth_user_class) auth_user = build_auth_user(auth_user_class) + new_user = auth_user.new? user = auth_user.find_and_update! if auth_user.valid_sign_in? @@ -178,6 +180,7 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController flash[:notice] = _('Welcome back! Your account had been deactivated due to inactivity but is now reactivated.') end + accept_pending_invitations(user: user) if new_user store_after_sign_up_path_for_user if intent_to_register? sign_in_and_redirect(user, event: :authentication) end diff --git a/app/controllers/profiles/personal_access_tokens_controller.rb b/app/controllers/profiles/personal_access_tokens_controller.rb index 1a8908e8571..07d786ab060 100644 --- a/app/controllers/profiles/personal_access_tokens_controller.rb +++ b/app/controllers/profiles/personal_access_tokens_controller.rb @@ -3,10 +3,6 @@ class Profiles::PersonalAccessTokensController < Profiles::ApplicationController feature_category :authentication_and_authorization - before_action do - push_frontend_feature_flag(:personal_access_tokens_scoped_to_projects, current_user) - end - def index set_index_vars scopes = params[:scopes].split(',').map(&:squish).select(&:present?).map(&:to_sym) unless params[:scopes].nil? @@ -62,7 +58,7 @@ class Profiles::PersonalAccessTokensController < Profiles::ApplicationController end def active_personal_access_tokens - tokens = finder(state: 'active', sort: 'expires_at_asc').execute + tokens = finder(state: 'active', sort: 'expires_at_asc_id_desc').execute if Feature.enabled?('access_token_pagination') tokens = tokens.page(page) diff --git a/app/controllers/profiles/two_factor_auths_controller.rb b/app/controllers/profiles/two_factor_auths_controller.rb index 2e71b4801ed..0b7d4626c6d 100644 --- a/app/controllers/profiles/two_factor_auths_controller.rb +++ b/app/controllers/profiles/two_factor_auths_controller.rb @@ -234,7 +234,7 @@ class Profiles::TwoFactorAuthsController < Profiles::ApplicationController def groups_notification(groups) group_links = groups.map { |group| view_context.link_to group.full_name, group_path(group) }.to_sentence - leave_group_links = groups.map { |group| view_context.link_to (s_("leave %{group_name}") % { group_name: group.full_name }), leave_group_members_path(group), remote: false, method: :delete}.to_sentence + leave_group_links = groups.map { |group| view_context.link_to (s_("leave %{group_name}") % { group_name: group.full_name }), leave_group_members_path(group), remote: false, method: :delete }.to_sentence s_(%{The group settings for %{group_links} require you to enable Two-Factor Authentication for your account. You can %{leave_group_links}.}) .html_safe % { group_links: group_links.html_safe, leave_group_links: leave_group_links.html_safe } diff --git a/app/controllers/projects/alerting/notifications_controller.rb b/app/controllers/projects/alerting/notifications_controller.rb index 82fff287c4a..f3283c88740 100644 --- a/app/controllers/projects/alerting/notifications_controller.rb +++ b/app/controllers/projects/alerting/notifications_controller.rb @@ -13,8 +13,6 @@ module Projects prepend_before_action :repository, :project_without_auth feature_category :incident_management - # Goal is to increase the urgency to medium. - # See https://gitlab.com/gitlab-org/gitlab/-/issues/361310. urgency :low, [:create] def create diff --git a/app/controllers/projects/analytics/cycle_analytics/stages_controller.rb b/app/controllers/projects/analytics/cycle_analytics/stages_controller.rb index 7b38c069a60..ab2cf3abdde 100644 --- a/app/controllers/projects/analytics/cycle_analytics/stages_controller.rb +++ b/app/controllers/projects/analytics/cycle_analytics/stages_controller.rb @@ -2,6 +2,7 @@ class Projects::Analytics::CycleAnalytics::StagesController < Projects::ApplicationController include ::Analytics::CycleAnalytics::StageActions + include Gitlab::Utils::StrongMemoize extend ::Gitlab::Utils::Override respond_to :json @@ -10,6 +11,7 @@ class Projects::Analytics::CycleAnalytics::StagesController < Projects::Applicat before_action :authorize_read_cycle_analytics! before_action :only_default_value_stream_is_allowed! + before_action :authorize_stage!, only: [:median, :count, :average, :records] urgency :low @@ -25,7 +27,26 @@ class Projects::Analytics::CycleAnalytics::StagesController < Projects::Applicat Analytics::CycleAnalytics::ProjectValueStream end + override :cycle_analytics_configuration + def cycle_analytics_configuration(stages) + super(stages.select { |stage| permitted_stage?(stage) }) + end + def only_default_value_stream_is_allowed! render_404 if params[:value_stream_id] != Analytics::CycleAnalytics::Stages::BaseService::DEFAULT_VALUE_STREAM_NAME end + + def permitted_stage?(stage) + permissions[stage.name.to_sym] # name matches the permission key (only when default stages are used) + end + + def permissions + strong_memoize(:permissions) do + Gitlab::CycleAnalytics::Permissions.new(user: current_user, project: parent).get + end + end + + def authorize_stage! + render_403 unless permitted_stage?(stage) + end end diff --git a/app/controllers/projects/blob_controller.rb b/app/controllers/projects/blob_controller.rb index 97aae56c4ec..f5188e28b81 100644 --- a/app/controllers/projects/blob_controller.rb +++ b/app/controllers/projects/blob_controller.rb @@ -43,6 +43,7 @@ class Projects::BlobController < Projects::ApplicationController before_action do push_frontend_feature_flag(:highlight_js, @project) + push_frontend_feature_flag(:file_line_blame, @project) push_licensed_feature(:file_locks) if @project.licensed_feature_available?(:file_locks) end diff --git a/app/controllers/projects/boards_controller.rb b/app/controllers/projects/boards_controller.rb index 36986a714fb..82b35a22669 100644 --- a/app/controllers/projects/boards_controller.rb +++ b/app/controllers/projects/boards_controller.rb @@ -10,8 +10,8 @@ class Projects::BoardsController < Projects::ApplicationController push_frontend_feature_flag(:board_multi_select, project) push_frontend_feature_flag(:realtime_labels, project&.group) experiment(:prominent_create_board_btn, subject: current_user) do |e| - e.control { } - e.candidate { } + e.control {} + e.candidate {} end.run end diff --git a/app/controllers/projects/ci/pipeline_editor_controller.rb b/app/controllers/projects/ci/pipeline_editor_controller.rb index 85e258b62e8..84e5d59a2c3 100644 --- a/app/controllers/projects/ci/pipeline_editor_controller.rb +++ b/app/controllers/projects/ci/pipeline_editor_controller.rb @@ -4,7 +4,6 @@ class Projects::Ci::PipelineEditorController < Projects::ApplicationController before_action :check_can_collaborate! before_action do push_frontend_feature_flag(:schema_linting, @project) - push_frontend_feature_flag(:simulate_pipeline, @project) end feature_category :pipeline_authoring diff --git a/app/controllers/projects/ci/secure_files_controller.rb b/app/controllers/projects/ci/secure_files_controller.rb deleted file mode 100644 index 59ddca19081..00000000000 --- a/app/controllers/projects/ci/secure_files_controller.rb +++ /dev/null @@ -1,11 +0,0 @@ -# frozen_string_literal: true - -class Projects::Ci::SecureFilesController < Projects::ApplicationController - before_action :authorize_read_secure_files! - - feature_category :pipeline_authoring - - def show - render_404 unless Feature.enabled?(:ci_secure_files, project) - end -end diff --git a/app/controllers/projects/compare_controller.rb b/app/controllers/projects/compare_controller.rb index 09a06aaed8c..d7fd65f02a8 100644 --- a/app/controllers/projects/compare_controller.rb +++ b/app/controllers/projects/compare_controller.rb @@ -88,7 +88,7 @@ class Projects::CompareController < Projects::ApplicationController # target == start_ref == from def target_project strong_memoize(:target_project) do - next source_project unless compare_params.key?(:from_project_id) + next source_project.default_merge_request_target unless compare_params.key?(:from_project_id) next source_project if compare_params[:from_project_id].to_i == source_project.id target_project = target_projects(source_project).find_by_id(compare_params[:from_project_id]) diff --git a/app/controllers/projects/feature_flags_controller.rb b/app/controllers/projects/feature_flags_controller.rb index 1d1fe91ad70..16392775c09 100644 --- a/app/controllers/projects/feature_flags_controller.rb +++ b/app/controllers/projects/feature_flags_controller.rb @@ -111,9 +111,9 @@ class Projects::FeatureFlagsController < Projects::ApplicationController .permit(:name, :description, :active, scopes_attributes: [:id, :environment_scope, :active, :_destroy, strategies: [:name, parameters: [:groupId, :percentage, :userIds]]], - strategies_attributes: [:id, :name, :user_list_id, :_destroy, - parameters: [:groupId, :percentage, :userIds, :rollout, :stickiness], - scopes_attributes: [:id, :environment_scope, :_destroy]]) + strategies_attributes: [:id, :name, :user_list_id, :_destroy, + parameters: [:groupId, :percentage, :userIds, :rollout, :stickiness], + scopes_attributes: [:id, :environment_scope, :_destroy]]) end def feature_flag_json(feature_flag) diff --git a/app/controllers/projects/google_cloud/base_controller.rb b/app/controllers/projects/google_cloud/base_controller.rb index 050b26a40c7..d1eb86c5e49 100644 --- a/app/controllers/projects/google_cloud/base_controller.rb +++ b/app/controllers/projects/google_cloud/base_controller.rb @@ -80,4 +80,16 @@ class Projects::GoogleCloud::BaseController < Projects::ApplicationController Gitlab::Tracking.event('Projects::GoogleCloud', action, **options) end + + def gcp_projects + google_api_client = GoogleApi::CloudPlatform::Client.new(token_in_session, nil) + google_api_client.list_projects + end + + def refs + params = { per_page: 50 } + branches = BranchesFinder.new(project.repository, params).execute(gitaly_pagination: true) + tags = TagsFinder.new(project.repository, params).execute(gitaly_pagination: true) + (branches + tags).map(&:name) + end end diff --git a/app/controllers/projects/google_cloud/configuration_controller.rb b/app/controllers/projects/google_cloud/configuration_controller.rb index fa672058247..8d252c35031 100644 --- a/app/controllers/projects/google_cloud/configuration_controller.rb +++ b/app/controllers/projects/google_cloud/configuration_controller.rb @@ -4,7 +4,6 @@ module Projects module GoogleCloud class ConfigurationController < Projects::GoogleCloud::BaseController def index - @google_cloud_path = project_google_cloud_configuration_path(project) js_data = { configurationUrl: project_google_cloud_configuration_path(project), deploymentsUrl: project_google_cloud_deployments_path(project), diff --git a/app/controllers/projects/google_cloud/databases_controller.rb b/app/controllers/projects/google_cloud/databases_controller.rb index 711409e7550..7b1cf6e5ce1 100644 --- a/app/controllers/projects/google_cloud/databases_controller.rb +++ b/app/controllers/projects/google_cloud/databases_controller.rb @@ -4,7 +4,6 @@ module Projects module GoogleCloud class DatabasesController < Projects::GoogleCloud::BaseController def index - @google_cloud_path = project_google_cloud_configuration_path(project) js_data = { configurationUrl: project_google_cloud_configuration_path(project), deploymentsUrl: project_google_cloud_deployments_path(project), diff --git a/app/controllers/projects/google_cloud/deployments_controller.rb b/app/controllers/projects/google_cloud/deployments_controller.rb index 4aa17b36fad..1ac4697a63f 100644 --- a/app/controllers/projects/google_cloud/deployments_controller.rb +++ b/app/controllers/projects/google_cloud/deployments_controller.rb @@ -4,7 +4,6 @@ class Projects::GoogleCloud::DeploymentsController < Projects::GoogleCloud::Base before_action :validate_gcp_token! def index - @google_cloud_path = project_google_cloud_configuration_path(project) js_data = { configurationUrl: project_google_cloud_configuration_path(project), deploymentsUrl: project_google_cloud_deployments_path(project), @@ -40,9 +39,9 @@ class Projects::GoogleCloud::DeploymentsController < Projects::GoogleCloud::Base redirect_to project_new_merge_request_path(project, merge_request: cloud_run_mr_params) end end - rescue Google::Apis::ClientError, Google::Apis::ServerError, Google::Apis::AuthorizationError => error - track_event('deployments#cloud_run', 'error_gcp', error) - flash[:warning] = _('Google Cloud Error - %{error}') % { error: error } + rescue Google::Apis::ClientError, Google::Apis::ServerError, Google::Apis::AuthorizationError => e + track_event('deployments#cloud_run', 'error_gcp', e) + flash[:warning] = _('Google Cloud Error - %{error}') % { error: e } redirect_to project_google_cloud_deployments_path(project) end diff --git a/app/controllers/projects/google_cloud/gcp_regions_controller.rb b/app/controllers/projects/google_cloud/gcp_regions_controller.rb index 3fbe9a96284..39f33624804 100644 --- a/app/controllers/projects/google_cloud/gcp_regions_controller.rb +++ b/app/controllers/projects/google_cloud/gcp_regions_controller.rb @@ -9,13 +9,7 @@ class Projects::GoogleCloud::GcpRegionsController < Projects::GoogleCloud::BaseC GCP_REGION_CI_VAR_KEY = 'GCP_REGION' def index - @google_cloud_path = project_google_cloud_configuration_path(project) - params = { per_page: 50 } - branches = BranchesFinder.new(project.repository, params).execute(gitaly_pagination: true) - tags = TagsFinder.new(project.repository, params).execute(gitaly_pagination: true) - refs = (branches + tags).map(&:name) js_data = { - screen: 'gcp_regions_form', availableRegions: AVAILABLE_REGIONS, refs: refs, cancelPath: project_google_cloud_configuration_path(project) diff --git a/app/controllers/projects/google_cloud/service_accounts_controller.rb b/app/controllers/projects/google_cloud/service_accounts_controller.rb index dbd83be19db..7f25054177e 100644 --- a/app/controllers/projects/google_cloud/service_accounts_controller.rb +++ b/app/controllers/projects/google_cloud/service_accounts_controller.rb @@ -4,22 +4,12 @@ class Projects::GoogleCloud::ServiceAccountsController < Projects::GoogleCloud:: before_action :validate_gcp_token! def index - @google_cloud_path = project_google_cloud_configuration_path(project) - google_api_client = GoogleApi::CloudPlatform::Client.new(token_in_session, nil) - gcp_projects = google_api_client.list_projects - if gcp_projects.empty? - @js_data = { screen: 'no_gcp_projects' }.to_json track_event('service_accounts#index', 'error_form', 'no_gcp_projects') flash[:warning] = _('No Google Cloud projects - You need at least one Google Cloud project') redirect_to project_google_cloud_configuration_path(project) else - params = { per_page: 50 } - branches = BranchesFinder.new(project.repository, params).execute(gitaly_pagination: true) - tags = TagsFinder.new(project.repository, params).execute(gitaly_pagination: true) - refs = (branches + tags).map(&:name) js_data = { - screen: 'service_accounts_form', gcpProjects: gcp_projects, refs: refs, cancelPath: project_google_cloud_configuration_path(project) @@ -28,9 +18,9 @@ class Projects::GoogleCloud::ServiceAccountsController < Projects::GoogleCloud:: track_event('service_accounts#index', 'success', js_data) end - rescue Google::Apis::ClientError, Google::Apis::ServerError, Google::Apis::AuthorizationError => error - track_event('service_accounts#index', 'error_gcp', error) - flash[:warning] = _('Google Cloud Error - %{error}') % { error: error } + rescue Google::Apis::ClientError, Google::Apis::ServerError, Google::Apis::AuthorizationError => e + track_event('service_accounts#index', 'error_gcp', e) + flash[:warning] = _('Google Cloud Error - %{error}') % { error: e } redirect_to project_google_cloud_configuration_path(project) end @@ -47,9 +37,9 @@ class Projects::GoogleCloud::ServiceAccountsController < Projects::GoogleCloud:: track_event('service_accounts#create', 'success', response) redirect_to project_google_cloud_configuration_path(project), notice: response.message - rescue Google::Apis::ClientError, Google::Apis::ServerError, Google::Apis::AuthorizationError => error - track_event('service_accounts#create', 'error_gcp', error) - flash[:warning] = _('Google Cloud Error - %{error}') % { error: error } + rescue Google::Apis::ClientError, Google::Apis::ServerError, Google::Apis::AuthorizationError => e + track_event('service_accounts#create', 'error_gcp', e) + flash[:warning] = _('Google Cloud Error - %{error}') % { error: e } redirect_to project_google_cloud_configuration_path(project) end end diff --git a/app/controllers/projects/incidents_controller.rb b/app/controllers/projects/incidents_controller.rb index f9fa8046962..36b52533e78 100644 --- a/app/controllers/projects/incidents_controller.rb +++ b/app/controllers/projects/incidents_controller.rb @@ -9,7 +9,7 @@ class Projects::IncidentsController < Projects::ApplicationController before_action do push_frontend_feature_flag(:incident_timeline, @project) push_force_frontend_feature_flag(:work_items, @project&.work_items_feature_flag_enabled?) - push_frontend_feature_flag(:work_items_mvc_2) + push_force_frontend_feature_flag(:work_items_mvc_2, @project&.work_items_mvc_2_feature_flag_enabled?) push_frontend_feature_flag(:work_items_hierarchy, @project) end diff --git a/app/controllers/projects/issues_controller.rb b/app/controllers/projects/issues_controller.rb index f1c9e2b2653..d19db2b11ab 100644 --- a/app/controllers/projects/issues_controller.rb +++ b/app/controllers/projects/issues_controller.rb @@ -44,12 +44,16 @@ class Projects::IssuesController < Projects::ApplicationController push_frontend_feature_flag(:incident_timeline, project) end + before_action only: [:index, :show] do + push_force_frontend_feature_flag(:work_items, project&.work_items_feature_flag_enabled?) + end + before_action only: :show do push_frontend_feature_flag(:issue_assignees_widget, project) push_frontend_feature_flag(:realtime_labels, project) - push_force_frontend_feature_flag(:work_items, project&.work_items_feature_flag_enabled?) - push_frontend_feature_flag(:work_items_mvc_2) + push_force_frontend_feature_flag(:work_items_mvc_2, project&.work_items_mvc_2_feature_flag_enabled?) push_frontend_feature_flag(:work_items_hierarchy, project) + push_force_frontend_feature_flag(:work_items_create_from_markdown, project&.work_items_create_from_markdown_feature_flag_enabled?) end around_action :allow_gitaly_ref_name_caching, only: [:discussions] @@ -239,12 +243,12 @@ class Projects::IssuesController < Projects::ApplicationController end def import_csv - if uploader = UploadService.new(project, params[:file]).execute - ImportIssuesCsvWorker.perform_async(current_user.id, project.id, uploader.upload.id) # rubocop:disable CodeReuse/Worker + result = Issues::PrepareImportCsvService.new(project, current_user, file: params[:file]).execute - flash[:notice] = _("Your issues are being imported. Once finished, you'll get a confirmation email.") + if result.success? + flash[:notice] = result.message else - flash[:alert] = _("File upload error.") + flash[:alert] = result.message end redirect_to project_issues_path(project) diff --git a/app/controllers/projects/jobs_controller.rb b/app/controllers/projects/jobs_controller.rb index ad59f421c06..7878ace5015 100644 --- a/app/controllers/projects/jobs_controller.rb +++ b/app/controllers/projects/jobs_controller.rb @@ -18,7 +18,7 @@ class Projects::JobsController < Projects::ApplicationController before_action :verify_api_request!, only: :terminal_websocket_authorize before_action :authorize_create_proxy_build!, only: :proxy_websocket_authorize before_action :verify_proxy_request!, only: :proxy_websocket_authorize - before_action :push_job_log_search, only: [:show] + before_action :push_job_log_jump_to_failures, only: [:show] before_action :reject_if_build_artifacts_size_refreshing!, only: [:erase] layout 'project' @@ -249,7 +249,7 @@ class Projects::JobsController < Projects::ApplicationController ::Gitlab::Workhorse.channel_websocket(service) end - def push_job_log_search - push_frontend_feature_flag(:job_log_search, @project) + def push_job_log_jump_to_failures + push_frontend_feature_flag(:job_log_jump_to_failures, @project) end end diff --git a/app/controllers/projects/merge_requests/diffs_controller.rb b/app/controllers/projects/merge_requests/diffs_controller.rb index 0dcc2bc3181..279fd4c457e 100644 --- a/app/controllers/projects/merge_requests/diffs_controller.rb +++ b/app/controllers/projects/merge_requests/diffs_controller.rb @@ -48,20 +48,24 @@ class Projects::MergeRequests::DiffsController < Projects::MergeRequests::Applic allow_tree_conflicts: display_merge_conflicts_in_diff? } - if diff_options_hash[:paths].blank? - # NOTE: Any variables that would affect the resulting json needs to be added to the cache_context to avoid stale cache issues. - cache_context = [ - current_user&.cache_key, - unfoldable_positions.map(&:to_h), - diff_view, - params[:w], - params[:expanded], - params[:page], - params[:per_page], - options[:merge_ref_head_diff], - options[:allow_tree_conflicts] - ] + # NOTE: Any variables that would affect the resulting json needs to be added to the cache_context to avoid stale cache issues. + cache_context = [ + current_user&.cache_key, + unfoldable_positions.map(&:to_h), + diff_view, + params[:w], + params[:expanded], + params[:page], + params[:per_page], + options[:merge_ref_head_diff], + options[:allow_tree_conflicts] + ] + + if Feature.enabled?(:etag_merge_request_diff_batches, @merge_request.project) + return unless stale?(etag: [cache_context + diff_options_hash.fetch(:paths, []), diffs]) + end + if diff_options_hash[:paths].blank? render_cached( diffs, with: PaginatedDiffSerializer.new(current_user: current_user), diff --git a/app/controllers/projects/merge_requests/drafts_controller.rb b/app/controllers/projects/merge_requests/drafts_controller.rb index db7557674b2..ff6b6bfaf27 100644 --- a/app/controllers/projects/merge_requests/drafts_controller.rb +++ b/app/controllers/projects/merge_requests/drafts_controller.rb @@ -72,9 +72,9 @@ class Projects::MergeRequests::DraftsController < Projects::MergeRequests::Appli strong_memoize(:draft_note) do draft_notes.find(params[:id]) end - rescue ActiveRecord::RecordNotFound => ex + rescue ActiveRecord::RecordNotFound => e # draft_note is allowed to be nil in #publish - raise ex unless allow_nil + raise e unless allow_nil end def draft_notes diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb index a2f018c013b..870c57fd6f3 100644 --- a/app/controllers/projects/merge_requests_controller.rb +++ b/app/controllers/projects/merge_requests_controller.rb @@ -34,16 +34,13 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo before_action only: [:show] do push_frontend_feature_flag(:merge_request_widget_graphql, project) push_frontend_feature_flag(:core_security_mr_widget_counts, project) - push_frontend_feature_flag(:restructured_mr_widget, project) push_frontend_feature_flag(:refactor_mr_widgets_extensions, project) push_frontend_feature_flag(:refactor_code_quality_extension, project) push_frontend_feature_flag(:refactor_mr_widget_test_summary, project) - push_frontend_feature_flag(:rebase_without_ci_ui, project) push_frontend_feature_flag(:issue_assignees_widget, @project) push_frontend_feature_flag(:realtime_labels, project) push_frontend_feature_flag(:refactor_security_extension, @project) push_frontend_feature_flag(:refactor_code_quality_inline_findings, project) - push_frontend_feature_flag(:mr_attention_requests, current_user) push_frontend_feature_flag(:moved_mr_sidebar, project) push_frontend_feature_flag(:paginated_mr_discussions, project) push_frontend_feature_flag(:mr_review_submit_comment, project) @@ -367,7 +364,7 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo end def rebase - @merge_request.rebase_async(current_user.id) + @merge_request.rebase_async(current_user.id, skip_ci: Gitlab::Utils.to_boolean(merge_params[:skip_ci], default: false)) head :ok rescue MergeRequest::RebaseLockTimeout => e diff --git a/app/controllers/projects/milestones_controller.rb b/app/controllers/projects/milestones_controller.rb index 744e45a0f9c..cfb67b7b4ff 100644 --- a/app/controllers/projects/milestones_controller.rb +++ b/app/controllers/projects/milestones_controller.rb @@ -92,8 +92,8 @@ class Projects::MilestonesController < Projects::ApplicationController render json: { url: project_milestones_path(project) } end end - rescue Milestones::PromoteService::PromoteMilestoneError => error - redirect_to milestone, alert: error.message + rescue Milestones::PromoteService::PromoteMilestoneError => e + redirect_to milestone, alert: e.message end def flash_notice_for(milestone, group) diff --git a/app/controllers/projects/mirrors_controller.rb b/app/controllers/projects/mirrors_controller.rb index bcb6b574d5a..acbd26cbdf6 100644 --- a/app/controllers/projects/mirrors_controller.rb +++ b/app/controllers/projects/mirrors_controller.rb @@ -58,8 +58,8 @@ class Projects::MirrorsController < Projects::ApplicationController else render json: lookup end - rescue ArgumentError => err - render json: { message: err.message }, status: :bad_request + rescue ArgumentError => e + render json: { message: e.message }, status: :bad_request end private diff --git a/app/controllers/projects/pages_controller.rb b/app/controllers/projects/pages_controller.rb index 4bd33882eee..0e990b64cd6 100644 --- a/app/controllers/projects/pages_controller.rb +++ b/app/controllers/projects/pages_controller.rb @@ -10,11 +10,29 @@ class Projects::PagesController < Projects::ApplicationController feature_category :pages - # rubocop: disable CodeReuse/ActiveRecord + def new + @pipeline_wizard_data = { + project_path: @project.full_path, + default_branch: @project.repository.root_ref, + redirect_to_when_done: project_pages_path(@project) + } + end + def show + unless @project.pages_enabled? + render :disabled + return + end + + if @project.pages_show_onboarding? + redirect_to action: 'new' + return + end + + # rubocop: disable CodeReuse/ActiveRecord @domains = @project.pages_domains.order(:domain).present(current_user: current_user) + # rubocop: enable CodeReuse/ActiveRecord end - # rubocop: enable CodeReuse/ActiveRecord def destroy ::Pages::DeleteService.new(@project, current_user).execute diff --git a/app/controllers/projects/pipelines/stages_controller.rb b/app/controllers/projects/pipelines/stages_controller.rb index 0447bbf29e7..c94d468cf2e 100644 --- a/app/controllers/projects/pipelines/stages_controller.rb +++ b/app/controllers/projects/pipelines/stages_controller.rb @@ -4,6 +4,7 @@ module Projects module Pipelines class StagesController < Projects::Pipelines::ApplicationController before_action :authorize_update_pipeline! + before_action :stage, only: [:play_manual] urgency :low, [ :play_manual @@ -26,7 +27,7 @@ module Projects private def stage - @pipeline_stage ||= pipeline.find_stage_by_name!(params[:stage_name]) + @stage ||= pipeline.stage(params[:stage_name]).presence || render_404 end end end diff --git a/app/controllers/projects/repositories_controller.rb b/app/controllers/projects/repositories_controller.rb index 9fc75fff807..33ce37ef4fb 100644 --- a/app/controllers/projects/repositories_controller.rb +++ b/app/controllers/projects/repositories_controller.rb @@ -35,8 +35,8 @@ class Projects::RepositoriesController < Projects::ApplicationController return if archive_not_modified? send_git_archive @repository, **repo_params - rescue StandardError => ex - logger.error("#{self.class.name}: #{ex}") + rescue StandardError => e + logger.error("#{self.class.name}: #{e}") git_not_found! end diff --git a/app/controllers/projects/runner_projects_controller.rb b/app/controllers/projects/runner_projects_controller.rb index 34ce8df202b..5946c43b134 100644 --- a/app/controllers/projects/runner_projects_controller.rb +++ b/app/controllers/projects/runner_projects_controller.rb @@ -15,7 +15,7 @@ class Projects::RunnerProjectsController < Projects::ApplicationController path = project_runners_path(project) - if ::Ci::Runners::AssignRunnerService.new(@runner, @project, current_user).execute + if ::Ci::Runners::AssignRunnerService.new(@runner, @project, current_user).execute.success? redirect_to path, notice: s_('Runners|Runner assigned to project.') else assign_to_messages = @runner.errors.messages[:assign_to] diff --git a/app/controllers/projects/settings/integration_hook_logs_controller.rb b/app/controllers/projects/settings/integration_hook_logs_controller.rb index b3b5a292d42..1e42fbce4c4 100644 --- a/app/controllers/projects/settings/integration_hook_logs_controller.rb +++ b/app/controllers/projects/settings/integration_hook_logs_controller.rb @@ -20,7 +20,7 @@ module Projects override :hook def hook - @hook ||= integration.service_hook || not_found + @hook ||= integration.try(:service_hook) || not_found end end end diff --git a/app/controllers/projects/settings/integrations_controller.rb b/app/controllers/projects/settings/integrations_controller.rb index cee9e9feb7b..03ef434456f 100644 --- a/app/controllers/projects/settings/integrations_controller.rb +++ b/app/controllers/projects/settings/integrations_controller.rb @@ -122,7 +122,7 @@ module Projects end def web_hook_logs - return unless integration.service_hook.present? + return unless integration.try(:service_hook).present? @web_hook_logs ||= integration.service_hook.web_hook_logs.recent.page(params[:page]) end diff --git a/app/controllers/projects/settings/packages_and_registries_controller.rb b/app/controllers/projects/settings/packages_and_registries_controller.rb index d3c08bef808..76c9cead360 100644 --- a/app/controllers/projects/settings/packages_and_registries_controller.rb +++ b/app/controllers/projects/settings/packages_and_registries_controller.rb @@ -14,11 +14,22 @@ module Projects def show end + def cleanup_tags + registry_settings_enabled! + + @hide_search_settings = true + end + private def packages_and_registries_settings_enabled! render_404 unless can?(current_user, :view_package_registry_project_settings, project) end + + def registry_settings_enabled! + render_404 unless Gitlab.config.registry.enabled && + can?(current_user, :admin_container_image, project) + end end end end diff --git a/app/controllers/projects/tags/releases_controller.rb b/app/controllers/projects/tags/releases_controller.rb deleted file mode 100644 index adeadf2133e..00000000000 --- a/app/controllers/projects/tags/releases_controller.rb +++ /dev/null @@ -1,39 +0,0 @@ -# frozen_string_literal: true - -# TODO: remove this file together with FF https://gitlab.com/gitlab-org/gitlab/-/issues/366244 -# also delete view/routes -class Projects::Tags::ReleasesController < Projects::ApplicationController - # Authorize - before_action :require_non_empty_project - before_action :authorize_download_code! - before_action :authorize_push_code! - before_action :tag - before_action :release - - feature_category :release_evidence - urgency :low - - def edit - end - - def update - release.update(release_params) if release.persisted? || release_params[:description].present? - - redirect_to project_tag_path(@project, tag.name) - end - - private - - def tag - @tag ||= @repository.find_tag(params[:tag_id]) - end - - def release - @release ||= Releases::CreateService.new(project, current_user, tag: @tag.name) - .find_or_build_release - end - - def release_params - params.require(:release).permit(:description) - end -end diff --git a/app/controllers/projects/tree_controller.rb b/app/controllers/projects/tree_controller.rb index ce51cbb6677..fea2689db14 100644 --- a/app/controllers/projects/tree_controller.rb +++ b/app/controllers/projects/tree_controller.rb @@ -19,6 +19,7 @@ class Projects::TreeController < Projects::ApplicationController before_action do push_frontend_feature_flag(:lazy_load_commits, @project) push_frontend_feature_flag(:highlight_js, @project) + push_frontend_feature_flag(:file_line_blame, @project) push_licensed_feature(:file_locks) if @project.licensed_feature_available?(:file_locks) end diff --git a/app/controllers/projects/variables_controller.rb b/app/controllers/projects/variables_controller.rb index e7bccf5a243..a8f062bd7c1 100644 --- a/app/controllers/projects/variables_controller.rb +++ b/app/controllers/projects/variables_controller.rb @@ -43,7 +43,7 @@ class Projects::VariablesController < Projects::ApplicationController end def variables_params - params.permit(variables_attributes: [*variable_params_attributes]) + params.permit(variables_attributes: Array(variable_params_attributes)) end def variable_params_attributes diff --git a/app/controllers/projects/work_items_controller.rb b/app/controllers/projects/work_items_controller.rb index ba23af41bb0..b794785f285 100644 --- a/app/controllers/projects/work_items_controller.rb +++ b/app/controllers/projects/work_items_controller.rb @@ -3,7 +3,7 @@ class Projects::WorkItemsController < Projects::ApplicationController before_action do push_force_frontend_feature_flag(:work_items, project&.work_items_feature_flag_enabled?) - push_frontend_feature_flag(:work_items_mvc_2) + push_force_frontend_feature_flag(:work_items_mvc_2, project&.work_items_mvc_2_feature_flag_enabled?) push_frontend_feature_flag(:work_items_hierarchy, project) end diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb index 37e472050a0..8a6bcb4b3fc 100644 --- a/app/controllers/projects_controller.rb +++ b/app/controllers/projects_controller.rb @@ -37,17 +37,18 @@ class ProjectsController < Projects::ApplicationController before_action do push_frontend_feature_flag(:lazy_load_commits, @project) push_frontend_feature_flag(:highlight_js, @project) + push_frontend_feature_flag(:file_line_blame, @project) push_frontend_feature_flag(:increase_page_size_exponentially, @project) push_licensed_feature(:file_locks) if @project.present? && @project.licensed_feature_available?(:file_locks) push_licensed_feature(:security_orchestration_policies) if @project.present? && @project.licensed_feature_available?(:security_orchestration_policies) push_force_frontend_feature_flag(:work_items, @project&.work_items_feature_flag_enabled?) - push_frontend_feature_flag(:work_items_mvc_2) + push_force_frontend_feature_flag(:work_items_mvc_2, @project&.work_items_mvc_2_feature_flag_enabled?) push_frontend_feature_flag(:package_registry_access_level) push_frontend_feature_flag(:work_items_hierarchy, @project) end before_action only: :edit do - push_frontend_feature_flag(:enforce_auth_checks_on_uploads, @project) + push_frontend_feature_flag(:split_operations_visibility_permissions, @project) end layout :determine_layout @@ -197,8 +198,8 @@ class ProjectsController < Projects::ApplicationController flash[:notice] = _("Project '%{project_name}' is in the process of being deleted.") % { project_name: @project.full_name } redirect_to dashboard_projects_path, status: :found - rescue Projects::DestroyService::DestroyError => ex - redirect_to edit_project_path(@project), status: :found, alert: ex.message + rescue Projects::DestroyService::DestroyError => e + redirect_to edit_project_path(@project), status: :found, alert: e.message end def new_issuable_address @@ -231,10 +232,10 @@ class ProjectsController < Projects::ApplicationController project_path(@project), notice: _("Housekeeping successfully started") ) - rescue ::Repositories::HousekeepingService::LeaseTaken => ex + rescue ::Repositories::HousekeepingService::LeaseTaken => e redirect_to( edit_project_path(@project, anchor: 'js-project-advanced-settings'), - alert: ex.to_s + alert: e.to_s ) end @@ -245,10 +246,10 @@ class ProjectsController < Projects::ApplicationController edit_project_path(@project, anchor: 'js-export-project'), notice: _("Project export started. A download link will be sent by email and made available on this page.") ) - rescue Project::ExportLimitExceeded => ex + rescue Project::ExportLimitExceeded => e redirect_to( edit_project_path(@project, anchor: 'js-export-project'), - alert: ex.to_s + alert: e.to_s ) end @@ -420,10 +421,19 @@ class ProjectsController < Projects::ApplicationController pages_access_level metrics_dashboard_access_level analytics_access_level - operations_access_level security_and_compliance_access_level container_registry_access_level - ] + ] + operations_feature_attributes + end + + def operations_feature_attributes + if Feature.enabled?(:split_operations_visibility_permissions, project) + %i[ + environments_access_level feature_flags_access_level releases_access_level + ] + else + %i[operations_access_level] + end end def project_setting_attributes diff --git a/app/controllers/registrations_controller.rb b/app/controllers/registrations_controller.rb index bb16c2d2098..33d2c482795 100644 --- a/app/controllers/registrations_controller.rb +++ b/app/controllers/registrations_controller.rb @@ -21,6 +21,7 @@ class RegistrationsController < Devise::RegistrationsController before_action only: [:new] do push_frontend_feature_flag(:gitlab_gtm_datalayer, type: :ops) + push_frontend_feature_flag(:trial_email_validation, type: :development) end feature_category :authentication_and_authorization diff --git a/app/controllers/repositories/git_http_client_controller.rb b/app/controllers/repositories/git_http_client_controller.rb index 24520a187e3..8d7ba3e38c0 100644 --- a/app/controllers/repositories/git_http_client_controller.rb +++ b/app/controllers/repositories/git_http_client_controller.rb @@ -107,7 +107,7 @@ module Repositories render plain: "HTTP Basic: Access denied\n" \ "You must use a personal access token with 'read_repository' or 'write_repository' scope for Git over HTTP.\n" \ "You can generate one at #{profile_personal_access_tokens_url}", - status: :unauthorized + status: :unauthorized end def repository diff --git a/app/controllers/repositories/lfs_api_controller.rb b/app/controllers/repositories/lfs_api_controller.rb index 7deda473b9d..83973d07a17 100644 --- a/app/controllers/repositories/lfs_api_controller.rb +++ b/app/controllers/repositories/lfs_api_controller.rb @@ -173,12 +173,12 @@ module Repositories LfsObjectsProject.link_to_project!(lfs_object, project) Gitlab::AppJsonLogger.info(message: "LFS object auto-linked to forked project", - lfs_object_oid: lfs_object.oid, - lfs_object_size: lfs_object.size, - source_project_id: project.fork_source.id, - source_project_path: project.fork_source.full_path, - target_project_id: project.project_id, - target_project_path: project.full_path) + lfs_object_oid: lfs_object.oid, + lfs_object_size: lfs_object.size, + source_project_id: project.fork_source.id, + source_project_path: project.fork_source.full_path, + target_project_id: project.project_id, + target_project_path: project.full_path) end end end diff --git a/app/controllers/repositories/lfs_locks_api_controller.rb b/app/controllers/repositories/lfs_locks_api_controller.rb index 1d091a5bfcd..f36126d67ff 100644 --- a/app/controllers/repositories/lfs_locks_api_controller.rb +++ b/app/controllers/repositories/lfs_locks_api_controller.rb @@ -38,8 +38,8 @@ module Repositories def render_json(data, process = true) render json: build_payload(data, process), - content_type: LfsRequest::CONTENT_TYPE, - status: @result[:http_status] + content_type: LfsRequest::CONTENT_TYPE, + status: @result[:http_status] end def build_payload(data, process) diff --git a/app/controllers/search_controller.rb b/app/controllers/search_controller.rb index 7a7e63f5fc4..5843e13c7cd 100644 --- a/app/controllers/search_controller.rb +++ b/app/controllers/search_controller.rb @@ -7,10 +7,14 @@ class SearchController < ApplicationController include ProductAnalyticsTracking include SearchRateLimitable - RESCUE_FROM_TIMEOUT_ACTIONS = [:count, :show, :autocomplete].freeze + RESCUE_FROM_TIMEOUT_ACTIONS = [:count, :show, :autocomplete, :aggregations].freeze track_event :show, name: 'i_search_total', destinations: [:redis_hll, :snowplow] + def self.search_rate_limited_endpoints + %i[show count autocomplete] + end + around_action :allow_gitaly_ref_name_caching before_action :block_anonymous_global_searches, :check_scope_global_search_enabled, except: :opensearch @@ -19,7 +23,7 @@ class SearchController < ApplicationController search_term_present = params[:search].present? || params[:term].present? search_term_present && !params[:project_id].present? end - before_action :check_search_rate_limit!, only: [:show, :count, :autocomplete] + before_action :check_search_rate_limit!, only: search_rate_limited_endpoints rescue_from ActiveRecord::QueryCanceled, with: :render_timeout @@ -32,8 +36,6 @@ class SearchController < ApplicationController @project = search_service.project @group = search_service.group - return if params[:search].blank? - return unless search_term_valid? return if check_single_commit_result? @@ -53,7 +55,6 @@ class SearchController < ApplicationController @search_results = @search_service.search_results @search_objects = @search_service.search_objects @search_highlight = @search_service.search_highlight - @aggregations = @search_service.search_aggregations end increment_search_counters @@ -83,8 +84,9 @@ class SearchController < ApplicationController @project = search_service.project @ref = params[:project_ref] if params[:project_ref].present? + @filter = params[:filter] - render json: search_autocomplete_opts(term).to_json + render json: search_autocomplete_opts(term, filter: @filter).to_json end def opensearch @@ -98,6 +100,8 @@ class SearchController < ApplicationController end def search_term_valid? + return false if params[:search].blank? + unless search_service.valid_query_length? flash[:alert] = t('errors.messages.search_chars_too_long', count: Gitlab::Search::Params::SEARCH_CHAR_LIMIT) return false @@ -150,6 +154,7 @@ class SearchController < ApplicationController payload[:metadata]['meta.search.filters.state'] = params[:state] payload[:metadata]['meta.search.force_search_results'] = params[:force_search_results] payload[:metadata]['meta.search.project_ids'] = params[:project_ids] + payload[:metadata]['meta.search.filters.language'] = params[:language] payload[:metadata]['meta.search.type'] = @search_type if @search_type.present? payload[:metadata]['meta.search.level'] = @search_level if @search_level.present? payload[:metadata][:global_search_duration_s] = @global_search_duration_s if @global_search_duration_s.present? @@ -205,7 +210,7 @@ class SearchController < ApplicationController case action_name.to_sym when :count render json: {}, status: :request_timeout - when :autocomplete + when :autocomplete, :aggregations render json: [], status: :request_timeout else render status: :request_timeout diff --git a/app/controllers/sessions_controller.rb b/app/controllers/sessions_controller.rb index 6195d152f00..fe3b8d9b8b4 100644 --- a/app/controllers/sessions_controller.rb +++ b/app/controllers/sessions_controller.rb @@ -215,11 +215,11 @@ class SessionsController < Devise::SessionsController def find_user strong_memoize(:find_user) do if session[:otp_user_id] && user_params[:login] - User.by_id_and_login(session[:otp_user_id], user_params[:login]).first + User.by_login(user_params[:login]).find_by_id(session[:otp_user_id]) elsif session[:otp_user_id] User.find(session[:otp_user_id]) elsif user_params[:login] - User.by_login(user_params[:login]) + User.find_by_login(user_params[:login]) end end end diff --git a/app/controllers/uploads_controller.rb b/app/controllers/uploads_controller.rb index 97bbb96eae6..09419a4589d 100644 --- a/app/controllers/uploads_controller.rb +++ b/app/controllers/uploads_controller.rb @@ -7,13 +7,13 @@ class UploadsController < ApplicationController UnknownUploadModelError = Class.new(StandardError) MODEL_CLASSES = { - "user" => User, - "project" => Project, - "note" => Note, - "group" => Group, - "appearance" => Appearance, + "user" => User, + "project" => Project, + "note" => Note, + "group" => Group, + "appearance" => Appearance, "personal_snippet" => PersonalSnippet, - "projects/topic" => Projects::Topic, + "projects/topic" => Projects::Topic, 'alert_management_metric_image' => ::AlertManagement::MetricImage, nil => PersonalSnippet }.freeze diff --git a/app/controllers/users/namespace_callouts_controller.rb b/app/controllers/users/namespace_callouts_controller.rb new file mode 100644 index 00000000000..d4876382dfe --- /dev/null +++ b/app/controllers/users/namespace_callouts_controller.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +module Users + class NamespaceCalloutsController < Users::CalloutsController + private + + def callout + Users::DismissNamespaceCalloutService.new( + container: nil, current_user: current_user, params: callout_params + ).execute + end + + def callout_params + params.permit(:namespace_id).merge(feature_name: feature_name) + end + end +end diff --git a/app/controllers/users/project_callouts_controller.rb b/app/controllers/users/project_callouts_controller.rb new file mode 100644 index 00000000000..64d89630021 --- /dev/null +++ b/app/controllers/users/project_callouts_controller.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +module Users + class ProjectCalloutsController < Users::CalloutsController + private + + def callout + Users::DismissProjectCalloutService.new( + container: nil, current_user: current_user, params: callout_params + ).execute + end + + def callout_params + params.permit(:project_id).merge(feature_name: feature_name) + end + end +end diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index eaf08cd421b..3c1a3534912 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -155,7 +155,11 @@ class UsersController < ApplicationController end def calendar_activities - @calendar_date = Date.parse(params[:date]) rescue Date.today + @calendar_date = begin + Date.parse(params[:date]) + rescue StandardError + Date.today + end @events = contributions_calendar.events_by_date(@calendar_date).map(&:present) render 'calendar_activities', layout: false |