diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2019-12-20 12:07:57 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2019-12-20 12:07:57 +0300 |
commit | 7881eb30eaa8b01dbcfe87faa09927c75c7d6e45 (patch) | |
tree | 298bc8d2c62b2f2c29cb8ecbcf3de3eaaa6466d9 /app/controllers | |
parent | 64b66e0cb6d1bfd27abf24e06653f00bddb60597 (diff) |
Add latest changes from gitlab-org/gitlab@12-6-stable-ee
Diffstat (limited to 'app/controllers')
51 files changed, 452 insertions, 223 deletions
diff --git a/app/controllers/admin/broadcast_messages_controller.rb b/app/controllers/admin/broadcast_messages_controller.rb index 6e5dd1a1f55..06ba916fc55 100644 --- a/app/controllers/admin/broadcast_messages_controller.rb +++ b/app/controllers/admin/broadcast_messages_controller.rb @@ -60,6 +60,8 @@ class Admin::BroadcastMessagesController < Admin::ApplicationController font message starts_at + target_path + broadcast_type )) end end diff --git a/app/controllers/admin/identities_controller.rb b/app/controllers/admin/identities_controller.rb index 8f2e34a6294..327538f1e93 100644 --- a/app/controllers/admin/identities_controller.rb +++ b/app/controllers/admin/identities_controller.rb @@ -28,7 +28,8 @@ class Admin::IdentitiesController < Admin::ApplicationController def update if @identity.update(identity_params) - RepairLdapBlockedUserService.new(@user).execute + ::Users::RepairLdapBlockedService.new(@user).execute + redirect_to admin_user_identities_path(@user), notice: _('User identity was successfully updated.') else render :edit @@ -37,7 +38,8 @@ class Admin::IdentitiesController < Admin::ApplicationController def destroy if @identity.destroy - RepairLdapBlockedUserService.new(@user).execute + ::Users::RepairLdapBlockedService.new(@user).execute + redirect_to admin_user_identities_path(@user), status: :found, notice: _('User identity was successfully removed.') else redirect_to admin_user_identities_path(@user), status: :found, alert: _('Failed to remove user identity.') diff --git a/app/controllers/admin/jobs_controller.rb b/app/controllers/admin/jobs_controller.rb index 0c1afdc3d3b..892f6dc657c 100644 --- a/app/controllers/admin/jobs_controller.rb +++ b/app/controllers/admin/jobs_controller.rb @@ -1,25 +1,15 @@ # frozen_string_literal: true class Admin::JobsController < Admin::ApplicationController - # rubocop: disable CodeReuse/ActiveRecord def index + # We need all builds for tabs counters + @all_builds = JobsFinder.new(current_user: current_user).execute + @scope = params[:scope] - @all_builds = Ci::Build - @builds = @all_builds.order('id DESC') - @builds = - case @scope - when 'pending' - @builds.pending.reverse_order - when 'running' - @builds.running.reverse_order - when 'finished' - @builds.finished - else - @builds - end + @builds = JobsFinder.new(current_user: current_user, params: params).execute + @builds = @builds.eager_load_everything @builds = @builds.page(params[:page]).per(30) end - # rubocop: enable CodeReuse/ActiveRecord def cancel_all Ci::Build.running_or_pending.each(&:cancel) diff --git a/app/controllers/admin/sessions_controller.rb b/app/controllers/admin/sessions_controller.rb index 1f946e41995..f9587655a8d 100644 --- a/app/controllers/admin/sessions_controller.rb +++ b/app/controllers/admin/sessions_controller.rb @@ -6,17 +6,23 @@ class Admin::SessionsController < ApplicationController before_action :user_is_admin! def new - # Renders a form in which the admin can enter their password + if current_user_mode.admin_mode? + redirect_to redirect_path, notice: _('Admin mode already enabled') + else + current_user_mode.request_admin_mode! unless current_user_mode.admin_mode_requested? + store_location_for(:redirect, redirect_path) + end end def create if current_user_mode.enable_admin_mode!(password: params[:password]) - redirect_location = stored_location_for(:redirect) || admin_root_path - redirect_to safe_redirect_path(redirect_location) + redirect_to redirect_path, notice: _('Admin mode enabled') else - flash.now[:alert] = _('Invalid Login or password') + flash.now[:alert] = _('Invalid login or password') render :new end + rescue Gitlab::Auth::CurrentUserMode::NotRequestedError + redirect_to new_admin_session_path, alert: _('Re-authentication period expired or never requested. Please try again') end def destroy @@ -30,4 +36,19 @@ class Admin::SessionsController < ApplicationController def user_is_admin! render_404 unless current_user&.admin? end + + def redirect_path + redirect_to_path = safe_redirect_path(stored_location_for(:redirect)) || safe_redirect_path_for_url(request.referer) + + if redirect_to_path && + excluded_redirect_paths.none? { |excluded| redirect_to_path.include?(excluded) } + redirect_to_path + else + admin_root_path + end + end + + def excluded_redirect_paths + [new_admin_session_path, admin_session_path] + end end diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 25c1d80b117..f5306801c04 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -16,15 +16,16 @@ class ApplicationController < ActionController::Base include ConfirmEmailWarning include Gitlab::Tracking::ControllerConcern include Gitlab::Experimentation::ControllerConcern + include InitializesCurrentUserMode before_action :authenticate_user!, except: [:route_not_found] before_action :enforce_terms!, if: :should_enforce_terms? before_action :validate_user_service_ticket! - before_action :check_password_expiration + before_action :check_password_expiration, if: :html_request? before_action :ldap_security_check - before_action :sentry_context + around_action :sentry_context before_action :default_headers - before_action :add_gon_variables, unless: [:peek_request?, :json_request?] + before_action :add_gon_variables, if: :html_request? before_action :configure_permitted_parameters, if: :devise_controller? before_action :require_email, unless: :devise_controller? before_action :active_user_check, unless: :devise_controller? @@ -41,7 +42,6 @@ class ApplicationController < ActionController::Base protect_from_forgery with: :exception, prepend: true helper_method :can? - helper_method :current_user_mode helper_method :import_sources_enabled?, :github_import_enabled?, :gitea_import_enabled?, :github_import_configured?, :gitlab_import_enabled?, :gitlab_import_configured?, @@ -74,6 +74,18 @@ class ApplicationController < ActionController::Base render_403 end + rescue_from Gitlab::Auth::IpBlacklisted do + Gitlab::AuthLogger.error( + message: 'Rack_Attack', + env: :blocklist, + remote_ip: request.ip, + request_method: request.request_method, + path: request.fullpath + ) + + head :forbidden + end + rescue_from Gitlab::Auth::TooManyIps do |e| head :forbidden, retry_after: Gitlab::Auth::UniqueIpsLimiter.config.unique_ips_limit_time_window end @@ -153,7 +165,7 @@ class ApplicationController < ActionController::Base end def log_exception(exception) - Gitlab::Sentry.track_acceptable_exception(exception) + Gitlab::ErrorTracking.track_exception(exception) backtrace_cleaner = request.env["action_dispatch.backtrace_cleaner"] application_trace = ActionDispatch::ExceptionWrapper.new(backtrace_cleaner, exception).application_trace @@ -216,10 +228,6 @@ class ApplicationController < ActionController::Base end end - def respond_201 - head :created - end - def respond_422 head :unprocessable_entity end @@ -455,8 +463,8 @@ class ApplicationController < ActionController::Base response.headers['Page-Title'] = URI.escape(page_title('GitLab')) end - def peek_request? - request.path.start_with?('/-/peek') + def html_request? + request.format.html? end def json_request? @@ -466,7 +474,7 @@ class ApplicationController < ActionController::Base def should_enforce_terms? return false unless Gitlab::CurrentSettings.current_application_settings.enforce_terms - !(peek_request? || devise_controller?) + html_request? && !devise_controller? end def set_usage_stats_consent_flag @@ -524,8 +532,8 @@ class ApplicationController < ActionController::Base @impersonator ||= User.find(session[:impersonator_id]) if session[:impersonator_id] end - def sentry_context - Gitlab::Sentry.context(current_user) + def sentry_context(&block) + Gitlab::ErrorTracking.with_context(current_user, &block) end def allow_gitaly_ref_name_caching @@ -534,10 +542,6 @@ class ApplicationController < ActionController::Base end end - def current_user_mode - @current_user_mode ||= Gitlab::Auth::CurrentUserMode.new(current_user) - end - # A user requires a role and have the setup_for_company attribute set when they are part of the experimental signup # flow (executed by the Growth team). Users are redirected to the welcome page when their role is required and the # experiment is enabled for the current user. diff --git a/app/controllers/autocomplete_controller.rb b/app/controllers/autocomplete_controller.rb index 06531932b31..0df201ab506 100644 --- a/app/controllers/autocomplete_controller.rb +++ b/app/controllers/autocomplete_controller.rb @@ -40,10 +40,20 @@ class AutocompleteController < ApplicationController end def merge_request_target_branches - merge_requests = MergeRequestsFinder.new(current_user, params).execute - target_branches = merge_requests.recent_target_branches + if target_branch_params.present? + merge_requests = MergeRequestsFinder.new(current_user, target_branch_params).execute + target_branches = merge_requests.recent_target_branches + + render json: target_branches.map { |target_branch| { title: target_branch } } + else + render json: { error: _('At least one of group_id or project_id must be specified') }, status: :bad_request + end + end + + private - render json: target_branches.map { |target_branch| { title: target_branch } } + def target_branch_params + params.permit(:group_id, :project_id).select { |_, v| v.present? } end end diff --git a/app/controllers/boards/lists_controller.rb b/app/controllers/boards/lists_controller.rb index 880f7500708..0b8469e8290 100644 --- a/app/controllers/boards/lists_controller.rb +++ b/app/controllers/boards/lists_controller.rb @@ -53,7 +53,7 @@ module Boards service = Boards::Lists::GenerateService.new(board_parent, current_user) if service.execute(board) - lists = board.lists.movable.preload_associations + lists = board.lists.movable.preload_associated_models List.preload_preferences_for_user(lists, current_user) diff --git a/app/controllers/clusters/clusters_controller.rb b/app/controllers/clusters/clusters_controller.rb index 9a539cf7c24..f4b74b14c0b 100644 --- a/app/controllers/clusters/clusters_controller.rb +++ b/app/controllers/clusters/clusters_controller.rb @@ -3,18 +3,15 @@ class Clusters::ClustersController < Clusters::BaseController include RoutableActions - before_action :cluster, only: [:cluster_status, :show, :update, :destroy] + before_action :cluster, only: [:cluster_status, :show, :update, :destroy, :clear_cache] before_action :generate_gcp_authorize_url, only: [:new] before_action :validate_gcp_token, only: [:new] before_action :gcp_cluster, only: [:new] before_action :user_cluster, only: [:new] - before_action :authorize_create_cluster!, only: [:new, :authorize_aws_role, :revoke_aws_role, :aws_proxy] + before_action :authorize_create_cluster!, only: [:new, :authorize_aws_role] before_action :authorize_update_cluster!, only: [:update] - before_action :authorize_admin_cluster!, only: [:destroy] + before_action :authorize_admin_cluster!, only: [:destroy, :clear_cache] before_action :update_applications_status, only: [:cluster_status] - before_action only: [:new, :create_gcp] do - push_frontend_feature_flag(:create_eks_clusters) - end before_action only: [:show] do push_frontend_feature_flag(:enable_cluster_application_elastic_stack) push_frontend_feature_flag(:enable_cluster_application_crossplane) @@ -42,11 +39,10 @@ class Clusters::ClustersController < Clusters::BaseController end def new - return unless Feature.enabled?(:create_eks_clusters) - if params[:provider] == 'aws' @aws_role = current_user.aws_role || Aws::Role.new @aws_role.ensure_role_external_id! + @instance_types = load_instance_types.to_json elsif params[:provider] == 'gcp' redirect_to @authorize_url if @authorize_url && !@valid_gcp_token @@ -113,6 +109,7 @@ class Clusters::ClustersController < Clusters::BaseController generate_gcp_authorize_url validate_gcp_token user_cluster + params[:provider] = 'gcp' render :new, locals: { active_tab: 'create' } end @@ -149,34 +146,24 @@ class Clusters::ClustersController < Clusters::BaseController end def authorize_aws_role - role = current_user.build_aws_role(create_role_params) - - role.save ? respond_201 : respond_422 - end - - def revoke_aws_role - current_user.aws_role&.destroy + response = Clusters::Aws::AuthorizeRoleService.new( + current_user, + params: aws_role_params + ).execute - head :no_content + render json: response.body, status: response.status end - def aws_proxy - response = Clusters::Aws::ProxyService.new( - current_user.aws_role, - params: params - ).execute + def clear_cache + cluster.delete_cached_resources! - render json: response.body, status: response.status + redirect_to cluster.show_path, notice: _('Cluster cache cleared.') end private def destroy_params - # To be uncomented on https://gitlab.com/gitlab-org/gitlab/merge_requests/16954 - # This MR got split into other since it was too big. - # - # params.permit(:cleanup) - {} + params.permit(:cleanup) end def update_params @@ -270,13 +257,12 @@ class Clusters::ClustersController < Clusters::BaseController ) end - def create_role_params + def aws_role_params params.require(:cluster).permit(:role_arn, :role_external_id) end def generate_gcp_authorize_url - params = Feature.enabled?(:create_eks_clusters) ? { provider: :gke } : {} - state = generate_session_key_redirect(clusterable.new_path(params).to_s) + state = generate_session_key_redirect(clusterable.new_path(provider: :gcp).to_s) @authorize_url = GoogleApi::CloudPlatform::Client.new( nil, callback_google_api_auth_url, @@ -317,6 +303,19 @@ class Clusters::ClustersController < Clusters::BaseController end end + ## + # Unfortunately the EC2 API doesn't provide a list of + # possible instance types. There is a workaround, using + # the Pricing API, but instead of requiring the + # user to grant extra permissions for this we use the + # values that validate the CloudFormation template. + def load_instance_types + stack_template = File.read(Rails.root.join('vendor', 'aws', 'cloudformation', 'eks_cluster.yaml')) + instance_types = YAML.safe_load(stack_template).dig('Parameters', 'NodeInstanceType', 'AllowedValues') + + instance_types.map { |type| Hash(name: type, value: type) } + end + def update_applications_status @cluster.applications.each(&:schedule_status_update) end diff --git a/app/controllers/concerns/boards_actions.rb b/app/controllers/concerns/boards_actions.rb index a093d0d6e7f..eb1080cb3d2 100644 --- a/app/controllers/concerns/boards_actions.rb +++ b/app/controllers/concerns/boards_actions.rb @@ -9,6 +9,7 @@ module BoardsActions before_action :boards, only: :index before_action :board, only: :show + before_action :push_wip_limits, only: [:index, :show] end def index @@ -24,6 +25,10 @@ module BoardsActions private + # Noop on FOSS + def push_wip_limits + end + def boards strong_memoize(:boards) do Boards::ListService.new(parent, current_user).execute diff --git a/app/controllers/concerns/confirm_email_warning.rb b/app/controllers/concerns/confirm_email_warning.rb index 86df0010665..32e1a46e580 100644 --- a/app/controllers/concerns/confirm_email_warning.rb +++ b/app/controllers/concerns/confirm_email_warning.rb @@ -4,15 +4,18 @@ module ConfirmEmailWarning extend ActiveSupport::Concern included do - before_action :set_confirm_warning, if: -> { Feature.enabled?(:soft_email_confirmation) } + before_action :set_confirm_warning, if: :show_confirm_warning? end protected + def show_confirm_warning? + html_request? && request.get? && Feature.enabled?(:soft_email_confirmation) + end + def set_confirm_warning return unless current_user return if current_user.confirmed? - return if peek_request? || json_request? || !request.get? email = current_user.unconfirmed_email || current_user.email diff --git a/app/controllers/concerns/cycle_analytics_params.rb b/app/controllers/concerns/cycle_analytics_params.rb index 1645af695be..a78d803927c 100644 --- a/app/controllers/concerns/cycle_analytics_params.rb +++ b/app/controllers/concerns/cycle_analytics_params.rb @@ -38,7 +38,8 @@ module CycleAnalyticsParams end def to_utc_time(field) - Date.parse(field).to_time.utc + date = field.is_a?(Date) ? field : Date.parse(field) + date.to_time.utc end end diff --git a/app/controllers/concerns/enforces_admin_authentication.rb b/app/controllers/concerns/enforces_admin_authentication.rb index e731211f423..527759de0bb 100644 --- a/app/controllers/concerns/enforces_admin_authentication.rb +++ b/app/controllers/concerns/enforces_admin_authentication.rb @@ -18,6 +18,7 @@ module EnforcesAdminAuthentication return unless Feature.enabled?(:user_mode_in_session) unless current_user_mode.admin_mode? + current_user_mode.request_admin_mode! store_location_for(:redirect, request.fullpath) if storable_location? redirect_to(new_admin_session_path, notice: _('Re-authentication required')) end diff --git a/app/controllers/concerns/initializes_current_user_mode.rb b/app/controllers/concerns/initializes_current_user_mode.rb new file mode 100644 index 00000000000..df7cea5c754 --- /dev/null +++ b/app/controllers/concerns/initializes_current_user_mode.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +module InitializesCurrentUserMode + extend ActiveSupport::Concern + + included do + helper_method :current_user_mode + end + + def current_user_mode + @current_user_mode ||= Gitlab::Auth::CurrentUserMode.new(current_user) + end +end diff --git a/app/controllers/concerns/issuable_actions.rb b/app/controllers/concerns/issuable_actions.rb index 6162d006cc7..c4abaacd573 100644 --- a/app/controllers/concerns/issuable_actions.rb +++ b/app/controllers/concerns/issuable_actions.rb @@ -98,13 +98,11 @@ module IssuableActions error_message = "Destroy confirmation not provided for #{issuable.human_class_name}" exception = RuntimeError.new(error_message) - Gitlab::Sentry.track_acceptable_exception( + Gitlab::ErrorTracking.track_exception( exception, - extra: { - project_path: issuable.project.full_path, - issuable_type: issuable.class.name, - issuable_id: issuable.id - } + project_path: issuable.project.full_path, + issuable_type: issuable.class.name, + issuable_id: issuable.id ) index_path = polymorphic_path([parent, issuable.class]) @@ -121,7 +119,7 @@ module IssuableActions end def bulk_update - result = Issuable::BulkUpdateService.new(current_user, bulk_update_params).execute(resource_name) + result = Issuable::BulkUpdateService.new(parent, current_user, bulk_update_params).execute(resource_name) quantity = result[:count] render json: { notice: "#{quantity} #{resource_name.pluralize(quantity)} updated" } diff --git a/app/controllers/concerns/membership_actions.rb b/app/controllers/concerns/membership_actions.rb index 0b2756c0c6a..993f091b0e6 100644 --- a/app/controllers/concerns/membership_actions.rb +++ b/app/controllers/concerns/membership_actions.rb @@ -144,4 +144,15 @@ module MembershipActions end end end + + def requested_relations + case params[:with_inherited_permissions].presence + when 'exclude' + [:direct] + when 'only' + [:inherited] + else + [:inherited, :direct] + end + end end diff --git a/app/controllers/concerns/notes_actions.rb b/app/controllers/concerns/notes_actions.rb index fbae4c53c31..3d599d9e7f9 100644 --- a/app/controllers/concerns/notes_actions.rb +++ b/app/controllers/concerns/notes_actions.rb @@ -63,7 +63,11 @@ module NotesActions json.merge!(note_json(@note)) end - render json: json + if @note.errors.present? && @note.errors.keys != [:commands_only] + render json: json, status: :unprocessable_entity + else + render json: json + end end format.html { redirect_back_or_default } end diff --git a/app/controllers/concerns/service_params.rb b/app/controllers/concerns/service_params.rb index fd9d5fad38e..3ccf227c431 100644 --- a/app/controllers/concerns/service_params.rb +++ b/app/controllers/concerns/service_params.rb @@ -18,6 +18,7 @@ module ServiceParams :channels, :color, :colorize_messages, + :comment_on_event_enabled, :confidential_issues_events, :default_irc_uri, :description, diff --git a/app/controllers/concerns/sessionless_authentication.rb b/app/controllers/concerns/sessionless_authentication.rb index f644923443b..d5c26fca957 100644 --- a/app/controllers/concerns/sessionless_authentication.rb +++ b/app/controllers/concerns/sessionless_authentication.rb @@ -33,6 +33,8 @@ module SessionlessAuthentication end def enable_admin_mode! - current_user_mode.enable_admin_mode!(skip_password_validation: true) if Feature.enabled?(:user_mode_in_session) + return unless Feature.enabled?(:user_mode_in_session) + + current_user_mode.enable_sessionless_admin_mode! end end diff --git a/app/controllers/concerns/sourcegraph_gon.rb b/app/controllers/concerns/sourcegraph_gon.rb index ab4abd734fb..01925cf9d4d 100644 --- a/app/controllers/concerns/sourcegraph_gon.rb +++ b/app/controllers/concerns/sourcegraph_gon.rb @@ -4,7 +4,7 @@ module SourcegraphGon extend ActiveSupport::Concern included do - before_action :push_sourcegraph_gon, unless: :json_request? + before_action :push_sourcegraph_gon, if: :html_request? end private diff --git a/app/controllers/concerns/uploads_actions.rb b/app/controllers/concerns/uploads_actions.rb index b87779c22d3..655575e0944 100644 --- a/app/controllers/concerns/uploads_actions.rb +++ b/app/controllers/concerns/uploads_actions.rb @@ -1,11 +1,16 @@ # frozen_string_literal: true module UploadsActions + extend ActiveSupport::Concern include Gitlab::Utils::StrongMemoize include SendFileUpload UPLOAD_MOUNTS = %w(avatar attachment file logo header_logo favicon).freeze + included do + prepend_before_action :set_request_format_from_path_extension + end + def create uploader = UploadService.new(model, params[:file], uploader_class).execute @@ -39,15 +44,14 @@ module UploadsActions expires_in ttl, directives - disposition = uploader.embeddable? ? 'inline' : 'attachment' - - uploaders = [uploader, *uploader.versions.values] - uploader = uploaders.find { |version| version.filename == params[:filename] } + file_uploader = [uploader, *uploader.versions.values].find do |version| + version.filename == params[:filename] + end - return render_404 unless uploader + return render_404 unless file_uploader workhorse_set_content_type! - send_upload(uploader, attachment: uploader.filename, disposition: disposition) + send_upload(file_uploader, attachment: file_uploader.filename, disposition: content_disposition) end def authorize @@ -64,6 +68,28 @@ module UploadsActions private + # Based on ActionDispatch::Http::MimeNegotiation. We have an + # initializer that monkey-patches this method out (so that repository + # paths don't guess a format based on extension), but we do want this + # behavior when serving uploads. + def set_request_format_from_path_extension + path = request.headers['action_dispatch.original_path'] || request.headers['PATH_INFO'] + + if match = path&.match(/\.(\w+)\z/) + format = Mime[match.captures.first] + + request.format = format.symbol if format + end + end + + def content_disposition + if uploader.embeddable? || uploader.pdf? + 'inline' + else + 'attachment' + end + end + def uploader_class raise NotImplementedError end diff --git a/app/controllers/groups/group_members_controller.rb b/app/controllers/groups/group_members_controller.rb index 1b1416a72d7..dcdf9aced1a 100644 --- a/app/controllers/groups/group_members_controller.rb +++ b/app/controllers/groups/group_members_controller.rb @@ -24,8 +24,7 @@ class Groups::GroupMembersController < Groups::ApplicationController @sort = params[:sort].presence || sort_value_name @project = @group.projects.find(params[:project_id]) if params[:project_id] - - @members = GroupMembersFinder.new(@group).execute + @members = find_members if can_manage_members @invited_members = @members.invite @@ -52,6 +51,12 @@ class Groups::GroupMembersController < Groups::ApplicationController # MembershipActions concern alias_method :membershipable, :group + + private + + def find_members + GroupMembersFinder.new(@group).execute(include_relations: requested_relations) + end end Groups::GroupMembersController.prepend_if_ee('EE::Groups::GroupMembersController') diff --git a/app/controllers/groups_controller.rb b/app/controllers/groups_controller.rb index 755d97b091c..0953ca96317 100644 --- a/app/controllers/groups_controller.rb +++ b/app/controllers/groups_controller.rb @@ -181,6 +181,7 @@ class GroupsController < Groups::ApplicationController :avatar, :description, :emails_disabled, + :mentions_disabled, :lfs_enabled, :name, :path, diff --git a/app/controllers/instance_statistics/conversational_development_index_controller.rb b/app/controllers/instance_statistics/conversational_development_index_controller.rb deleted file mode 100644 index 306c16d559c..00000000000 --- a/app/controllers/instance_statistics/conversational_development_index_controller.rb +++ /dev/null @@ -1,9 +0,0 @@ -# frozen_string_literal: true - -class InstanceStatistics::ConversationalDevelopmentIndexController < InstanceStatistics::ApplicationController - # rubocop: disable CodeReuse/ActiveRecord - def index - @metric = ConversationalDevelopmentIndex::Metric.order(:created_at).last&.present - end - # rubocop: enable CodeReuse/ActiveRecord -end diff --git a/app/controllers/instance_statistics/dev_ops_score_controller.rb b/app/controllers/instance_statistics/dev_ops_score_controller.rb new file mode 100644 index 00000000000..238f7fa7707 --- /dev/null +++ b/app/controllers/instance_statistics/dev_ops_score_controller.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +class InstanceStatistics::DevOpsScoreController < InstanceStatistics::ApplicationController + # rubocop: disable CodeReuse/ActiveRecord + def index + @metric = DevOpsScore::Metric.order(:created_at).last&.present + end + # rubocop: enable CodeReuse/ActiveRecord +end diff --git a/app/controllers/oauth/applications_controller.rb b/app/controllers/oauth/applications_controller.rb index 8dd51ce1d64..bbf0bdd3662 100644 --- a/app/controllers/oauth/applications_controller.rb +++ b/app/controllers/oauth/applications_controller.rb @@ -6,6 +6,7 @@ class Oauth::ApplicationsController < Doorkeeper::ApplicationsController include PageLayoutHelper include OauthApplications include Gitlab::Experimentation::ControllerConcern + include InitializesCurrentUserMode before_action :verify_user_oauth_applications_enabled, except: :index before_action :authenticate_user! diff --git a/app/controllers/oauth/authorizations_controller.rb b/app/controllers/oauth/authorizations_controller.rb index e65726dffbf..2a4e659c5b9 100644 --- a/app/controllers/oauth/authorizations_controller.rb +++ b/app/controllers/oauth/authorizations_controller.rb @@ -2,6 +2,8 @@ class Oauth::AuthorizationsController < Doorkeeper::AuthorizationsController include Gitlab::Experimentation::ControllerConcern + include InitializesCurrentUserMode + layout 'profile' # Overridden from Doorkeeper::AuthorizationsController to diff --git a/app/controllers/omniauth_callbacks_controller.rb b/app/controllers/omniauth_callbacks_controller.rb index eca58748cc5..92f36c031f1 100644 --- a/app/controllers/omniauth_callbacks_controller.rb +++ b/app/controllers/omniauth_callbacks_controller.rb @@ -4,6 +4,7 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController include AuthenticatesWithTwoFactor include Devise::Controllers::Rememberable include AuthHelper + include InitializesCurrentUserMode protect_from_forgery except: [:kerberos, :saml, :cas3, :failure], with: :exception, prepend: true @@ -94,8 +95,12 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController return render_403 unless link_provider_allowed?(oauth['provider']) log_audit_event(current_user, with: oauth['provider']) - identity_linker ||= auth_module::IdentityLinker.new(current_user, oauth, session) + if Feature.enabled?(:user_mode_in_session) + return admin_mode_flow if current_user_mode.admin_mode_requested? + end + + identity_linker ||= auth_module::IdentityLinker.new(current_user, oauth, session) link_identity(identity_linker) if identity_linker.changed? @@ -239,6 +244,24 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController store_location_for(:user, uri.to_s) end end + + def admin_mode_flow + if omniauth_identity_matches_current_user? + current_user_mode.enable_admin_mode!(skip_password_validation: true) + + redirect_to stored_location_for(:redirect) || admin_root_path, notice: _('Admin mode enabled') + else + fail_admin_mode_invalid_credentials + end + end + + def omniauth_identity_matches_current_user? + current_user.matches_identity?(oauth['provider'], oauth['uid']) + end + + def fail_admin_mode_invalid_credentials + redirect_to new_admin_session_path, alert: _('Invalid login or password') + end end OmniauthCallbacksController.prepend_if_ee('EE::OmniauthCallbacksController') diff --git a/app/controllers/projects/branches_controller.rb b/app/controllers/projects/branches_controller.rb index 578a3d451a7..09754409104 100644 --- a/app/controllers/projects/branches_controller.rb +++ b/app/controllers/projects/branches_controller.rb @@ -46,7 +46,7 @@ class Projects::BranchesController < Projects::ApplicationController def diverging_commit_counts respond_to do |format| format.json do - service = Branches::DivergingCommitCountsService.new(repository) + service = ::Branches::DivergingCommitCountsService.new(repository) branches = BranchesFinder.new(repository, params.permit(names: [])).execute Gitlab::GitalyClient.allow_n_plus_1_calls do @@ -63,7 +63,7 @@ class Projects::BranchesController < Projects::ApplicationController redirect_to_autodeploy = project.empty_repo? && project.deployment_platform.present? - result = CreateBranchService.new(project, current_user) + result = ::Branches::CreateService.new(project, current_user) .execute(branch_name, ref) success = (result[:status] == :success) @@ -102,7 +102,7 @@ class Projects::BranchesController < Projects::ApplicationController def destroy @branch_name = Addressable::URI.unescape(params[:id]) - result = DeleteBranchService.new(project, current_user).execute(@branch_name) + result = ::Branches::DeleteService.new(project, current_user).execute(@branch_name) respond_to do |format| format.html do @@ -118,7 +118,7 @@ class Projects::BranchesController < Projects::ApplicationController end def destroy_all_merged - DeleteMergedBranchesService.new(@project, current_user).async_execute + ::Branches::DeleteMergedService.new(@project, current_user).async_execute redirect_to project_branches_path(@project), notice: _('Merged branches are being deleted. This can take some time depending on the number of branches. Please refresh the page to see changes.') @@ -133,8 +133,6 @@ class Projects::BranchesController < Projects::ApplicationController # frontend could omit this set. To prevent excessive I/O, we require # that a list of names be specified. def limit_diverging_commit_counts! - return unless Feature.enabled?(:limit_diverging_commit_counts, default_enabled: true) - limit = Kaminari.config.default_per_page # If we don't have many branches in the repository, then go ahead. diff --git a/app/controllers/projects/ci/lints_controller.rb b/app/controllers/projects/ci/lints_controller.rb index d7a0b7ece14..812420e9708 100644 --- a/app/controllers/projects/ci/lints_controller.rb +++ b/app/controllers/projects/ci/lints_controller.rb @@ -8,11 +8,13 @@ class Projects::Ci::LintsController < Projects::ApplicationController def create @content = params[:content] - @error = Gitlab::Ci::YamlProcessor.validation_message(@content, yaml_processor_options) - @status = @error.blank? + result = Gitlab::Ci::YamlProcessor.new_with_validation_errors(@content, yaml_processor_options) - if @error.blank? - @config_processor = Gitlab::Ci::YamlProcessor.new(@content, yaml_processor_options) + @error = result.errors.join(', ') + @status = result.valid? + + if result.valid? + @config_processor = result.content @stages = @config_processor.stages @builds = @config_processor.builds @jobs = @config_processor.jobs diff --git a/app/controllers/projects/environments/prometheus_api_controller.rb b/app/controllers/projects/environments/prometheus_api_controller.rb index e902d218c75..98fcc594d6e 100644 --- a/app/controllers/projects/environments/prometheus_api_controller.rb +++ b/app/controllers/projects/environments/prometheus_api_controller.rb @@ -7,23 +7,34 @@ class Projects::Environments::PrometheusApiController < Projects::ApplicationCon before_action :environment def proxy - result = Prometheus::ProxyService.new( + variable_substitution_result = + variable_substitution_service.new(environment, permit_params).execute + + if variable_substitution_result[:status] == :error + return error_response(variable_substitution_result) + end + + prometheus_result = Prometheus::ProxyService.new( environment, proxy_method, proxy_path, - proxy_params + variable_substitution_result[:params] ).execute - return continue_polling_response if result.nil? - return error_response(result) if result[:status] == :error + return continue_polling_response if prometheus_result.nil? + return error_response(prometheus_result) if prometheus_result[:status] == :error - success_response(result) + success_response(prometheus_result) end private - def query_context - Gitlab::Prometheus::QueryVariables.call(environment) + def variable_substitution_service + Prometheus::ProxyVariableSubstitutionService + end + + def permit_params + params.permit! end def environment @@ -37,15 +48,4 @@ class Projects::Environments::PrometheusApiController < Projects::ApplicationCon def proxy_path params[:proxy_path] end - - def proxy_params - substitute_query_variables(params).permit! - end - - def substitute_query_variables(params) - query = params[:query] - return params unless query - - params.merge(query: query % query_context) - end end diff --git a/app/controllers/projects/environments/sample_metrics_controller.rb b/app/controllers/projects/environments/sample_metrics_controller.rb new file mode 100644 index 00000000000..79a7eab150b --- /dev/null +++ b/app/controllers/projects/environments/sample_metrics_controller.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +class Projects::Environments::SampleMetricsController < Projects::ApplicationController + def query + result = Metrics::SampleMetricsService.new(params[:identifier]).query + + if result + render json: { "status": "success", "data": { "resultType": "matrix", "result": result } } + else + render_404 + end + end +end diff --git a/app/controllers/projects/environments_controller.rb b/app/controllers/projects/environments_controller.rb index 4562296cea0..1179782036d 100644 --- a/app/controllers/projects/environments_controller.rb +++ b/app/controllers/projects/environments_controller.rb @@ -7,14 +7,15 @@ class Projects::EnvironmentsController < Projects::ApplicationController before_action :authorize_read_environment! before_action :authorize_create_environment!, only: [:new, :create] before_action :authorize_stop_environment!, only: [:stop] - before_action :authorize_update_environment!, only: [:edit, :update] + before_action :authorize_update_environment!, only: [:edit, :update, :cancel_auto_stop] before_action :authorize_admin_environment!, only: [:terminal, :terminal_websocket_authorize] - before_action :environment, only: [:show, :edit, :update, :stop, :terminal, :terminal_websocket_authorize, :metrics] + before_action :environment, only: [:show, :edit, :update, :stop, :terminal, :terminal_websocket_authorize, :metrics, :cancel_auto_stop] before_action :verify_api_request!, only: :terminal_websocket_authorize - before_action :expire_etag_cache, only: [:index] + before_action :expire_etag_cache, only: [:index], unless: -> { request.format.json? } before_action only: [:metrics, :additional_metrics, :metrics_dashboard] do push_frontend_feature_flag(:prometheus_computed_alerts) end + after_action :expire_etag_cache, only: [:cancel_auto_stop] def index @environments = project.environments @@ -104,6 +105,27 @@ class Projects::EnvironmentsController < Projects::ApplicationController end end + def cancel_auto_stop + result = Environments::ResetAutoStopService.new(project, current_user) + .execute(environment) + + if result[:status] == :success + respond_to do |format| + message = _('Auto stop successfully canceled.') + + format.html { redirect_back_or_default(default: { action: 'show' }, options: { notice: message }) } + format.json { render json: { message: message }, status: :ok } + end + else + respond_to do |format| + message = result[:message] + + format.html { redirect_back_or_default(default: { action: 'show' }, options: { alert: message }) } + format.json { render json: { message: message }, status: :unprocessable_entity } + end + end + end + def terminal # Currently, this acts as a hint to load the terminal details into the cache # if they aren't there already. In the future, users will need these details @@ -175,8 +197,6 @@ class Projects::EnvironmentsController < Projects::ApplicationController end def expire_etag_cache - return if request.format.json? - # this forces to reload json content Gitlab::EtagCaching::Store.new.tap do |store| store.touch(project_environments_path(project, format: :json)) @@ -222,6 +242,10 @@ class Projects::EnvironmentsController < Projects::ApplicationController def authorize_stop_environment! access_denied! unless can?(current_user, :stop_environment, environment) end + + def authorize_update_environment! + access_denied! unless can?(current_user, :update_environment, environment) + end end Projects::EnvironmentsController.prepend_if_ee('EE::Projects::EnvironmentsController') diff --git a/app/controllers/projects/error_tracking_controller.rb b/app/controllers/projects/error_tracking_controller.rb index 7143424473e..ba21ccfb169 100644 --- a/app/controllers/projects/error_tracking_controller.rb +++ b/app/controllers/projects/error_tracking_controller.rb @@ -44,13 +44,18 @@ class Projects::ErrorTrackingController < Projects::ApplicationController private def render_index_json - service = ErrorTracking::ListIssuesService.new(project, current_user) + service = ErrorTracking::ListIssuesService.new( + project, + current_user, + list_issues_params + ) result = service.execute return if handle_errors(result) render json: { errors: serialize_errors(result[:issues]), + pagination: result[:pagination], external_url: service.external_url } end @@ -72,8 +77,10 @@ class Projects::ErrorTrackingController < Projects::ApplicationController return if handle_errors(result) + result_with_syntax_highlight = Gitlab::ErrorTracking::StackTraceHighlightDecorator.decorate(result[:latest_event]) + render json: { - error: serialize_error_event(result[:latest_event]) + error: serialize_error_event(result_with_syntax_highlight) } end @@ -106,6 +113,10 @@ class Projects::ErrorTrackingController < Projects::ApplicationController end end + def list_issues_params + params.permit(:search_term, :sort, :cursor) + end + def list_projects_params params.require(:error_tracking_setting).permit([:api_host, :token]) end diff --git a/app/controllers/projects/hook_logs_controller.rb b/app/controllers/projects/hook_logs_controller.rb index a7afc3d77a5..ed7e7b68acb 100644 --- a/app/controllers/projects/hook_logs_controller.rb +++ b/app/controllers/projects/hook_logs_controller.rb @@ -16,15 +16,17 @@ class Projects::HookLogsController < Projects::ApplicationController end def retry - result = hook.execute(hook_log.request_data, hook_log.trigger) - - set_hook_execution_notice(result) - + execute_hook redirect_to edit_project_hook_path(@project, @hook) end private + def execute_hook + result = hook.execute(hook_log.request_data, hook_log.trigger) + set_hook_execution_notice(result) + end + def hook @hook ||= @project.hooks.find(params[:hook_id]) end diff --git a/app/controllers/projects/issues_controller.rb b/app/controllers/projects/issues_controller.rb index 009765702ab..229374c3929 100644 --- a/app/controllers/projects/issues_controller.rb +++ b/app/controllers/projects/issues_controller.rb @@ -44,7 +44,7 @@ class Projects::IssuesController < Projects::ApplicationController before_action do push_frontend_feature_flag(:vue_issuable_sidebar, project.group) - push_frontend_feature_flag(:release_search_filter, project) + push_frontend_feature_flag(:release_search_filter, project, default_enabled: true) end respond_to :html @@ -237,7 +237,10 @@ class Projects::IssuesController < Projects::ApplicationController end def issue_params - params.require(:issue).permit(*issue_params_attributes) + params.require(:issue).permit( + *issue_params_attributes, + sentry_issue_attributes: [:sentry_issue_identifier] + ) end def issue_params_attributes diff --git a/app/controllers/projects/jobs_controller.rb b/app/controllers/projects/jobs_controller.rb index 1d914ab6011..796f3ff603f 100644 --- a/app/controllers/projects/jobs_controller.rb +++ b/app/controllers/projects/jobs_controller.rb @@ -12,39 +12,20 @@ class Projects::JobsController < Projects::ApplicationController before_action :authorize_use_build_terminal!, only: [:terminal, :terminal_websocket_authorize] before_action :verify_api_request!, only: :terminal_websocket_authorize before_action only: [:show] do - push_frontend_feature_flag(:job_log_json, project) + push_frontend_feature_flag(:job_log_json, project, default_enabled: true) end layout 'project' - # rubocop: disable CodeReuse/ActiveRecord def index + # We need all builds for tabs counters + @all_builds = JobsFinder.new(current_user: current_user, project: @project).execute + @scope = params[:scope] - @all_builds = project.builds.relevant - @builds = @all_builds.order('ci_builds.id DESC') - @builds = - case @scope - when 'pending' - @builds.pending.reverse_order - when 'running' - @builds.running.reverse_order - when 'finished' - @builds.finished - else - @builds - end - @builds = @builds.includes([ - { pipeline: [:project, :user] }, - :job_artifacts_archive, - :metadata, - :trigger_request, - :project, - :user, - :tags - ]) + @builds = JobsFinder.new(current_user: current_user, project: @project, params: params).execute + @builds = @builds.eager_load_everything @builds = @builds.page(params[:page]).per(30).without_count end - # rubocop: enable CodeReuse/ActiveRecord # rubocop: disable CodeReuse/ActiveRecord def show @@ -72,7 +53,7 @@ class Projects::JobsController < Projects::ApplicationController format.json do # TODO: when the feature flag is removed we should not pass # content_format to serialize method. - content_format = Feature.enabled?(:job_log_json, @project) ? :json : :html + content_format = Feature.enabled?(:job_log_json, @project, default_enabled: true) ? :json : :html build_trace = Ci::BuildTrace.new( build: @build, diff --git a/app/controllers/projects/merge_requests/diffs_controller.rb b/app/controllers/projects/merge_requests/diffs_controller.rb index 42f9c0522a3..37d90ecdc00 100644 --- a/app/controllers/projects/merge_requests/diffs_controller.rb +++ b/app/controllers/projects/merge_requests/diffs_controller.rb @@ -5,8 +5,8 @@ class Projects::MergeRequests::DiffsController < Projects::MergeRequests::Applic include RendersNotes before_action :apply_diff_view_cookie! - before_action :commit, except: :diffs_batch - before_action :define_diff_vars, except: :diffs_batch + before_action :commit + before_action :define_diff_vars before_action :define_diff_comment_vars, except: [:diffs_batch, :diffs_metadata] def show @@ -20,14 +20,11 @@ class Projects::MergeRequests::DiffsController < Projects::MergeRequests::Applic def diffs_batch return render_404 unless Feature.enabled?(:diffs_batch_load, @merge_request.project) - diffable = @merge_request.merge_request_diff - - return render_404 unless diffable - - diffs = diffable.diffs_in_batch(params[:page], params[:per_page], diff_options: diff_options) + diffs = @compare.diffs_in_batch(params[:page], params[:per_page], diff_options: diff_options) positions = @merge_request.note_positions_for_paths(diffs.diff_file_paths, current_user) diffs.unfold_diff_files(positions.unfoldable) + diffs.write_cache options = { merge_request: @merge_request, @@ -39,8 +36,10 @@ class Projects::MergeRequests::DiffsController < Projects::MergeRequests::Applic end def diffs_metadata + diffs = @compare.diffs(diff_options) + render json: DiffsMetadataSerializer.new(project: @merge_request.project) - .represent(@diffs, additional_attributes) + .represent(diffs, additional_attributes) end private @@ -49,11 +48,13 @@ class Projects::MergeRequests::DiffsController < Projects::MergeRequests::Applic [{ source_project: :namespace }, { target_project: :namespace }] end + # Deprecated: https://gitlab.com/gitlab-org/gitlab/issues/37735 def render_diffs + diffs = @compare.diffs(diff_options) @environment = @merge_request.environments_for(current_user).last - @diffs.unfold_diff_files(note_positions.unfoldable) - @diffs.write_cache + diffs.unfold_diff_files(note_positions.unfoldable) + diffs.write_cache request = { current_user: current_user, @@ -63,15 +64,14 @@ class Projects::MergeRequests::DiffsController < Projects::MergeRequests::Applic options = additional_attributes.merge(diff_view: diff_view) - render json: DiffsSerializer.new(request).represent(@diffs, options) + render json: DiffsSerializer.new(request).represent(diffs, options) end + # Deprecated: https://gitlab.com/gitlab-org/gitlab/issues/37735 def define_diff_vars @merge_request_diffs = @merge_request.merge_request_diffs.viewable.order_id_desc @compare = commit || find_merge_request_diff_compare return render_404 unless @compare - - @diffs = @compare.diffs(diff_options) end # rubocop: disable CodeReuse/ActiveRecord @@ -84,6 +84,8 @@ class Projects::MergeRequests::DiffsController < Projects::MergeRequests::Applic # rubocop: enable CodeReuse/ActiveRecord # rubocop: disable CodeReuse/ActiveRecord + # + # Deprecated: https://gitlab.com/gitlab-org/gitlab/issues/37735 def find_merge_request_diff_compare @merge_request_diff = if diff_id = params[:diff_id].presence @@ -126,6 +128,7 @@ class Projects::MergeRequests::DiffsController < Projects::MergeRequests::Applic } end + # Deprecated: https://gitlab.com/gitlab-org/gitlab/issues/37735 def define_diff_comment_vars @new_diff_note_attrs = { noteable_type: 'MergeRequest', diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb index 766ec1e33f3..69e3e7c7acb 100644 --- a/app/controllers/projects/merge_requests_controller.rb +++ b/app/controllers/projects/merge_requests_controller.rb @@ -20,11 +20,13 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo before_action :check_user_can_push_to_source_branch!, only: [:rebase] before_action only: [:show] do push_frontend_feature_flag(:diffs_batch_load, @project) + push_frontend_feature_flag(:single_mr_diff_view, @project) end before_action do push_frontend_feature_flag(:vue_issuable_sidebar, @project.group) - push_frontend_feature_flag(:release_search_filter, @project) + push_frontend_feature_flag(:release_search_filter, @project, default_enabled: true) + push_frontend_feature_flag(:async_mr_widget, @project) end around_action :allow_gitaly_ref_name_caching, only: [:index, :show, :discussions] @@ -218,11 +220,16 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo end def ci_environments_status - environments = if ci_environments_status_on_merge_result? - EnvironmentStatus.after_merge_request(@merge_request, current_user) - else - EnvironmentStatus.for_merge_request(@merge_request, current_user) - end + environments = + if ci_environments_status_on_merge_result? + if Feature.enabled?(:deployment_merge_requests_widget, @project) + EnvironmentStatus.for_deployed_merge_request(@merge_request, current_user) + else + EnvironmentStatus.after_merge_request(@merge_request, current_user) + end + else + EnvironmentStatus.for_merge_request(@merge_request, current_user) + end render json: EnvironmentStatusSerializer.new(current_user: current_user).represent(environments) end diff --git a/app/controllers/projects/pages_controller.rb b/app/controllers/projects/pages_controller.rb index 722fc30b3ff..f1e591ea1ec 100644 --- a/app/controllers/projects/pages_controller.rb +++ b/app/controllers/projects/pages_controller.rb @@ -15,8 +15,7 @@ class Projects::PagesController < Projects::ApplicationController # rubocop: enable CodeReuse/ActiveRecord def destroy - project.remove_pages - project.pages_domains.destroy_all # rubocop: disable DestroyAll + ::Pages::DeleteService.new(@project, current_user).execute respond_to do |format| format.html do diff --git a/app/controllers/projects/pages_domains_controller.rb b/app/controllers/projects/pages_domains_controller.rb index b693642981e..5a81a064048 100644 --- a/app/controllers/projects/pages_domains_controller.rb +++ b/app/controllers/projects/pages_domains_controller.rb @@ -8,7 +8,6 @@ class Projects::PagesDomainsController < Projects::ApplicationController before_action :domain, except: [:new, :create] def show - redirect_to edit_project_pages_domain_path(@project, @domain) end def new @@ -24,17 +23,18 @@ class Projects::PagesDomainsController < Projects::ApplicationController flash[:alert] = 'Failed to verify domain ownership' end - redirect_to edit_project_pages_domain_path(@project, @domain) + redirect_to project_pages_domain_path(@project, @domain) end def edit + redirect_to project_pages_domain_path(@project, @domain) end def create @domain = @project.pages_domains.create(create_params) if @domain.valid? - redirect_to edit_project_pages_domain_path(@project, @domain) + redirect_to project_pages_domain_path(@project, @domain) else render 'new' end @@ -46,7 +46,7 @@ class Projects::PagesDomainsController < Projects::ApplicationController status: :found, notice: 'Domain was updated' else - render 'edit' + render 'show' end end @@ -68,7 +68,7 @@ class Projects::PagesDomainsController < Projects::ApplicationController flash[:alert] = @domain.errors.full_messages.join(', ') end - redirect_to edit_project_pages_domain_path(@project, @domain) + redirect_to project_pages_domain_path(@project, @domain) end private diff --git a/app/controllers/projects/pipeline_schedules_controller.rb b/app/controllers/projects/pipeline_schedules_controller.rb index 72e939a3310..6a7e2b69652 100644 --- a/app/controllers/projects/pipeline_schedules_controller.rb +++ b/app/controllers/projects/pipeline_schedules_controller.rb @@ -83,12 +83,14 @@ class Projects::PipelineSchedulesController < Projects::ApplicationController def play_rate_limit return unless current_user - limiter = ::Gitlab::ActionRateLimiter.new(action: :play_pipeline_schedule) - - return unless limiter.throttled?([current_user, schedule], 1) + if rate_limiter.throttled?(:play_pipeline_schedule, scope: [current_user, schedule]) + flash[:alert] = _('You cannot play this scheduled pipeline at the moment. Please wait a minute.') + redirect_to pipeline_schedules_path(@project) + end + end - flash[:alert] = _('You cannot play this scheduled pipeline at the moment. Please wait a minute.') - redirect_to pipeline_schedules_path(@project) + def rate_limiter + ::Gitlab::ApplicationRateLimiter end def schedule diff --git a/app/controllers/projects/pipelines_controller.rb b/app/controllers/projects/pipelines_controller.rb index 4d35353d5f5..e3ef8f3f2ff 100644 --- a/app/controllers/projects/pipelines_controller.rb +++ b/app/controllers/projects/pipelines_controller.rb @@ -11,7 +11,6 @@ class Projects::PipelinesController < Projects::ApplicationController before_action :authorize_create_pipeline!, only: [:new, :create] before_action :authorize_update_pipeline!, only: [:retry, :cancel] before_action do - push_frontend_feature_flag(:hide_dismissed_vulnerabilities) push_frontend_feature_flag(:junit_pipeline_view) end diff --git a/app/controllers/projects/project_members_controller.rb b/app/controllers/projects/project_members_controller.rb index b01d48ca3d3..7bd084458d1 100644 --- a/app/controllers/projects/project_members_controller.rb +++ b/app/controllers/projects/project_members_controller.rb @@ -17,7 +17,7 @@ class Projects::ProjectMembersController < Projects::ApplicationController @skip_groups << @project.namespace_id unless @project.personal? @skip_groups += @project.group.ancestors.pluck(:id) if @project.group - @project_members = MembersFinder.new(@project, current_user).execute + @project_members = MembersFinder.new(@project, current_user).execute(include_relations: requested_relations) if params[:search].present? @project_members = @project_members.joins(:user).merge(User.search(params[:search])) diff --git a/app/controllers/projects/raw_controller.rb b/app/controllers/projects/raw_controller.rb index c94fdd9483d..f39d98be516 100644 --- a/app/controllers/projects/raw_controller.rb +++ b/app/controllers/projects/raw_controller.rb @@ -4,11 +4,15 @@ class Projects::RawController < Projects::ApplicationController include ExtractsPath include SendsBlob + include StaticObjectExternalStorage + + prepend_before_action(only: [:show]) { authenticate_sessionless_user!(:blob) } before_action :require_non_empty_project before_action :assign_ref_vars before_action :authorize_download_code! - before_action :show_rate_limit, only: [:show] + before_action :show_rate_limit, only: [:show], unless: :external_storage_request? + before_action :redirect_to_external_storage, only: :show, if: :static_objects_external_storage_enabled? def show @blob = @repository.blob_at(@commit.id, @path) @@ -19,14 +23,16 @@ class Projects::RawController < Projects::ApplicationController private def show_rate_limit - limiter = ::Gitlab::ActionRateLimiter.new(action: :show_raw_controller) - - return unless limiter.throttled?([@project, @commit, @path], raw_blob_request_limit) + if rate_limiter.throttled?(:show_raw_controller, scope: [@project, @commit, @path], threshold: raw_blob_request_limit) + rate_limiter.log_request(request, :raw_blob_request_limit, current_user) - limiter.log_request(request, :raw_blob_request_limit, current_user) + flash[:alert] = _('You cannot access the raw file. Please wait a minute.') + redirect_to project_blob_path(@project, File.join(@ref, @path)), status: :too_many_requests + end + end - flash[:alert] = _('You cannot access the raw file. Please wait a minute.') - redirect_to project_blob_path(@project, File.join(@ref, @path)), status: :too_many_requests + def rate_limiter + ::Gitlab::ApplicationRateLimiter end def raw_blob_request_limit diff --git a/app/controllers/projects/releases_controller.rb b/app/controllers/projects/releases_controller.rb index 72c82aec31d..ffe69fe97e4 100644 --- a/app/controllers/projects/releases_controller.rb +++ b/app/controllers/projects/releases_controller.rb @@ -6,10 +6,11 @@ class Projects::ReleasesController < Projects::ApplicationController before_action :release, only: %i[edit update] before_action :authorize_read_release! before_action do - push_frontend_feature_flag(:release_edit_page, project, default_enabled: true) push_frontend_feature_flag(:release_issue_summary, project) + push_frontend_feature_flag(:release_evidence_collection, project) end before_action :authorize_update_release!, only: %i[edit update] + before_action :authorize_download_code!, only: [:evidence] def index respond_to do |format| @@ -20,6 +21,14 @@ class Projects::ReleasesController < Projects::ApplicationController end end + def evidence + respond_to do |format| + format.json do + render json: release.evidence_summary + end + end + end + protected def releases @@ -35,7 +44,6 @@ class Projects::ReleasesController < Projects::ApplicationController private def authorize_update_release! - access_denied! unless Feature.enabled?(:release_edit_page, project, default_enabled: true) access_denied! unless can?(current_user, :update_release, release) end diff --git a/app/controllers/projects/service_hook_logs_controller.rb b/app/controllers/projects/service_hook_logs_controller.rb new file mode 100644 index 00000000000..5c814ea139f --- /dev/null +++ b/app/controllers/projects/service_hook_logs_controller.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true + +class Projects::ServiceHookLogsController < Projects::HookLogsController + before_action :service, only: [:show, :retry] + + def retry + execute_hook + redirect_to edit_project_service_path(@project, @service) + end + + private + + def hook + @hook ||= service.service_hook + end + + def service + @service ||= @project.find_or_initialize_service(params[:service_id]) + end +end diff --git a/app/controllers/projects/services_controller.rb b/app/controllers/projects/services_controller.rb index c9f680a4696..daaca9e1268 100644 --- a/app/controllers/projects/services_controller.rb +++ b/app/controllers/projects/services_controller.rb @@ -7,6 +7,7 @@ class Projects::ServicesController < Projects::ApplicationController before_action :authorize_admin_project! before_action :ensure_service_enabled before_action :service + before_action :web_hook_logs, only: [:edit, :update] respond_to :html @@ -77,6 +78,12 @@ class Projects::ServicesController < Projects::ApplicationController @service ||= @project.find_or_initialize_service(params[:id]) end + def web_hook_logs + return unless @service.service_hook.present? + + @web_hook_logs ||= @service.service_hook.web_hook_logs.recent.page(params[:page]) + end + def ensure_service_enabled render_404 unless service end diff --git a/app/controllers/projects/settings/ci_cd_controller.rb b/app/controllers/projects/settings/ci_cd_controller.rb index cfed8727450..6af815b8daa 100644 --- a/app/controllers/projects/settings/ci_cd_controller.rb +++ b/app/controllers/projects/settings/ci_cd_controller.rb @@ -13,7 +13,7 @@ module Projects Projects::UpdateService.new(project, current_user, update_params).tap do |service| result = service.execute if result[:status] == :success - flash[:notice] = _("Pipelines settings for '%{project_name}' were successfully updated.") % { project_name: @project.name } + flash[:toast] = _("Pipelines settings for '%{project_name}' were successfully updated.") % { project_name: @project.name } run_autodevops_pipeline(service) @@ -39,7 +39,7 @@ module Projects def reset_registration_token @project.reset_runners_token! - flash[:notice] = _('New runners registration token has been generated!') + flash[:toast] = _("New runners registration token has been generated!") redirect_to namespace_project_settings_ci_cd_path end @@ -65,12 +65,14 @@ module Projects return unless service.run_auto_devops_pipeline? if @project.empty_repo? - flash[:warning] = _("This repository is currently empty. A new Auto DevOps pipeline will be created after a new file has been pushed to a branch.") + flash[:notice] = _("This repository is currently empty. A new Auto DevOps pipeline will be created after a new file has been pushed to a branch.") return end CreatePipelineWorker.perform_async(project.id, current_user.id, project.default_branch, :web, ignore_skip_ci: true, save_on_errors: false) - flash[:success] = "A new Auto DevOps pipeline has been created, go to <a href=\"#{project_pipelines_path(@project)}\">Pipelines page</a> for details".html_safe + + pipelines_link_start = '<a href="%{url}">'.html_safe % { url: project_pipelines_path(@project) } + flash[:toast] = _("A new Auto DevOps pipeline has been created, go to %{pipelines_link_start}Pipelines page%{pipelines_link_end} for details") % { pipelines_link_start: pipelines_link_start, pipelines_link_end: "</a>".html_safe } end def define_variables diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb index e5dea031bb5..47d6fb67108 100644 --- a/app/controllers/projects_controller.rb +++ b/app/controllers/projects_controller.rb @@ -32,6 +32,9 @@ class ProjectsController < Projects::ApplicationController before_action :authorize_archive_project!, only: [:archive, :unarchive] before_action :event_filter, only: [:show, :activity] + # Project Export Rate Limit + before_action :export_rate_limit, only: [:export, :download_export, :generate_new_export] + layout :determine_layout def index @@ -465,6 +468,21 @@ class ProjectsController < Projects::ApplicationController def present_project @project = @project.present(current_user: current_user) end + + def export_rate_limit + prefixed_action = "project_#{params[:action]}".to_sym + + if rate_limiter.throttled?(prefixed_action, scope: [current_user, prefixed_action, @project]) + rate_limiter.log_request(request, "#{prefixed_action}_request_limit".to_sym, current_user) + + flash[:alert] = _('This endpoint has been requested too many times. Try again later.') + redirect_to edit_project_path(@project) + end + end + + def rate_limiter + ::Gitlab::ApplicationRateLimiter + end end ProjectsController.prepend_if_ee('EE::ProjectsController') diff --git a/app/controllers/snippets_controller.rb b/app/controllers/snippets_controller.rb index 5805d068e21..54774df5e76 100644 --- a/app/controllers/snippets_controller.rb +++ b/app/controllers/snippets_controller.rb @@ -15,13 +15,9 @@ class SnippetsController < ApplicationController before_action :snippet, only: [:show, :edit, :destroy, :update, :raw] - # Allow read snippet + before_action :authorize_create_snippet!, only: [:new, :create] before_action :authorize_read_snippet!, only: [:show, :raw] - - # Allow modify snippet before_action :authorize_update_snippet!, only: [:edit, :update] - - # Allow destroy snippet before_action :authorize_admin_snippet!, only: [:destroy] skip_before_action :authenticate_user!, only: [:index, :show, :raw] @@ -140,6 +136,10 @@ class SnippetsController < ApplicationController return render_404 unless can?(current_user, :admin_personal_snippet, @snippet) end + def authorize_create_snippet! + return render_404 unless can?(current_user, :create_personal_snippet) + end + def snippet_params params.require(:personal_snippet).permit(:title, :content, :file_name, :private, :visibility_level, :description) end diff --git a/app/controllers/uploads_controller.rb b/app/controllers/uploads_controller.rb index 635db386792..67d33648470 100644 --- a/app/controllers/uploads_controller.rb +++ b/app/controllers/uploads_controller.rb @@ -20,7 +20,6 @@ class UploadsController < ApplicationController skip_before_action :authenticate_user! before_action :upload_mount_satisfied? - before_action :find_model before_action :authorize_access!, only: [:show] before_action :authorize_create_access!, only: [:create, :authorize] before_action :verify_workhorse_api!, only: [:authorize] |