diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2023-07-19 17:16:28 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2023-07-19 17:16:28 +0300 |
commit | e4384360a16dd9a19d4d2d25d0ef1f2b862ed2a6 (patch) | |
tree | 2fcdfa7dcdb9db8f5208b2562f4b4e803d671243 /app/controllers | |
parent | ffda4e7bcac36987f936b4ba515995a6698698f0 (diff) |
Add latest changes from gitlab-org/gitlab@16-2-stable-eev16.2.0-rc42
Diffstat (limited to 'app/controllers')
67 files changed, 566 insertions, 438 deletions
diff --git a/app/controllers/admin/application_settings/appearances_controller.rb b/app/controllers/admin/application_settings/appearances_controller.rb index 719e8e4a913..1a1e85d48da 100644 --- a/app/controllers/admin/application_settings/appearances_controller.rb +++ b/app/controllers/admin/application_settings/appearances_controller.rb @@ -69,7 +69,7 @@ class Admin::ApplicationSettings::AppearancesController < Admin::ApplicationCont @appearance = Appearance.current || Appearance.new end - # Only allow a trusted parameter "white list" through. + # Only allow a trusted parameter "allow list" through. def appearance_params params.require(:appearance).permit(allowed_appearance_params) end diff --git a/app/controllers/admin/application_settings_controller.rb b/app/controllers/admin/application_settings_controller.rb index dff1c04311d..f0b6d86d48d 100644 --- a/app/controllers/admin/application_settings_controller.rb +++ b/app/controllers/admin/application_settings_controller.rb @@ -30,7 +30,7 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController feature_category :continuous_integration, [:ci_cd, :reset_registration_token] urgency :low, [:ci_cd, :reset_registration_token] feature_category :service_ping, [:usage_data, :service_usage_data] - feature_category :integrations, [:integrations] + feature_category :integrations, [:integrations, :slack_app_manifest_share, :slack_app_manifest_download] feature_category :pages, [:lets_encrypt_terms_of_service] feature_category :error_tracking, [:reset_error_tracking_access_token] @@ -114,6 +114,14 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController redirect_to ::Gitlab::LetsEncrypt.terms_of_service_url end + def slack_app_manifest_share + redirect_to Slack::Manifest.share_url + end + + def slack_app_manifest_download + send_data Slack::Manifest.to_json, type: :json, disposition: 'attachment', filename: 'slack_manifest.json' + end + private def set_application_setting diff --git a/app/controllers/admin/runners_controller.rb b/app/controllers/admin/runners_controller.rb index f63616a2bea..b368ba6e495 100644 --- a/app/controllers/admin/runners_controller.rb +++ b/app/controllers/admin/runners_controller.rb @@ -3,32 +3,23 @@ class Admin::RunnersController < Admin::ApplicationController include RunnerSetupScripts - before_action :runner, except: [:index, :new, :tag_list, :runner_setup_scripts] - - before_action only: [:index] do - push_frontend_feature_flag(:create_runner_workflow_for_admin, current_user) - end + before_action :runner, only: [:show, :edit, :register, :update] feature_category :runner urgency :low - def index - end + def index; end - def show - end + def show; end def edit assign_projects end - def new - render_404 unless Feature.enabled?(:create_runner_workflow_for_admin, current_user) - end + def new; end def register - render_404 unless Feature.enabled?(:create_runner_workflow_for_admin, current_user) && - runner.registration_available? + render_404 unless runner.registration_available? end def update diff --git a/app/controllers/admin/users_controller.rb b/app/controllers/admin/users_controller.rb index 3c96e49499f..b75ca2649c3 100644 --- a/app/controllers/admin/users_controller.rb +++ b/app/controllers/admin/users_controller.rb @@ -159,7 +159,7 @@ class Admin::UsersController < Admin::ApplicationController end def unlock - if update_user(&:unlock_access!) + if unlock_user redirect_back_or_admin_user(notice: _("Successfully unlocked")) else redirect_back_or_admin_user(alert: _("Error occurred. User was not unlocked")) @@ -401,6 +401,11 @@ class Admin::UsersController < Admin::ApplicationController _("You cannot impersonate a user who cannot log in") end end + + # method overriden in EE + def unlock_user + update_user(&:unlock_access!) + end end Admin::UsersController.prepend_mod_with('Admin::UsersController') diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 08e4f4956df..8588273a41f 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -181,7 +181,7 @@ class ApplicationController < ActionController::Base payload[:queue_duration_s] = request.env[::Gitlab::Middleware::RailsQueueDuration::GITLAB_RAILS_QUEUE_DURATION_KEY] - payload[:response_bytes] = response.body_parts.sum(&:bytesize) if Feature.enabled?(:log_response_length) + payload[:response_bytes] = response.body_parts.sum(&:bytesize) store_cloudflare_headers!(payload, request) end diff --git a/app/controllers/clusters/clusters_controller.rb b/app/controllers/clusters/clusters_controller.rb index 2f6331a6822..b012a4e003e 100644 --- a/app/controllers/clusters/clusters_controller.rb +++ b/app/controllers/clusters/clusters_controller.rb @@ -2,7 +2,6 @@ class Clusters::ClustersController < Clusters::BaseController include RoutableActions - include MetricsDashboard before_action :cluster, only: [:cluster_status, :show, :update, :destroy, :clear_cache] before_action :user_cluster, only: [:connect] diff --git a/app/controllers/concerns/integrations/params.rb b/app/controllers/concerns/integrations/params.rb index 19e458307a1..53dd06ce638 100644 --- a/app/controllers/concerns/integrations/params.rb +++ b/app/controllers/concerns/integrations/params.rb @@ -43,6 +43,8 @@ module Integrations :external_wiki_url, :google_iap_service_account_json, :google_iap_audience_client_id, + :group_confidential_mention_events, + :group_mention_events, :incident_events, :inherit_from_id, # We're using `issues_events` and `merge_requests_events` diff --git a/app/controllers/concerns/internal_redirect.rb b/app/controllers/concerns/internal_redirect.rb index b803be67d2e..c3aa487c805 100644 --- a/app/controllers/concerns/internal_redirect.rb +++ b/app/controllers/concerns/internal_redirect.rb @@ -6,7 +6,7 @@ module InternalRedirect def safe_redirect_path(path) return unless path # Verify that the string starts with a `/` and a known route character. - return unless path =~ %r{\A/[-\w].*\z} + return unless %r{\A/[-\w].*\z}.match?(path) uri = URI(path) # Ignore anything path of the redirect except for the path, querystring and, diff --git a/app/controllers/concerns/issuable_actions.rb b/app/controllers/concerns/issuable_actions.rb index 0ad8a08960a..a326fa308ad 100644 --- a/app/controllers/concerns/issuable_actions.rb +++ b/app/controllers/concerns/issuable_actions.rb @@ -12,6 +12,7 @@ module IssuableActions before_action :authorize_destroy_issuable!, only: :destroy before_action :check_destroy_confirmation!, only: :destroy before_action :authorize_admin_issuable!, only: :bulk_update + before_action :set_application_context!, only: :show end def show @@ -226,6 +227,10 @@ module IssuableActions render_404 unless can?(current_user, :"update_#{resource_name}", issuable) end + def set_application_context! + # no-op. The logic is defined in EE module. + end + def bulk_update_params clean_bulk_update_params( params.require(:update).permit(bulk_update_permitted_keys) diff --git a/app/controllers/concerns/membership_actions.rb b/app/controllers/concerns/membership_actions.rb index 31675a58163..0c15c4d0d3f 100644 --- a/app/controllers/concerns/membership_actions.rb +++ b/app/controllers/concerns/membership_actions.rb @@ -16,7 +16,7 @@ module MembershipActions member_data = if member.expires? { expires_soon: member.expires_soon?, - expires_at_formatted: member.expires_at.to_time.in_time_zone.to_s(:medium) + expires_at_formatted: member.expires_at.to_time.in_time_zone.to_fs(:medium) } else {} diff --git a/app/controllers/concerns/metrics_dashboard.rb b/app/controllers/concerns/metrics_dashboard.rb deleted file mode 100644 index 7a84c597424..00000000000 --- a/app/controllers/concerns/metrics_dashboard.rb +++ /dev/null @@ -1,126 +0,0 @@ -# frozen_string_literal: true - -# Provides an action which fetches a metrics dashboard according -# to the parameters specified by the controller. -module MetricsDashboard - include RenderServiceResults - include ChecksCollaboration - include EnvironmentsHelper - - extend ActiveSupport::Concern - - def metrics_dashboard - return not_found if Feature.enabled?(:remove_monitor_metrics) - - result = dashboard_finder.find( - project_for_dashboard, - current_user, - decoded_params - ) - - if result - result[:all_dashboards] = all_dashboards if include_all_dashboards? - result[:metrics_data] = metrics_data(project_for_dashboard, environment_for_dashboard) - end - - respond_to do |format| - if result.nil? - format.json { continue_polling_response } - elsif result[:status] == :success - format.json { render dashboard_success_response(result) } - else - format.json { render dashboard_error_response(result) } - end - end - end - - private - - def all_dashboards - dashboard_finder - .find_all_paths(project_for_dashboard) - .map { |dashboard| amend_dashboard(dashboard) } - end - - def amend_dashboard(dashboard) - project_dashboard = project_for_dashboard && !dashboard[:out_of_the_box_dashboard] - - dashboard[:can_edit] = project_dashboard ? can_edit?(dashboard) : false - dashboard[:project_blob_path] = project_dashboard ? dashboard_project_blob_path(dashboard) : nil - dashboard[:starred] = starred_dashboards.include?(dashboard[:path]) - dashboard[:user_starred_path] = project_for_dashboard ? user_starred_path(project_for_dashboard, dashboard[:path]) : nil - - dashboard - end - - def user_starred_path(project, path) - expose_path(api_v4_projects_metrics_user_starred_dashboards_path(id: project.id, params: { dashboard_path: path })) - end - - def dashboard_project_blob_path(dashboard) - project_blob_path(project_for_dashboard, File.join(project_for_dashboard.default_branch, dashboard.fetch(:path, ""))) - end - - def can_edit?(dashboard) - can_collaborate_with_project?(project_for_dashboard, ref: project_for_dashboard.default_branch) - end - - # Override in class to provide arguments to the finder. - def metrics_dashboard_params - {} - end - - # Override in class if response requires complete list of - # dashboards in addition to requested dashboard body. - def include_all_dashboards? - false - end - - def dashboard_finder - ::Gitlab::Metrics::Dashboard::Finder - end - - def starred_dashboards - @starred_dashboards ||= - if project_for_dashboard.present? - ::Metrics::UsersStarredDashboardsFinder - .new(user: current_user, project: project_for_dashboard) - .execute - .map(&:dashboard_path) - .to_set - else - Set.new - end - end - - # Project is not defined for group and admin level clusters. - def project_for_dashboard - defined?(project) ? project : nil - end - - def environment_for_dashboard - defined?(environment) ? environment : nil - end - - def dashboard_success_response(result) - { - status: :ok, - json: result.slice(:all_dashboards, :dashboard, :status, :metrics_data) - } - end - - def dashboard_error_response(result) - { - status: result[:http_status] || :bad_request, - json: result.slice(:all_dashboards, :message, :status) - } - end - - def decoded_params - params = metrics_dashboard_params - - params[:dashboard_path] = CGI.unescape(params[:dashboard_path]) if params[:dashboard_path] - - params - end -end diff --git a/app/controllers/concerns/observability/content_security_policy.rb b/app/controllers/concerns/observability/content_security_policy.rb index 1e25dc492a0..e51d986d36c 100644 --- a/app/controllers/concerns/observability/content_security_policy.rb +++ b/app/controllers/concerns/observability/content_security_policy.rb @@ -5,26 +5,23 @@ module Observability extend ActiveSupport::Concern included do - content_security_policy_with_context do |p| - current_group = if defined?(group) - group - else - defined?(project) ? project&.group : nil - end - - next if p.directives.blank? || !Feature.enabled?(:observability_group_tab, current_group) + content_security_policy do |p| + next if p.directives.blank? default_frame_src = p.directives['frame-src'] || p.directives['default-src'] - - # When ObservabilityUI is not authenticated, it needs to be able - # to redirect to the GL sign-in page, hence '/users/sign_in' and '/oauth/authorize' + # When Gitlab Observability Backend is not authenticated, it needs to be able + # to redirect to the GitLab sign-in page, hence '/users/sign_in' and '/oauth/authorize' frame_src_values = Array.wrap(default_frame_src) | [ Gitlab::Observability.observability_url, Gitlab::Utils.append_path(Gitlab.config.gitlab.url, '/users/sign_in'), Gitlab::Utils.append_path(Gitlab.config.gitlab.url, '/oauth/authorize') ] - p.frame_src(*frame_src_values) + + default_connect_src = p.directives['connect-src'] || p.directives['default-src'] + connect_src_values = + Array.wrap(default_connect_src) | [Gitlab::Observability.observability_url] + p.connect_src(*connect_src_values) end end end diff --git a/app/controllers/concerns/onboarding/status.rb b/app/controllers/concerns/onboarding/status.rb new file mode 100644 index 00000000000..986f3f17847 --- /dev/null +++ b/app/controllers/concerns/onboarding/status.rb @@ -0,0 +1,41 @@ +# frozen_string_literal: true + +module Onboarding + class Status + def initialize(user) + @user = user + end + + def continue_full_onboarding? + false + end + + def single_invite? + # If there are more than one member it will mean we have been invited to multiple projects/groups and + # are not able to distinguish which one we should putting the user in after registration + members.count == 1 + end + + def last_invited_member + members.last + end + + def last_invited_member_source + last_invited_member&.source + end + + def invite_with_tasks_to_be_done? + return false if members.empty? + + MemberTask.for_members(members).exists? + end + + private + + attr_reader :user + + def members + @members ||= user.members + end + end +end diff --git a/app/controllers/concerns/preview_markdown.rb b/app/controllers/concerns/preview_markdown.rb index a7655efe7a9..7f1b961e92a 100644 --- a/app/controllers/concerns/preview_markdown.rb +++ b/app/controllers/concerns/preview_markdown.rb @@ -48,9 +48,7 @@ module PreviewMarkdown end.merge( requested_path: params[:path], ref: params[:ref], - # Disable comments in markdown for IE browsers because comments in IE - # could allow script execution. - allow_comments: !browser.ie? + allow_comments: false ) end diff --git a/app/controllers/concerns/redirects_for_missing_path_on_tree.rb b/app/controllers/concerns/redirects_for_missing_path_on_tree.rb index 92574dfade9..97c23a2cf3c 100644 --- a/app/controllers/concerns/redirects_for_missing_path_on_tree.rb +++ b/app/controllers/concerns/redirects_for_missing_path_on_tree.rb @@ -1,8 +1,8 @@ # frozen_string_literal: true module RedirectsForMissingPathOnTree - def redirect_to_tree_root_for_missing_path(project, ref, path) - redirect_to project_tree_path(project, ref), notice: missing_path_on_ref(path, ref) + def redirect_to_tree_root_for_missing_path(project, ref, path, ref_type: nil) + redirect_to project_tree_path(project, ref, ref_type: ref_type), notice: missing_path_on_ref(path, ref) end private diff --git a/app/controllers/concerns/requires_whitelisted_monitoring_client.rb b/app/controllers/concerns/requires_allowlisted_monitoring_client.rb index ef3d281589a..ad6d4dc548c 100644 --- a/app/controllers/concerns/requires_whitelisted_monitoring_client.rb +++ b/app/controllers/concerns/requires_allowlisted_monitoring_client.rb @@ -1,28 +1,28 @@ # frozen_string_literal: true -module RequiresWhitelistedMonitoringClient +module RequiresAllowlistedMonitoringClient extend ActiveSupport::Concern included do - before_action :validate_ip_whitelisted_or_valid_token! + before_action :validate_ip_allowlisted_or_valid_token! end private - def validate_ip_whitelisted_or_valid_token! - render_404 unless client_ip_whitelisted? || valid_token? + def validate_ip_allowlisted_or_valid_token! + render_404 unless client_ip_allowlisted? || valid_token? end - def client_ip_whitelisted? + def client_ip_allowlisted? # Always allow developers to access http://localhost:3000/-/metrics for # debugging purposes return true if Rails.env.development? && request.local? - ip_whitelist.any? { |e| e.include?(Gitlab::RequestContext.instance.client_ip) } + ip_allowlist.any? { |e| e.include?(Gitlab::RequestContext.instance.client_ip) } end - def ip_whitelist - @ip_whitelist ||= Settings.monitoring.ip_whitelist.map { |ip| IPAddr.new(ip) } + def ip_allowlist + @ip_allowlist ||= Settings.monitoring.ip_whitelist.map { |ip| IPAddr.new(ip) } end def valid_token? diff --git a/app/controllers/concerns/uploads_actions.rb b/app/controllers/concerns/uploads_actions.rb index 222fcc17222..29b61264322 100644 --- a/app/controllers/concerns/uploads_actions.rb +++ b/app/controllers/concerns/uploads_actions.rb @@ -110,7 +110,7 @@ module UploadsActions if uploader_mounted? model.public_send(upload_mount) # rubocop:disable GitlabSecurity/PublicSend else - build_uploader_from_upload || build_uploader_from_params + build_uploader_from_upload end end strong_memoize_attr :uploader @@ -125,21 +125,6 @@ module UploadsActions end # rubocop: enable CodeReuse/ActiveRecord - def build_uploader_from_params - return unless uploader = build_uploader - - uploader.retrieve_from_store!(params[:filename]) - - Gitlab::AppJsonLogger.info( - message: 'Deprecated usage of build_uploader_from_params', - uploader_class: uploader.class.name, - path: params[:filename], - exists: uploader.exists? - ) - - uploader - end - def build_uploader return unless params[:secret] && params[:filename] diff --git a/app/controllers/concerns/verifies_with_email.rb b/app/controllers/concerns/verifies_with_email.rb index 45869c05f41..13378800ea9 100644 --- a/app/controllers/concerns/verifies_with_email.rb +++ b/app/controllers/concerns/verifies_with_email.rb @@ -25,6 +25,7 @@ module VerifiesWithEmail if user.valid_password?(user_params[:password]) # The user has logged in successfully. + if user.unlock_token # Prompt for the token if it already has been set prompt_for_email_verification(user) @@ -32,7 +33,8 @@ module VerifiesWithEmail # require email verification if: # - their account has been locked because of too many failed login attempts, or # - they have logged in before, but never from the current ip address - send_verification_instructions(user) + reason = 'sign in from untrusted IP address' unless user.access_locked? + send_verification_instructions(user, reason: reason) prompt_for_email_verification(user) end end @@ -75,13 +77,13 @@ module VerifiesWithEmail super end - def send_verification_instructions(user) + def send_verification_instructions(user, reason: nil) return if send_rate_limited?(user) service = Users::EmailVerification::GenerateTokenService.new(attr: :unlock_token, user: user) raw_token, encrypted_token = service.execute user.unlock_token = encrypted_token - user.lock_access!({ send_instructions: false }) + user.lock_access!({ send_instructions: false, reason: reason }) send_verification_instructions_email(user, raw_token) end diff --git a/app/controllers/explore/projects_controller.rb b/app/controllers/explore/projects_controller.rb index 577bd04d656..b3a1b510db9 100644 --- a/app/controllers/explore/projects_controller.rb +++ b/app/controllers/explore/projects_controller.rb @@ -10,6 +10,7 @@ class Explore::ProjectsController < Explore::ApplicationController MIN_SEARCH_LENGTH = 3 PAGE_LIMIT = 50 + RSS_ENTRIES_LIMIT = 20 before_action :set_non_archived_param before_action :set_sorting @@ -83,6 +84,14 @@ class Explore::ProjectsController < Explore::ApplicationController params[:topic] = @topic.name @projects = load_projects + + respond_to do |format| + format.html + format.atom do + @projects = @projects.projects_order_id_desc.limit(RSS_ENTRIES_LIMIT) + render layout: 'xml' + end + end end private diff --git a/app/controllers/graphql_controller.rb b/app/controllers/graphql_controller.rb index 3d3b7f31dfd..5c0c2b4adf2 100644 --- a/app/controllers/graphql_controller.rb +++ b/app/controllers/graphql_controller.rb @@ -14,6 +14,7 @@ class GraphqlController < ApplicationController # The query string of a standard IntrospectionQuery, used to compare incoming requests for caching CACHED_INTROSPECTION_QUERY_STRING = CachedIntrospectionQuery.query_string + INTROSPECTION_QUERY_OPERATION_NAME = 'IntrospectionQuery' # If a user is using their session to access GraphQL, we need to have session # storage, since the admin-mode check is session wide. @@ -58,7 +59,7 @@ class GraphqlController < ApplicationController urgency :low, [:execute] def execute - result = if Feature.enabled?(:cache_introspection_query) && params[:operationName] == 'IntrospectionQuery' + result = if Feature.enabled?(:cache_introspection_query) && introspection_query? execute_introspection_query else multiplex? ? execute_multiplex : execute_query @@ -276,9 +277,6 @@ class GraphqlController < ApplicationController def execute_introspection_query if introspection_query_can_use_cache? - Gitlab::AppLogger.info(message: "IntrospectionQueryCache hit") - log_introspection_query_cache_details(true) - # Context for caching: https://gitlab.com/gitlab-org/gitlab/-/issues/409448 Rails.cache.fetch( introspection_query_cache_key, @@ -286,17 +284,12 @@ class GraphqlController < ApplicationController execute_query.to_json end else - Gitlab::AppLogger.info(message: "IntrospectionQueryCache miss") - log_introspection_query_cache_details(false) - execute_query end end def introspection_query_can_use_cache? - graphql_query = GraphQL::Query.new(GitlabSchema, query: query, variables: build_variables(params[:variables])) - - CACHED_INTROSPECTION_QUERY_STRING == graphql_query.query_string.squish + CACHED_INTROSPECTION_QUERY_STRING == graphql_query_object.query_string.squish end def introspection_query_cache_key @@ -306,13 +299,17 @@ class GraphqlController < ApplicationController ['introspection-query-cache', Gitlab.revision, context[:remove_deprecated]] end - def log_introspection_query_cache_details(can_use_introspection_query_cache) - Gitlab::AppLogger.info( - message: "IntrospectionQueryCache", - can_use_introspection_query_cache: can_use_introspection_query_cache.to_s, - query: query, - variables: build_variables(params[:variables]).to_s, - introspection_query_cache_key: introspection_query_cache_key.to_s - ) + def introspection_query? + if params.key?(:operationName) + params[:operationName] == INTROSPECTION_QUERY_OPERATION_NAME + else + # If we don't provide operationName param, we infer it from the query + graphql_query_object.selected_operation_name == INTROSPECTION_QUERY_OPERATION_NAME + end + end + + def graphql_query_object + @graphql_query_object ||= GraphQL::Query.new(GitlabSchema, query: query, + variables: build_variables(params[:variables])) end end diff --git a/app/controllers/groups/milestones_controller.rb b/app/controllers/groups/milestones_controller.rb index 5f6b55ea928..cbed75019f2 100644 --- a/app/controllers/groups/milestones_controller.rb +++ b/app/controllers/groups/milestones_controller.rb @@ -9,6 +9,10 @@ class Groups::MilestonesController < Groups::ApplicationController feature_category :team_planning urgency :low + before_action do + push_frontend_feature_flag(:content_editor_on_issues, group) + end + def index respond_to do |format| format.html do diff --git a/app/controllers/groups/runners_controller.rb b/app/controllers/groups/runners_controller.rb index 4b52617d287..2dd0e36b65f 100644 --- a/app/controllers/groups/runners_controller.rb +++ b/app/controllers/groups/runners_controller.rb @@ -6,10 +6,6 @@ class Groups::RunnersController < Groups::ApplicationController before_action :authorize_update_runner!, only: [:edit, :update, :destroy, :pause, :resume] before_action :runner, only: [:edit, :update, :destroy, :pause, :resume, :show, :register] - before_action only: [:index] do - push_frontend_feature_flag(:create_runner_workflow_for_namespace, group) - end - feature_category :runner urgency :low @@ -20,11 +16,9 @@ class Groups::RunnersController < Groups::ApplicationController Gitlab::Tracking.event(self.class.name, 'index', user: current_user, namespace: @group) end - def show - end + def show; end - def edit - end + def edit; end def update if Ci::Runners::UpdateRunnerService.new(@runner).execute(runner_params).success? @@ -34,12 +28,10 @@ class Groups::RunnersController < Groups::ApplicationController end end - def new - render_404 unless create_runner_workflow_for_namespace_enabled? - end + def new; end def register - render_404 unless create_runner_workflow_for_namespace_enabled? && runner.registration_available? + render_404 unless runner.registration_available? end private @@ -67,10 +59,6 @@ class Groups::RunnersController < Groups::ApplicationController render_404 end - - def create_runner_workflow_for_namespace_enabled? - Feature.enabled?(:create_runner_workflow_for_namespace, group) - end end Groups::RunnersController.prepend_mod diff --git a/app/controllers/groups/settings/ci_cd_controller.rb b/app/controllers/groups/settings/ci_cd_controller.rb index 4bbaf92b126..169caabf9d8 100644 --- a/app/controllers/groups/settings/ci_cd_controller.rb +++ b/app/controllers/groups/settings/ci_cd_controller.rb @@ -14,6 +14,7 @@ module Groups feature_category :continuous_integration before_action do + push_frontend_feature_flag(:ci_group_env_scope_graphql, group) push_frontend_feature_flag(:ci_variables_pages, current_user) end diff --git a/app/controllers/groups/uploads_controller.rb b/app/controllers/groups/uploads_controller.rb index cd1ebc39411..d29532f9d6f 100644 --- a/app/controllers/groups/uploads_controller.rb +++ b/app/controllers/groups/uploads_controller.rb @@ -9,7 +9,7 @@ class Groups::UploadsController < Groups::ApplicationController before_action :authorize_upload_file!, only: [:create, :authorize] before_action :verify_workhorse_api!, only: [:authorize] - feature_category :groups_and_projects + feature_category :portfolio_management urgency :low, [:show] private diff --git a/app/controllers/health_check_controller.rb b/app/controllers/health_check_controller.rb index a2abed7ba4e..a85629985ba 100644 --- a/app/controllers/health_check_controller.rb +++ b/app/controllers/health_check_controller.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true class HealthCheckController < HealthCheck::HealthCheckController - include RequiresWhitelistedMonitoringClient + include RequiresAllowlistedMonitoringClient end diff --git a/app/controllers/health_controller.rb b/app/controllers/health_controller.rb index 5fac7c0d663..1381999ab4c 100644 --- a/app/controllers/health_controller.rb +++ b/app/controllers/health_controller.rb @@ -3,7 +3,7 @@ # rubocop:disable Rails/ApplicationController class HealthController < ActionController::Base protect_from_forgery with: :exception, prepend: true - include RequiresWhitelistedMonitoringClient + include RequiresAllowlistedMonitoringClient CHECKS = [ Gitlab::HealthChecks::MasterCheck diff --git a/app/controllers/import/base_controller.rb b/app/controllers/import/base_controller.rb index bcb6aed9e38..f3a0ce64839 100644 --- a/app/controllers/import/base_controller.rb +++ b/app/controllers/import/base_controller.rb @@ -82,7 +82,7 @@ class Import::BaseController < ApplicationController # rubocop: disable CodeReuse/ActiveRecord def find_already_added_projects(import_type) - current_user.created_projects.where(import_type: import_type).with_import_state + current_user.created_projects.inc_routes.where(import_type: import_type).with_import_state end # rubocop: enable CodeReuse/ActiveRecord diff --git a/app/controllers/import/bitbucket_server_controller.rb b/app/controllers/import/bitbucket_server_controller.rb index 40664922d3d..e17cd00d053 100644 --- a/app/controllers/import/bitbucket_server_controller.rb +++ b/app/controllers/import/bitbucket_server_controller.rb @@ -103,8 +103,8 @@ class Import::BitbucketServerController < Import::BaseController return render_validation_error('Missing project key') unless @project_key.present? && @repo_slug.present? return render_validation_error('Missing repository slug') unless @repo_slug.present? - return render_validation_error('Invalid project key') unless @project_key =~ VALID_BITBUCKET_PROJECT_CHARS - return render_validation_error('Invalid repository slug') unless @repo_slug =~ VALID_BITBUCKET_CHARS + return render_validation_error('Invalid project key') unless VALID_BITBUCKET_PROJECT_CHARS.match?(@project_key) + return render_validation_error('Invalid repository slug') unless VALID_BITBUCKET_CHARS.match?(@repo_slug) end def render_validation_error(message) diff --git a/app/controllers/metrics_controller.rb b/app/controllers/metrics_controller.rb index 3dfa8d7b11e..9f41c092fa0 100644 --- a/app/controllers/metrics_controller.rb +++ b/app/controllers/metrics_controller.rb @@ -2,7 +2,7 @@ # rubocop:disable Rails/ApplicationController class MetricsController < ActionController::Base - include RequiresWhitelistedMonitoringClient + include RequiresAllowlistedMonitoringClient protect_from_forgery with: :exception, prepend: true diff --git a/app/controllers/oauth/authorizations_controller.rb b/app/controllers/oauth/authorizations_controller.rb index 96a3fab7e1a..a1d4df6ff48 100644 --- a/app/controllers/oauth/authorizations_controller.rb +++ b/app/controllers/oauth/authorizations_controller.rb @@ -1,9 +1,11 @@ # frozen_string_literal: true class Oauth::AuthorizationsController < Doorkeeper::AuthorizationsController + include Gitlab::GonHelper include InitializesCurrentUserMode include Gitlab::Utils::StrongMemoize + before_action :add_gon_variables before_action :verify_confirmed_email!, :verify_admin_allowed! layout 'profile' diff --git a/app/controllers/organizations/application_controller.rb b/app/controllers/organizations/application_controller.rb index 5f5a57d176b..43cc7014f62 100644 --- a/app/controllers/organizations/application_controller.rb +++ b/app/controllers/organizations/application_controller.rb @@ -4,6 +4,8 @@ module Organizations class ApplicationController < ::ApplicationController before_action :organization + layout 'organization' + private def organization diff --git a/app/controllers/organizations/organizations_controller.rb b/app/controllers/organizations/organizations_controller.rb index 0eb5c3aa6fd..4781ef995b7 100644 --- a/app/controllers/organizations/organizations_controller.rb +++ b/app/controllers/organizations/organizations_controller.rb @@ -6,6 +6,8 @@ module Organizations before_action { authorize_action!(:admin_organization) } - def directory; end + def show; end + + def groups_and_projects; end end end diff --git a/app/controllers/profiles/accounts_controller.rb b/app/controllers/profiles/accounts_controller.rb index eb64016379d..f618eafea38 100644 --- a/app/controllers/profiles/accounts_controller.rb +++ b/app/controllers/profiles/accounts_controller.rb @@ -7,6 +7,7 @@ class Profiles::AccountsController < Profiles::ApplicationController urgency :low, [:show] def show + push_frontend_feature_flag(:delay_delete_own_user) render(locals: show_view_variables) end diff --git a/app/controllers/profiles/notifications_controller.rb b/app/controllers/profiles/notifications_controller.rb index b663a75f04a..1477f8e0aac 100644 --- a/app/controllers/profiles/notifications_controller.rb +++ b/app/controllers/profiles/notifications_controller.rb @@ -45,7 +45,7 @@ class Profiles::NotificationsController < Profiles::ApplicationController projects = project_notifications.map(&:source) ActiveRecord::Associations::Preloader.new( records: projects, - associations: { namespace: [:route, :owner], group: [] } + associations: { namespace: [:route, :owner], group: [], creator: [] } ).call Preloaders::UserMaxAccessLevelInProjectsPreloader.new(projects, current_user).execute diff --git a/app/controllers/projects/alerting/notifications_controller.rb b/app/controllers/projects/alerting/notifications_controller.rb index 89e8a261288..281ac14d3ce 100644 --- a/app/controllers/projects/alerting/notifications_controller.rb +++ b/app/controllers/projects/alerting/notifications_controller.rb @@ -72,7 +72,7 @@ module Projects end def endpoint_identifier - params[:endpoint_identifier] || AlertManagement::HttpIntegration::LEGACY_IDENTIFIER + params[:endpoint_identifier] || AlertManagement::HttpIntegration::LEGACY_IDENTIFIERS end def notification_payload diff --git a/app/controllers/projects/blob_controller.rb b/app/controllers/projects/blob_controller.rb index 28393e1f365..b41e4d11d24 100644 --- a/app/controllers/projects/blob_controller.rb +++ b/app/controllers/projects/blob_controller.rb @@ -49,6 +49,7 @@ class Projects::BlobController < Projects::ApplicationController before_action do push_frontend_feature_flag(:highlight_js, @project) + push_frontend_feature_flag(:highlight_js_worker, @project) push_frontend_feature_flag(:explain_code_chat, current_user) push_licensed_feature(:file_locks) if @project.licensed_feature_available?(:file_locks) end @@ -160,6 +161,8 @@ class Projects::BlobController < Projects::ApplicationController end def check_for_ambiguous_ref + return if Feature.enabled?(:redirect_with_ref_type, @project) + @ref_type = ref_type if @ref_type == ExtractsRef::BRANCH_REF_TYPE && ambiguous_ref?(@project, @ref) @@ -169,7 +172,17 @@ class Projects::BlobController < Projects::ApplicationController end def commit - @commit ||= @repository.commit(@ref) + if Feature.enabled?(:redirect_with_ref_type, @project) + response = ::ExtractsRef::RequestedRef.new(@repository, ref_type: ref_type, ref: @ref).find + @commit = response[:commit] + @ref_type = response[:ref_type] + + if response[:ambiguous] + return redirect_to(project_blob_path(@project, File.join(@ref_type ? @ref : @commit.id, @path), ref_type: @ref_type)) + end + else + @commit ||= @repository.commit(@ref) + end return render_404 unless @commit end diff --git a/app/controllers/projects/environments_controller.rb b/app/controllers/projects/environments_controller.rb index 10d0d03e56d..4cc1ed092d2 100644 --- a/app/controllers/projects/environments_controller.rb +++ b/app/controllers/projects/environments_controller.rb @@ -12,12 +12,8 @@ class Projects::EnvironmentsController < Projects::ApplicationController push_frontend_feature_flag(:environment_details_vue, @project) end - before_action only: [:index] do - push_frontend_feature_flag(:kas_user_access_project, @project) - end - - before_action only: [:edit, :new] do - push_frontend_feature_flag(:environment_settings_to_graphql, @project) + before_action only: [:index, :edit, :new] do + push_frontend_feature_flag(:kubernetes_namespace_for_environment) end before_action :authorize_read_environment! @@ -28,7 +24,7 @@ class Projects::EnvironmentsController < Projects::ApplicationController before_action :environment, only: [:show, :edit, :update, :stop, :terminal, :terminal_websocket_authorize, :cancel_auto_stop] before_action :verify_api_request!, only: :terminal_websocket_authorize before_action :expire_etag_cache, only: [:index], unless: -> { request.format.json? } - before_action :set_kas_cookie, only: [:index], if: -> { current_user && request.format.html? } + before_action :set_kas_cookie, only: [:index, :edit, :new], if: -> { current_user && request.format.html? } after_action :expire_etag_cache, only: [:cancel_auto_stop] track_event :index, :folder, :show, :new, :edit, :create, :update, :stop, :cancel_auto_stop, :terminal, diff --git a/app/controllers/projects/forks_controller.rb b/app/controllers/projects/forks_controller.rb index ff3dc71b6cc..de2040afff3 100644 --- a/app/controllers/projects/forks_controller.rb +++ b/app/controllers/projects/forks_controller.rb @@ -65,9 +65,8 @@ class Projects::ForksController < Projects::ApplicationController end end - # rubocop: disable CodeReuse/ActiveRecord def create - @forked_project = fork_namespace.projects.find_by(path: project.path) + @forked_project = fork_namespace.projects.find_by(path: project.path) # rubocop: disable CodeReuse/ActiveRecord @forked_project = nil unless @forked_project && @forked_project.forked_from_project == project @forked_project ||= fork_service.execute @@ -96,7 +95,9 @@ class Projects::ForksController < Projects::ApplicationController current_user: current_user ).execute + # rubocop: disable CodeReuse/ActiveRecord forks.includes(:route, :creator, :group, :topics, namespace: [:route, :owner]) + # rubocop: enable CodeReuse/ActiveRecord end def fork_service @@ -130,15 +131,21 @@ class Projects::ForksController < Projects::ApplicationController end def load_namespaces_with_associations + # rubocop: disable CodeReuse/ActiveRecord @load_namespaces_with_associations ||= fork_service.valid_fork_targets(only_groups: true).preload(:route) + # rubocop: enable CodeReuse/ActiveRecord end def memberships_hash + # rubocop: disable CodeReuse/ActiveRecord current_user.members.where(source: load_namespaces_with_associations).index_by(&:source_id) + # rubocop: enable CodeReuse/ActiveRecord end def forked_projects_by_namespace(namespaces) + # rubocop: disable CodeReuse/ActiveRecord project.forks.where(namespace: namespaces).includes(:namespace).index_by(&:namespace_id) + # rubocop: enable CodeReuse/ActiveRecord end end diff --git a/app/controllers/projects/grafana_api_controller.rb b/app/controllers/projects/grafana_api_controller.rb deleted file mode 100644 index 2cc6c6c35ba..00000000000 --- a/app/controllers/projects/grafana_api_controller.rb +++ /dev/null @@ -1,46 +0,0 @@ -# frozen_string_literal: true - -class Projects::GrafanaApiController < Projects::ApplicationController - include RenderServiceResults - include MetricsDashboard - - before_action :authorize_read_grafana!, only: :proxy - - feature_category :metrics - urgency :low - - def proxy - return not_found if Feature.enabled?(:remove_monitor_metrics) - - result = ::Grafana::ProxyService.new( - project, - params[:datasource_id], - params[:proxy_path], - prometheus_params - ).execute - - return continue_polling_response if result.nil? - return error_response(result) if result[:status] == :error - - success_response(result) - end - - private - - def metrics_dashboard_params - params.permit(:embedded, :grafana_url) - end - - def query_params - params.permit(:query, :start_time, :end_time, :step) - end - - def prometheus_params - query_params.to_h - .except(:start_time, :end_time) - .merge( - start: query_params[:start_time], - end: query_params[:end_time] - ) - end -end diff --git a/app/controllers/projects/incidents_controller.rb b/app/controllers/projects/incidents_controller.rb index 7121096bd77..6109e29b169 100644 --- a/app/controllers/projects/incidents_controller.rb +++ b/app/controllers/projects/incidents_controller.rb @@ -11,6 +11,7 @@ class Projects::IncidentsController < Projects::ApplicationController push_force_frontend_feature_flag(:work_items_mvc, @project&.work_items_mvc_feature_flag_enabled?) push_force_frontend_feature_flag(:work_items_mvc_2, @project&.work_items_mvc_2_feature_flag_enabled?) push_frontend_feature_flag(:moved_mr_sidebar, project) + push_frontend_feature_flag(:move_close_into_dropdown, project) end feature_category :incident_management diff --git a/app/controllers/projects/issues_controller.rb b/app/controllers/projects/issues_controller.rb index 6311907a859..6a45595580f 100644 --- a/app/controllers/projects/issues_controller.rb +++ b/app/controllers/projects/issues_controller.rb @@ -51,13 +51,14 @@ class Projects::IssuesController < Projects::ApplicationController push_frontend_feature_flag(:service_desk_new_note_email_native_attachments, project) push_frontend_feature_flag(:saved_replies, current_user) push_frontend_feature_flag(:issues_grid_view) + push_frontend_feature_flag(:service_desk_ticket) end before_action only: [:index, :show] do push_force_frontend_feature_flag(:work_items, project&.work_items_feature_flag_enabled?) end - before_action only: :index do + before_action only: [:index, :service_desk] do push_frontend_feature_flag(:or_issuable_queries, project) push_frontend_feature_flag(:frontend_caching, project&.group) end @@ -69,6 +70,7 @@ class Projects::IssuesController < Projects::ApplicationController push_force_frontend_feature_flag(:work_items_mvc_2, project&.work_items_mvc_2_feature_flag_enabled?) push_frontend_feature_flag(:epic_widget_edit_confirmation, project) push_frontend_feature_flag(:moved_mr_sidebar, project) + push_frontend_feature_flag(:move_close_into_dropdown, project) end around_action :allow_gitaly_ref_name_caching, only: [:discussions] diff --git a/app/controllers/projects/jobs_controller.rb b/app/controllers/projects/jobs_controller.rb index 79ddcbf732d..4e0b304a2ee 100644 --- a/app/controllers/projects/jobs_controller.rb +++ b/app/controllers/projects/jobs_controller.rb @@ -21,7 +21,7 @@ class Projects::JobsController < Projects::ApplicationController before_action :verify_proxy_request!, only: :proxy_websocket_authorize before_action :push_job_log_jump_to_failures, only: [:show] before_action :reject_if_build_artifacts_size_refreshing!, only: [:erase] - + before_action :push_ai_build_failure_cause, only: [:show] layout 'project' feature_category :continuous_integration @@ -258,4 +258,8 @@ class Projects::JobsController < Projects::ApplicationController def push_job_log_jump_to_failures push_frontend_feature_flag(:job_log_jump_to_failures, @project) end + + def push_ai_build_failure_cause + push_frontend_feature_flag(:ai_build_failure_cause, @project) + end end diff --git a/app/controllers/projects/merge_requests/conflicts_controller.rb b/app/controllers/projects/merge_requests/conflicts_controller.rb index 76a233afa13..66a358963e2 100644 --- a/app/controllers/projects/merge_requests/conflicts_controller.rb +++ b/app/controllers/projects/merge_requests/conflicts_controller.rb @@ -15,7 +15,8 @@ class Projects::MergeRequests::ConflictsController < Projects::MergeRequests::Ap respond_to do |format| format.html do @issuable_sidebar = serializer.represent(@merge_request, serializer: 'sidebar') - Gitlab::UsageDataCounters::MergeRequestActivityUniqueCounter.track_loading_conflict_ui_action(user: current_user) + Gitlab::UsageDataCounters::MergeRequestActivityUniqueCounter + .track_loading_conflict_ui_action(user: current_user) end format.json do @@ -23,12 +24,14 @@ class Projects::MergeRequests::ConflictsController < Projects::MergeRequests::Ap render json: @conflicts_list elsif @merge_request.can_be_merged? render json: { - message: _('The merge conflicts for this merge request have already been resolved. Please return to the merge request.'), + message: _('The merge conflicts for this merge request have already been resolved. ' \ + 'Please return to the merge request.'), type: 'error' } else render json: { - message: _('The merge conflicts for this merge request cannot be resolved through GitLab. Please try to resolve them locally.'), + message: _('The merge conflicts for this merge request cannot be resolved through GitLab. ' \ + 'Please try to resolve them locally.'), type: 'error' } end @@ -52,7 +55,8 @@ class Projects::MergeRequests::ConflictsController < Projects::MergeRequests::Ap Gitlab::UsageDataCounters::MergeRequestActivityUniqueCounter.track_resolve_conflict_action(user: current_user) if @merge_request.can_be_merged? - render status: :bad_request, json: { message: _('The merge conflicts for this merge request have already been resolved.') } + render status: :bad_request, + json: { message: _('The merge conflicts for this merge request have already been resolved.') } return end @@ -71,6 +75,8 @@ class Projects::MergeRequests::ConflictsController < Projects::MergeRequests::Ap private + alias_method :issuable, :merge_request + def authorize_can_resolve_conflicts! @conflicts_list = ::MergeRequests::Conflicts::ListService.new(@merge_request) diff --git a/app/controllers/projects/merge_requests/creations_controller.rb b/app/controllers/projects/merge_requests/creations_controller.rb index 06381315614..6a3523b82d9 100644 --- a/app/controllers/projects/merge_requests/creations_controller.rb +++ b/app/controllers/projects/merge_requests/creations_controller.rb @@ -11,6 +11,12 @@ class Projects::MergeRequests::CreationsController < Projects::MergeRequests::Ap before_action :apply_diff_view_cookie!, only: [:diffs, :diff_for_path] before_action :build_merge_request, except: [:create] + before_action only: [:new] do + if can?(current_user, :fill_in_merge_request_template, project) + push_frontend_feature_flag(:fill_in_mr_template, project) + end + end + urgency :low, [ :new, :create, @@ -25,7 +31,9 @@ class Projects::MergeRequests::CreationsController < Projects::MergeRequests::Ap end def create - @merge_request = ::MergeRequests::CreateService.new(project: project, current_user: current_user, params: merge_request_params).execute + @merge_request = ::MergeRequests::CreateService + .new(project: project, current_user: current_user, params: merge_request_params) + .execute if @merge_request.valid? incr_count_webide_merge_request @@ -82,7 +90,10 @@ class Projects::MergeRequests::CreationsController < Projects::MergeRequests::Ap def branch_to @target_project = selected_target_project - if @target_project && params[:ref].present? && Ability.allowed?(current_user, :create_merge_request_in, @target_project) + if @target_project && + params[:ref].present? && + Ability.allowed?(current_user, :create_merge_request_in, @target_project) + @ref = params[:ref] @commit = @target_project.commit(Gitlab::Git::BRANCH_REF_PREFIX + @ref) end @@ -104,10 +115,13 @@ class Projects::MergeRequests::CreationsController < Projects::MergeRequests::Ap def build_merge_request params[:merge_request] ||= ActionController::Parameters.new(source_project: @project) + new_params = merge_request_params.merge(diff_options: diff_options) # Gitaly N+1 issue: https://gitlab.com/gitlab-org/gitlab-foss/issues/58096 Gitlab::GitalyClient.allow_n_plus_1_calls do - @merge_request = ::MergeRequests::BuildService.new(project: project, current_user: current_user, params: merge_request_params.merge(diff_options: diff_options)).execute + @merge_request = ::MergeRequests::BuildService + .new(project: project, current_user: current_user, params: new_params) + .execute end end diff --git a/app/controllers/projects/merge_requests/diffs_controller.rb b/app/controllers/projects/merge_requests/diffs_controller.rb index f3a01fd3223..5bd0063ab95 100644 --- a/app/controllers/projects/merge_requests/diffs_controller.rb +++ b/app/controllers/projects/merge_requests/diffs_controller.rb @@ -49,7 +49,8 @@ class Projects::MergeRequests::DiffsController < Projects::MergeRequests::Applic pagination_data: diffs.pagination_data } - # NOTE: Any variables that would affect the resulting json needs to be added to the cache_context to avoid stale cache issues. + # 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), @@ -130,7 +131,8 @@ class Projects::MergeRequests::DiffsController < Projects::MergeRequests::Applic # rubocop: disable CodeReuse/ActiveRecord def commit return unless commit_id = params[:commit_id].presence - return unless @merge_request.all_commits.exists?(sha: commit_id) || @merge_request.recent_context_commits.map(&:id).include?(commit_id) + return unless @merge_request.all_commits.exists?(sha: commit_id) || + @merge_request.recent_context_commits.map(&:id).include?(commit_id) @commit ||= @project.commit(commit_id) end @@ -160,7 +162,10 @@ class Projects::MergeRequests::DiffsController < Projects::MergeRequests::Applic end end - return @merge_request.context_commits_diff if show_only_context_commits? && !@merge_request.context_commits_diff.empty? + if show_only_context_commits? && !@merge_request.context_commits_diff.empty? + return @merge_request.context_commits_diff + end + return @merge_request.merge_head_diff if render_merge_ref_head_diff? if @start_sha diff --git a/app/controllers/projects/merge_requests/drafts_controller.rb b/app/controllers/projects/merge_requests/drafts_controller.rb index ca6ab83b877..74c495261a3 100644 --- a/app/controllers/projects/merge_requests/drafts_controller.rb +++ b/app/controllers/projects/merge_requests/drafts_controller.rb @@ -27,17 +27,23 @@ class Projects::MergeRequests::DraftsController < Projects::MergeRequests::Appli draft_note = create_service.execute + if draft_note.errors.present? + render json: { errors: draft_note.errors.full_messages.to_sentence }, status: :unprocessable_entity + return + end + prepare_notes_for_rendering(draft_note) render json: DraftNoteSerializer.new(current_user: current_user).represent(draft_note) end def update - draft_note.update!(draft_note_params) - - prepare_notes_for_rendering(draft_note) - - render json: DraftNoteSerializer.new(current_user: current_user).represent(draft_note) + if draft_note.update(draft_note_params) + prepare_notes_for_rendering(draft_note) + render json: DraftNoteSerializer.new(current_user: current_user).represent(draft_note) + else + render json: { errors: draft_note.errors.full_messages.to_sentence }, status: :unprocessable_entity + end end def destroy @@ -57,10 +63,13 @@ class Projects::MergeRequests::DraftsController < Projects::MergeRequests::Appli if Gitlab::Utils.to_boolean(approve_params[:approve]) unless merge_request.approved_by?(current_user) - success = ::MergeRequests::ApprovalService.new(project: @project, current_user: current_user, params: approve_params).execute(merge_request) + success = ::MergeRequests::ApprovalService + .new(project: @project, current_user: current_user, params: approve_params) + .execute(merge_request) unless success - return render json: { message: _('An error occurred while approving, please try again.') }, status: :internal_server_error + return render json: { message: _('An error occurred while approving, please try again.') }, + status: :internal_server_error end end @@ -101,7 +110,9 @@ class Projects::MergeRequests::DraftsController < Projects::MergeRequests::Appli # rubocop: disable CodeReuse/ActiveRecord def merge_request - @merge_request ||= MergeRequestsFinder.new(current_user, project_id: @project.id).find_by!(iid: params[:merge_request_id]) + @merge_request ||= MergeRequestsFinder + .new(current_user, project_id: @project.id) + .find_by!(iid: params[:merge_request_id]) end # rubocop: enable CodeReuse/ActiveRecord diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb index 60f619a8d20..2172c91fc76 100644 --- a/app/controllers/projects/merge_requests_controller.rb +++ b/app/controllers/projects/merge_requests_controller.rb @@ -41,19 +41,23 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo push_force_frontend_feature_flag(:content_editor_on_issues, project&.content_editor_on_issues_feature_flag_enabled?) push_frontend_feature_flag(:core_security_mr_widget_counts, project) push_frontend_feature_flag(:issue_assignees_widget, @project) - push_frontend_feature_flag(:deprecate_vulnerabilities_feedback, @project) push_frontend_feature_flag(:moved_mr_sidebar, project) + push_frontend_feature_flag(:sast_reports_in_inline_diff, project) push_frontend_feature_flag(:mr_experience_survey, project) push_frontend_feature_flag(:saved_replies, current_user) push_frontend_feature_flag(:code_quality_inline_drawer, project) - push_frontend_feature_flag(:auto_merge_labels_mr_widget, project) push_force_frontend_feature_flag(:summarize_my_code_review, summarize_my_code_review_enabled?) push_frontend_feature_flag(:mr_activity_filters, current_user) push_frontend_feature_flag(:review_apps_redeploy_mr_widget, project) - push_frontend_feature_flag(:comment_on_files, current_user) push_frontend_feature_flag(:ci_job_failures_in_mr, project) end + before_action only: [:edit] do + if can?(current_user, :fill_in_merge_request_template, project) + push_frontend_feature_flag(:fill_in_mr_template, project) + end + end + around_action :allow_gitaly_ref_name_caching, only: [:index, :show, :diffs, :discussions] after_action :log_merge_request_show, only: [:show, :diffs] @@ -124,16 +128,31 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo @merge_request.recent_context_commits ) - per_page = [(params[:per_page] || MergeRequestDiff::COMMITS_SAFE_SIZE).to_i, MergeRequestDiff::COMMITS_SAFE_SIZE].min - recent_commits = @merge_request.recent_commits(load_from_gitaly: true, limit: per_page, page: params[:page]).with_latest_pipeline(@merge_request.source_branch).with_markdown_cache + per_page = [ + (params[:per_page] || MergeRequestDiff::COMMITS_SAFE_SIZE).to_i, + MergeRequestDiff::COMMITS_SAFE_SIZE + ].min + recent_commits = @merge_request + .recent_commits(load_from_gitaly: true, limit: per_page, page: params[:page]) + .with_latest_pipeline(@merge_request.source_branch) + .with_markdown_cache @next_page = recent_commits.next_page @commits = set_commits_for_rendering( recent_commits, commits_count: @merge_request.commits_count ) - commits_count = @merge_request.preparing? ? '-' : @merge_request.commits_count + @merge_request.context_commits_count - render json: { html: view_to_html_string('projects/merge_requests/_commits'), next_page: @next_page, count: commits_count } + commits_count = if @merge_request.preparing? + '-' + else + @merge_request.commits_count + @merge_request.context_commits_count + end + + render json: { + html: view_to_html_string('projects/merge_requests/_commits'), + next_page: @next_page, + count: commits_count + } end def pipelines @@ -221,7 +240,9 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo end def update - @merge_request = ::MergeRequests::UpdateService.new(project: project, current_user: current_user, params: merge_request_update_params).execute(@merge_request) + @merge_request = ::MergeRequests::UpdateService + .new(project: project, current_user: current_user, params: merge_request_update_params) + .execute(@merge_request) respond_to do |format| format.html do @@ -287,7 +308,9 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo end def assign_related_issues - result = ::MergeRequests::AssignIssuesService.new(project: project, current_user: current_user, params: { merge_request: @merge_request }).execute + result = ::MergeRequests::AssignIssuesService + .new(project: project, current_user: current_user, params: { merge_request: @merge_request }) + .execute case result[:count] when 0 @@ -317,7 +340,8 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo end def rebase - @merge_request.rebase_async(current_user.id, skip_ci: Gitlab::Utils.to_boolean(merge_params[:skip_ci], default: false)) + @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 @@ -334,7 +358,8 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo IssuableExportCsvWorker.perform_async(:merge_request, current_user.id, project.id, finder_options.to_h) # rubocop:disable CodeReuse/Worker index_path = project_merge_requests_path(project) - message = _('Your CSV export has started. It will be emailed to %{email} when complete.') % { email: current_user.notification_email_or_default } + message = _('Your CSV export has started. It will be emailed to %{email} when complete.') % + { email: current_user.notification_email_or_default } redirect_to(index_path, notice: message) end @@ -432,10 +457,15 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo @commits_count = @merge_request.commits_count + @merge_request.context_commits_count @diffs_count = get_diffs_count @issuable_sidebar = serializer.represent(@merge_request, serializer: 'sidebar') - @current_user_data = Gitlab::Json.dump(UserSerializer.new(project: @project).represent(current_user, {}, MergeRequestCurrentUserEntity)) + @current_user_data = Gitlab::Json + .dump(UserSerializer.new(project: @project) + .represent(current_user, {}, MergeRequestCurrentUserEntity)) @show_whitespace_default = current_user.nil? || current_user.show_whitespace_in_diffs @file_by_file_default = current_user&.view_diffs_file_by_file - @coverage_path = coverage_reports_project_merge_request_path(@project, @merge_request, format: :json) if @merge_request.has_coverage_reports? + if @merge_request.has_coverage_reports? + @coverage_path = coverage_reports_project_merge_request_path(@project, @merge_request, format: :json) + end + @update_current_user_path = expose_path(api_v4_user_preferences_path) @endpoint_metadata_url = endpoint_metadata_url(@project, @merge_request) @endpoint_diff_batch_url = endpoint_diff_batch_url(@project, @merge_request) @@ -478,12 +508,18 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo def merge! # Disable the CI check if auto_merge_strategy is specified since we have # to wait until CI completes to know - unless @merge_request.mergeable?(skip_ci_check: auto_merge_requested?) + skipped_checks = @merge_request.skipped_mergeable_checks( + auto_merge_requested: auto_merge_requested?, + auto_merge_strategy: params[:auto_merge_strategy] + ) + + unless @merge_request.mergeable?(**skipped_checks) return :failed end squashing = params.fetch(:squash, false) - merge_service = ::MergeRequests::MergeService.new(project: @project, current_user: current_user, params: merge_params) + merge_service = ::MergeRequests::MergeService + .new(project: @project, current_user: current_user, params: merge_params) unless merge_service.hooks_validation_pass?(@merge_request, validate_squash_message: squashing) return :hook_validation_error @@ -500,7 +536,10 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo AutoMergeService.new(project, current_user, merge_params).update(merge_request) else AutoMergeService.new(project, current_user, merge_params) - .execute(merge_request, params[:auto_merge_strategy] || AutoMergeService::STRATEGY_MERGE_WHEN_PIPELINE_SUCCEEDS) + .execute( + merge_request, + params[:auto_merge_strategy] || AutoMergeService::STRATEGY_MERGE_WHEN_PIPELINE_SUCCEEDS + ) end else @merge_request.merge_async(current_user.id, merge_params) @@ -595,7 +634,9 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo def endpoint_diff_batch_url(project, merge_request) per_page = current_user&.view_diffs_file_by_file ? '1' : '5' - params = request.query_parameters.merge(view: 'inline', diff_head: true, w: show_whitespace, page: '0', per_page: per_page) + params = request + .query_parameters + .merge(view: 'inline', diff_head: true, w: show_whitespace, page: '0', per_page: per_page) params[:ck] = merge_request.merge_head_diff&.id if merge_request.diffs_batch_cache_with_max_age? diffs_batch_project_json_merge_request_path(project, merge_request, 'json', params) diff --git a/app/controllers/projects/milestones_controller.rb b/app/controllers/projects/milestones_controller.rb index 35b65dbce7e..1f4e5b54500 100644 --- a/app/controllers/projects/milestones_controller.rb +++ b/app/controllers/projects/milestones_controller.rb @@ -24,6 +24,10 @@ class Projects::MilestonesController < Projects::ApplicationController feature_category :team_planning urgency :low + before_action do + push_frontend_feature_flag(:content_editor_on_issues, @project) + end + def index @sort = params[:sort] || 'due_date_asc' @milestones = milestones.sort_by_attribute(@sort) diff --git a/app/controllers/projects/ml/candidates_controller.rb b/app/controllers/projects/ml/candidates_controller.rb index ed7155fc5f4..9905e454acb 100644 --- a/app/controllers/projects/ml/candidates_controller.rb +++ b/app/controllers/projects/ml/candidates_controller.rb @@ -3,7 +3,9 @@ module Projects module Ml class CandidatesController < ApplicationController - before_action :check_feature_enabled, :set_candidate + before_action :set_candidate + before_action :check_read, only: [:show] + before_action :check_write, only: [:destroy] feature_category :mlops @@ -26,9 +28,13 @@ module Projects render_404 unless @candidate.present? end - def check_feature_enabled + def check_read render_404 unless can?(current_user, :read_model_experiments, @project) end + + def check_write + render_404 unless can?(current_user, :write_model_experiments, @project) + end end end end diff --git a/app/controllers/projects/ml/experiments_controller.rb b/app/controllers/projects/ml/experiments_controller.rb index a620e9919e7..85e7f63779c 100644 --- a/app/controllers/projects/ml/experiments_controller.rb +++ b/app/controllers/projects/ml/experiments_controller.rb @@ -5,7 +5,8 @@ module Projects class ExperimentsController < ::Projects::ApplicationController include Projects::Ml::ExperimentsHelper - before_action :check_feature_enabled + before_action :check_read, only: [:show, :index] + before_action :check_write, only: [:destroy] before_action :set_experiment, only: [:show, :destroy] feature_category :mlops @@ -55,10 +56,14 @@ module Projects private - def check_feature_enabled + def check_read render_404 unless can?(current_user, :read_model_experiments, @project) end + def check_write + render_404 unless can?(current_user, :write_model_experiments, @project) + end + def set_experiment @experiment = ::Ml::Experiment.by_project_id_and_iid(@project.id, params[:iid]) diff --git a/app/controllers/projects/ml/models_controller.rb b/app/controllers/projects/ml/models_controller.rb new file mode 100644 index 00000000000..77855b73cbd --- /dev/null +++ b/app/controllers/projects/ml/models_controller.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true + +module Projects + module Ml + class ModelsController < ::Projects::ApplicationController + before_action :check_feature_enabled + feature_category :mlops + + def index + @models = ::Projects::Ml::ModelFinder.new(@project).execute + end + + private + + def check_feature_enabled + render_404 unless can?(current_user, :read_model_registry, @project) + end + end + end +end diff --git a/app/controllers/projects/notes_controller.rb b/app/controllers/projects/notes_controller.rb index 054e8c302c9..7fcdf220bd2 100644 --- a/app/controllers/projects/notes_controller.rb +++ b/app/controllers/projects/notes_controller.rb @@ -1,6 +1,7 @@ # frozen_string_literal: true class Projects::NotesController < Projects::ApplicationController + extend Gitlab::Utils::Override include RendersNotes include NotesActions include NotesHelper @@ -11,10 +12,30 @@ class Projects::NotesController < Projects::ApplicationController before_action :authorize_create_note!, only: [:create] before_action :authorize_resolve_note!, only: [:resolve, :unresolve] - feature_category :team_planning + feature_category :team_planning, [:index, :create, :update, :destroy, :delete_attachment, :toggle_award_emoji] + feature_category :code_review_workflow, [:resolve, :unresolve, :outdated_line_change] urgency :medium, [:index] urgency :low, [:create, :update, :destroy, :resolve, :unresolve, :toggle_award_emoji, :outdated_line_change] + override :feature_category + def feature_category + if %w[index create].include?(params[:action]) + category = feature_category_override_for_target_type(params[:target_type]) + return category if category + end + + super + end + + def feature_category_override_for_target_type(target_type) + case target_type + when 'merge_request' + 'code_review_workflow' + when 'commit', 'project_snippet' + 'source_code_management' + end + end + def delete_attachment note.remove_attachment! note.update_attribute(:attachment, nil) diff --git a/app/controllers/projects/pages_controller.rb b/app/controllers/projects/pages_controller.rb index 332d33b8e52..6cfbb61fbb2 100644 --- a/app/controllers/projects/pages_controller.rb +++ b/app/controllers/projects/pages_controller.rb @@ -1,8 +1,6 @@ # frozen_string_literal: true class Projects::PagesController < Projects::ApplicationController - layout :resolve_layout - before_action :require_pages_enabled! before_action :authorize_read_pages!, only: [:show] before_action :authorize_update_pages!, except: [:show, :destroy] @@ -10,10 +8,6 @@ class Projects::PagesController < Projects::ApplicationController feature_category :pages - before_action do - push_frontend_feature_flag(:show_pages_in_deployments_menu, current_user, type: :experiment) - end - def new @pipeline_wizard_data = { project_path: @project.full_path, @@ -66,10 +60,6 @@ class Projects::PagesController < Projects::ApplicationController private - def resolve_layout - 'project_settings' unless Feature.enabled?(:show_pages_in_deployments_menu, current_user, type: :experiment) - end - def project_params params.require(:project).permit(project_params_attributes) end diff --git a/app/controllers/projects/pipeline_schedules_controller.rb b/app/controllers/projects/pipeline_schedules_controller.rb index fb332fec3b5..4fd307b5105 100644 --- a/app/controllers/projects/pipeline_schedules_controller.rb +++ b/app/controllers/projects/pipeline_schedules_controller.rb @@ -25,14 +25,25 @@ class Projects::PipelineSchedulesController < Projects::ApplicationController end def create - @schedule = Ci::CreatePipelineScheduleService - .new(@project, current_user, schedule_params) - .execute - - if @schedule.persisted? - redirect_to pipeline_schedules_path(@project) + if ::Feature.enabled?(:ci_refactoring_pipeline_schedule_create_service, @project) + response = Ci::PipelineSchedules::CreateService.new(@project, current_user, schedule_params).execute + @schedule = response.payload + + if response.success? + redirect_to pipeline_schedules_path(@project) + else + render :new + end else - render :new + @schedule = Ci::CreatePipelineScheduleService + .new(@project, current_user, schedule_params) + .execute + + if @schedule.persisted? + redirect_to pipeline_schedules_path(@project) + else + render :new + end end end diff --git a/app/controllers/projects/pipelines_controller.rb b/app/controllers/projects/pipelines_controller.rb index 98e6459b543..a96ee2215c2 100644 --- a/app/controllers/projects/pipelines_controller.rb +++ b/app/controllers/projects/pipelines_controller.rb @@ -22,7 +22,6 @@ class Projects::PipelinesController < Projects::ApplicationController before_action :authorize_update_pipeline!, only: [:retry, :cancel] before_action :ensure_pipeline, only: [:show, :downloadable_artifacts] before_action :reject_if_build_artifacts_size_refreshing!, only: [:destroy] - before_action :push_frontend_feature_flags, only: [:show, :builds, :dag, :failures, :test_report] # Will be removed with https://gitlab.com/gitlab-org/gitlab/-/issues/225596 before_action :redirect_for_legacy_scope_filter, only: [:index], if: -> { request.format.html? } @@ -350,10 +349,6 @@ class Projects::PipelinesController < Projects::ApplicationController def tracking_project_source project end - - def push_frontend_feature_flags - push_frontend_feature_flag(:pipeline_details_header_vue, @project) - end end Projects::PipelinesController.prepend_mod_with('Projects::PipelinesController') diff --git a/app/controllers/projects/runners_controller.rb b/app/controllers/projects/runners_controller.rb index 2b2c2cef8e2..db19ca23e9f 100644 --- a/app/controllers/projects/runners_controller.rb +++ b/app/controllers/projects/runners_controller.rb @@ -12,8 +12,7 @@ class Projects::RunnersController < Projects::ApplicationController redirect_to project_settings_ci_cd_path(@project, anchor: 'js-runners-settings') end - def edit - end + def edit; end def update if Ci::Runners::UpdateRunnerService.new(@runner).execute(runner_params).success? @@ -23,12 +22,10 @@ class Projects::RunnersController < Projects::ApplicationController end end - def new - render_404 unless create_runner_workflow_for_namespace_enabled? - end + def new; end def register - render_404 unless create_runner_workflow_for_namespace_enabled? && runner.registration_available? + render_404 unless runner.registration_available? end def destroy @@ -55,8 +52,7 @@ class Projects::RunnersController < Projects::ApplicationController end end - def show - end + def show; end def toggle_shared_runners update_params = { shared_runners_enabled: !project.shared_runners_enabled } @@ -84,8 +80,4 @@ class Projects::RunnersController < Projects::ApplicationController def runner_params params.require(:runner).permit(Ci::Runner::FORM_EDITABLE) end - - def create_runner_workflow_for_namespace_enabled? - Feature.enabled?(:create_runner_workflow_for_namespace, project.namespace) - end end diff --git a/app/controllers/projects/service_desk/custom_email_controller.rb b/app/controllers/projects/service_desk/custom_email_controller.rb new file mode 100644 index 00000000000..fb5e87f9a97 --- /dev/null +++ b/app/controllers/projects/service_desk/custom_email_controller.rb @@ -0,0 +1,84 @@ +# frozen_string_literal: true + +module Projects + module ServiceDesk + class CustomEmailController < Projects::ApplicationController + before_action :check_feature_flag_enabled + before_action :authorize_admin_project! + + feature_category :service_desk + urgency :low + + def create + response = ::ServiceDesk::CustomEmails::CreateService.new( + project: project, + current_user: current_user, + params: params + ).execute + + json_response(service_response: response) + end + + def update + response = ServiceDeskSettings::UpdateService.new(project, current_user, update_setting_params).execute + + if response.error? + json_response( + error_message: s_("ServiceDesk|Cannot update custom email"), + status: :unprocessable_entity + ) + return + end + + json_response + end + + def destroy + response = ::ServiceDesk::CustomEmails::DestroyService.new( + project: project, + current_user: current_user + ).execute + + json_response(service_response: response) + end + + def show + json_response + end + + private + + def update_setting_params + params.permit(:custom_email_enabled) + end + + def json_response(error_message: nil, status: :ok, service_response: nil) + if service_response.present? + status = service_response.success? ? :ok : :unprocessable_entity + error_message = service_response.message + end + + respond_to do |format| + format.json { render json: custom_email_attributes(error_message: error_message), status: status } + end + end + + def custom_email_attributes(error_message:) + setting = project.service_desk_setting + + { + custom_email: setting&.custom_email, + custom_email_enabled: setting&.custom_email_enabled || false, + custom_email_verification_state: setting&.custom_email_verification&.state, + custom_email_verification_error: setting&.custom_email_verification&.error, + custom_email_smtp_address: setting&.custom_email_credential&.smtp_address, + error_message: error_message + } + end + + def check_feature_flag_enabled + render_404 unless Feature.enabled?(:service_desk_custom_email, @project) + end + end + end +end diff --git a/app/controllers/projects/service_desk_controller.rb b/app/controllers/projects/service_desk_controller.rb index 8f576b8d72b..b1e30e7a45b 100644 --- a/app/controllers/projects/service_desk_controller.rb +++ b/app/controllers/projects/service_desk_controller.rb @@ -13,12 +13,12 @@ class Projects::ServiceDeskController < Projects::ApplicationController def update Projects::UpdateService.new(project, current_user, { service_desk_enabled: params[:service_desk_enabled] }).execute - result = ServiceDeskSettings::UpdateService.new(project, current_user, setting_params).execute + response = ServiceDeskSettings::UpdateService.new(project, current_user, setting_params).execute - if result[:status] == :success + if response.success? json_response else - render json: { message: result[:message] }, status: :unprocessable_entity + render json: { message: response.message }, status: :unprocessable_entity end end diff --git a/app/controllers/projects/settings/ci_cd_controller.rb b/app/controllers/projects/settings/ci_cd_controller.rb index ce760051f79..0e892ef3faa 100644 --- a/app/controllers/projects/settings/ci_cd_controller.rb +++ b/app/controllers/projects/settings/ci_cd_controller.rb @@ -14,10 +14,6 @@ module Projects before_action do push_frontend_feature_flag(:ci_variables_pages, current_user) - push_frontend_feature_flag(:ci_limit_environment_scope, @project) - push_frontend_feature_flag(:create_runner_workflow_for_namespace, @project.namespace) - push_frontend_feature_flag(:frozen_outbound_job_token_scopes, @project) - push_frontend_feature_flag(:frozen_outbound_job_token_scopes_override, @project) end helper_method :highlight_badge diff --git a/app/controllers/projects/tracing_controller.rb b/app/controllers/projects/tracing_controller.rb new file mode 100644 index 00000000000..d1218ebf344 --- /dev/null +++ b/app/controllers/projects/tracing_controller.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +module Projects + class TracingController < Projects::ApplicationController + include ::Observability::ContentSecurityPolicy + + feature_category :tracing + + before_action :check_tracing_enabled + + def index; end + + private + + def check_tracing_enabled + render_404 unless Gitlab::Observability.tracing_enabled?(project) + end + end +end diff --git a/app/controllers/projects/tree_controller.rb b/app/controllers/projects/tree_controller.rb index c8f698d6193..b961339111b 100644 --- a/app/controllers/projects/tree_controller.rb +++ b/app/controllers/projects/tree_controller.rb @@ -12,12 +12,14 @@ class Projects::TreeController < Projects::ApplicationController before_action :require_non_empty_project, except: [:new, :create] before_action :assign_ref_vars + before_action :find_requested_ref, only: [:show] before_action :assign_dir_vars, only: [:create_dir] before_action :authorize_read_code! before_action :authorize_edit_tree!, only: [:create_dir] before_action do push_frontend_feature_flag(:highlight_js, @project) + push_frontend_feature_flag(:highlight_js_worker, @project) push_frontend_feature_flag(:explain_code_chat, current_user) push_licensed_feature(:file_locks) if @project.licensed_feature_available?(:file_locks) end @@ -28,18 +30,20 @@ class Projects::TreeController < Projects::ApplicationController def show return render_404 unless @commit - @ref_type = ref_type - if @ref_type == BRANCH_REF_TYPE && ambiguous_ref?(@project, @ref) - branch = @project.repository.find_branch(@ref) - if branch - redirect_to project_tree_path(@project, branch.target) - return + unless Feature.enabled?(:redirect_with_ref_type, @project) + @ref_type = ref_type + if @ref_type == BRANCH_REF_TYPE && ambiguous_ref?(@project, @ref) + branch = @project.repository.find_branch(@ref) + if branch + redirect_to project_tree_path(@project, branch.target) + return + end end end if tree.entries.empty? if @repository.blob_at(@commit.id, @path) - redirect_to project_blob_path(@project, File.join(@ref, @path)) + redirect_to project_blob_path(@project, File.join(@ref, @path), ref_type: @ref_type) elsif @path.present? redirect_to_tree_root_for_missing_path(@project, @ref, @path) end @@ -59,6 +63,23 @@ class Projects::TreeController < Projects::ApplicationController private + def find_requested_ref + return unless Feature.enabled?(:redirect_with_ref_type, @project) + + @ref_type = ref_type + if @ref_type.present? + @tree = @repo.tree(@ref, @path, ref_type: @ref_type) + else + response = ExtractsPath::RequestedRef.new(@repository, ref_type: nil, ref: @ref).find + @ref_type = response[:ref_type] + @commit = response[:commit] + + if response[:ambiguous] + redirect_to(project_tree_path(@project, File.join(@ref_type ? @ref : @commit.id, @path), ref_type: @ref_type)) + end + end + end + def redirect_renamed_default_branch? action_name == 'show' end diff --git a/app/controllers/projects/uploads_controller.rb b/app/controllers/projects/uploads_controller.rb index 8f4987a07f6..48399e17b25 100644 --- a/app/controllers/projects/uploads_controller.rb +++ b/app/controllers/projects/uploads_controller.rb @@ -11,7 +11,7 @@ class Projects::UploadsController < Projects::ApplicationController before_action :authorize_upload_file!, only: [:create, :authorize] before_action :verify_workhorse_api!, only: [:authorize] - feature_category :not_owned # rubocop:todo Gitlab/AvoidFeatureCategoryNotOwned + feature_category :team_planning private diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb index 81f205a6457..51f6158d9c0 100644 --- a/app/controllers/projects_controller.rb +++ b/app/controllers/projects_controller.rb @@ -38,9 +38,11 @@ class ProjectsController < Projects::ApplicationController before_action do push_frontend_feature_flag(:highlight_js, @project) + push_frontend_feature_flag(:highlight_js_worker, @project) push_frontend_feature_flag(:remove_monitor_metrics, @project) push_frontend_feature_flag(:explain_code_chat, current_user) push_frontend_feature_flag(:ci_namespace_catalog_experimental, @project) + push_frontend_feature_flag(:service_desk_custom_email, @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?) @@ -172,7 +174,9 @@ class ProjectsController < Projects::ApplicationController flash.now[:alert] = _("Project '%{project_name}' queued for deletion.") % { project_name: @project.name } end - if ambiguous_ref?(@project, @ref) + if Feature.enabled?(:redirect_with_ref_type, @project) + @ref_type = 'heads' + elsif ambiguous_ref?(@project, @ref) branch = @project.repository.find_branch(@ref) # The files view would render a ref other than the default branch diff --git a/app/controllers/registrations/welcome_controller.rb b/app/controllers/registrations/welcome_controller.rb index 76aa4afbe80..76f181e3ce8 100644 --- a/app/controllers/registrations/welcome_controller.rb +++ b/app/controllers/registrations/welcome_controller.rb @@ -7,10 +7,10 @@ module Registrations include ::Gitlab::Utils::StrongMemoize layout 'minimal' - skip_before_action :authenticate_user!, :required_signup_info, :check_two_factor_requirement, only: [:show, :update] - before_action :require_current_user + skip_before_action :required_signup_info, :check_two_factor_requirement helper_method :welcome_update_params + helper_method :onboarding_status feature_category :user_management @@ -25,7 +25,7 @@ module Registrations if result.success? track_event('successfully_submitted_form') - finish_onboarding_on_welcome_page unless complete_signup_onboarding? + successful_update_hooks redirect_to update_success_path else @@ -35,14 +35,10 @@ module Registrations private - def registering_from_invite?(members) - # If there are more than one member it will mean we have been invited to multiple projects/groups and - # are not able to distinguish which one we should putting the user in after registration - members.count == 1 && members.last.source.present? - end + def authenticate_user! + return if current_user - def require_current_user - return redirect_to new_user_registration_path unless current_user + redirect_to new_user_registration_path end def completed_welcome_step? @@ -54,33 +50,28 @@ module Registrations end def path_for_signed_in_user(user) - stored_location_for(user) || members_activity_path(user.members) - end - - def members_activity_path(members) - return dashboard_projects_path unless members.any? - return dashboard_projects_path unless members.last.source.present? - - members.last.source.activity_path + stored_location_for(user) || last_member_activity_path end # overridden in EE def complete_signup_onboarding? - false + onboarding_status.continue_full_onboarding? end - def invites_with_tasks_to_be_done? - MemberTask.for_members(user_members).exists? + def last_member_activity_path + return dashboard_projects_path unless onboarding_status.last_invited_member_source.present? + + onboarding_status.last_invited_member_source.activity_path end def update_success_path - if invites_with_tasks_to_be_done? + if onboarding_status.invite_with_tasks_to_be_done? issues_dashboard_path(assignee_username: current_user.username) elsif complete_signup_onboarding? # trials/regular registration on .com signup_onboarding_path - elsif registering_from_invite?(user_members) # invites w/o tasks due to order - flash[:notice] = helpers.invite_accepted_notice(user_members.last) - members_activity_path(user_members) + elsif onboarding_status.single_invite? # invites w/o tasks due to order + flash[:notice] = helpers.invite_accepted_notice(onboarding_status.last_invited_member) + onboarding_status.last_invited_member_source.activity_path else # Subscription registrations goes through here as well. # Invites will come here too if there is more than 1. @@ -88,13 +79,8 @@ module Registrations end end - def user_members - current_user.members - end - strong_memoize_attr :user_members - # overridden in EE - def finish_onboarding_on_welcome_page; end + def successful_update_hooks; end # overridden in EE def signup_onboarding_path; end @@ -106,6 +92,11 @@ module Registrations def welcome_update_params {} end + + def onboarding_status + Onboarding::Status.new(current_user) + end + strong_memoize_attr :onboarding_status end end diff --git a/app/controllers/registrations_controller.rb b/app/controllers/registrations_controller.rb index f481681da02..76b7d30cd51 100644 --- a/app/controllers/registrations_controller.rb +++ b/app/controllers/registrations_controller.rb @@ -184,8 +184,6 @@ class RegistrationsController < Devise::RegistrationsController end def check_captcha - ensure_correct_params! - return unless show_recaptcha_sign_up? return unless Gitlab::Recaptcha.load_configurations! @@ -224,6 +222,7 @@ class RegistrationsController < Devise::RegistrationsController end def sign_up_params + ensure_correct_params! params.require(:user).permit(sign_up_params_attributes) end diff --git a/app/controllers/uploads_controller.rb b/app/controllers/uploads_controller.rb index b797a204d7f..6d3811514d9 100644 --- a/app/controllers/uploads_controller.rb +++ b/app/controllers/uploads_controller.rb @@ -29,7 +29,7 @@ class UploadsController < ApplicationController before_action :authorize_create_access!, only: [:create, :authorize] before_action :verify_workhorse_api!, only: [:authorize] - feature_category :team_planning + feature_category :groups_and_projects def self.model_classes MODEL_CLASSES diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index 4db5745c005..88a8851607b 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -97,11 +97,11 @@ class UsersController < ApplicationController end def groups - load_groups - respond_to do |format| format.html { render 'show' } format.json do + load_groups + render json: { html: view_to_html_string("shared/groups/_list", groups: @groups) } @@ -110,36 +110,36 @@ class UsersController < ApplicationController end def projects - load_projects - - present_projects(@projects) + present_projects do + load_projects + end end def contributed - load_contributed_projects - - present_projects(@contributed_projects) + present_projects do + load_contributed_projects + end end def starred - load_starred_projects - - present_projects(@starred_projects) + present_projects do + load_starred_projects + end end def followers - @user_followers = user.followers.page(params[:page]) - - present_users(@user_followers) + present_users do + @user_followers = user.followers.page(params[:page]) + end end def following - @user_following = user.followees.page(params[:page]) - - present_users(@user_following) + present_users do + @user_following = user.followees.page(params[:page]) + end end - def present_projects(projects) + def present_projects skip_pagination = Gitlab::Utils.to_boolean(params[:skip_pagination]) skip_namespace = Gitlab::Utils.to_boolean(params[:skip_namespace]) compact_mode = Gitlab::Utils.to_boolean(params[:compact_mode]) @@ -147,17 +147,19 @@ class UsersController < ApplicationController respond_to do |format| format.html { render 'show' } format.json do + projects = yield + pager_json("shared/projects/_list", projects.count, projects: projects, skip_pagination: skip_pagination, skip_namespace: skip_namespace, compact_mode: compact_mode) end end end def snippets - load_snippets - respond_to do |format| format.html { render 'show' } format.json do + load_snippets + render json: { html: view_to_html_string("snippets/_snippets", collection: @snippets) } @@ -281,10 +283,11 @@ class UsersController < ApplicationController access_denied! unless can?(current_user, :read_user_profile, user) end - def present_users(users) + def present_users respond_to do |format| format.html { render 'show' } format.json do + users = yield render json: { html: view_to_html_string("shared/users/index", users: users) } |