From 6e4e1050d9dba2b7b2523fdd1768823ab85feef4 Mon Sep 17 00:00:00 2001 From: GitLab Bot Date: Thu, 20 Aug 2020 18:42:06 +0000 Subject: Add latest changes from gitlab-org/gitlab@13-3-stable-ee --- .../admin/application_settings_controller.rb | 10 +-- app/controllers/admin/integrations_controller.rb | 2 +- app/controllers/admin/services_controller.rb | 3 - app/controllers/clusters/base_controller.rb | 4 -- .../concerns/authenticates_with_two_factor.rb | 12 ++-- app/controllers/concerns/checks_collaboration.rb | 2 +- .../concerns/graceful_timeout_handling.rb | 15 +++++ app/controllers/concerns/integrations_actions.rb | 3 - app/controllers/concerns/issuable_collections.rb | 2 +- app/controllers/concerns/packages_access.rb | 20 ++++++ app/controllers/concerns/paginated_collection.rb | 2 +- app/controllers/concerns/renders_blob.rb | 8 ++- app/controllers/concerns/send_file_upload.rb | 21 +++++- app/controllers/concerns/snippets_actions.rb | 22 ++++--- app/controllers/concerns/wiki_actions.rb | 10 ++- app/controllers/dashboard/projects_controller.rb | 2 +- app/controllers/dashboard/todos_controller.rb | 2 - app/controllers/explore/projects_controller.rb | 2 +- app/controllers/groups/packages_controller.rb | 13 ++++ app/controllers/groups/releases_controller.rb | 23 +++++++ app/controllers/groups/variables_controller.rb | 7 +- .../import/available_namespaces_controller.rb | 7 ++ app/controllers/import/base_controller.rb | 8 ++- app/controllers/import/gitea_controller.rb | 10 +++ app/controllers/import/github_controller.rb | 76 ++++++++++++++++++++-- app/controllers/import/manifest_controller.rb | 57 ++++++++++------ app/controllers/invites_controller.rb | 46 ++++++------- app/controllers/omniauth_callbacks_controller.rb | 7 ++ app/controllers/profiles/passwords_controller.rb | 2 +- .../profiles/personal_access_tokens_controller.rb | 8 +-- app/controllers/projects/artifacts_controller.rb | 2 +- app/controllers/projects/blob_controller.rb | 2 - app/controllers/projects/ci/lints_controller.rb | 34 +++++++--- app/controllers/projects/commit_controller.rb | 8 ++- .../projects/cycle_analytics/events_controller.rb | 1 + .../projects/cycle_analytics_controller.rb | 1 + .../projects/environments_controller.rb | 15 ++--- app/controllers/projects/forks_controller.rb | 14 +++- app/controllers/projects/incidents_controller.rb | 8 +++ app/controllers/projects/issues_controller.rb | 20 ++++-- .../projects/merge_requests/diffs_controller.rb | 2 +- .../projects/merge_requests_controller.rb | 19 ++++-- .../metrics/dashboards/builder_controller.rb | 42 ++++++++++++ .../projects/metrics_dashboard_controller.rb | 3 +- .../projects/packages/package_files_controller.rb | 16 +++++ .../projects/packages/packages_controller.rb | 24 +++++++ .../projects/pipelines/tests_controller.rb | 19 ++---- app/controllers/projects/pipelines_controller.rb | 11 +--- .../projects/product_analytics_controller.rb | 53 +++++++++++++++ .../projects/prometheus/alerts_controller.rb | 8 +-- .../projects/protected_refs_controller.rb | 2 +- app/controllers/projects/releases_controller.rb | 2 +- app/controllers/projects/services_controller.rb | 1 - .../projects/settings/operations_controller.rb | 6 +- .../projects/snippets/blobs_controller.rb | 2 +- app/controllers/projects/snippets_controller.rb | 4 ++ app/controllers/projects/variables_controller.rb | 7 +- app/controllers/projects_controller.rb | 8 +++ .../registrations/experience_levels_controller.rb | 4 +- app/controllers/registrations_controller.rb | 14 ++-- .../repositories/git_http_controller.rb | 2 +- .../repositories/lfs_storage_controller.rb | 5 +- app/controllers/root_controller.rb | 5 ++ app/controllers/search_controller.rb | 14 +++- app/controllers/sessions_controller.rb | 7 +- app/controllers/snippets_controller.rb | 4 ++ 66 files changed, 602 insertions(+), 193 deletions(-) create mode 100644 app/controllers/concerns/graceful_timeout_handling.rb create mode 100644 app/controllers/concerns/packages_access.rb create mode 100644 app/controllers/groups/packages_controller.rb create mode 100644 app/controllers/groups/releases_controller.rb create mode 100644 app/controllers/import/available_namespaces_controller.rb create mode 100644 app/controllers/projects/incidents_controller.rb create mode 100644 app/controllers/projects/metrics/dashboards/builder_controller.rb create mode 100644 app/controllers/projects/packages/package_files_controller.rb create mode 100644 app/controllers/projects/packages/packages_controller.rb create mode 100644 app/controllers/projects/product_analytics_controller.rb (limited to 'app/controllers') diff --git a/app/controllers/admin/application_settings_controller.rb b/app/controllers/admin/application_settings_controller.rb index 41a6616d10c..3a5b8b2862e 100644 --- a/app/controllers/admin/application_settings_controller.rb +++ b/app/controllers/admin/application_settings_controller.rb @@ -16,7 +16,7 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController push_frontend_feature_flag(:ci_instance_variables_ui, default_enabled: true) end - VALID_SETTING_PANELS = %w(general integrations repository + VALID_SETTING_PANELS = %w(general repository ci_cd reporting metrics_and_profiling network preferences).freeze @@ -32,12 +32,7 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController end def integrations - if Feature.enabled?(:instance_level_integrations) - @integrations = Service.find_or_initialize_instances.sort_by(&:title) - else - set_application_setting - perform_update if submitted? - end + @integrations = Service.find_or_initialize_instances.sort_by(&:title) end def update @@ -225,7 +220,6 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController :lets_encrypt_terms_of_service_accepted, :domain_blacklist_file, :raw_blob_request_limit, - :namespace_storage_size_limit, :issues_create_limit, :default_branch_name, disabled_oauth_sign_in_sources: [], diff --git a/app/controllers/admin/integrations_controller.rb b/app/controllers/admin/integrations_controller.rb index 4f3be43d14d..b2d5a2d130c 100644 --- a/app/controllers/admin/integrations_controller.rb +++ b/app/controllers/admin/integrations_controller.rb @@ -12,7 +12,7 @@ class Admin::IntegrationsController < Admin::ApplicationController end def integrations_enabled? - Feature.enabled?(:instance_level_integrations) + true end def scoped_edit_integration_path(integration) diff --git a/app/controllers/admin/services_controller.rb b/app/controllers/admin/services_controller.rb index e0137accd2d..1bc82e98ab8 100644 --- a/app/controllers/admin/services_controller.rb +++ b/app/controllers/admin/services_controller.rb @@ -5,9 +5,6 @@ class Admin::ServicesController < Admin::ApplicationController before_action :service, only: [:edit, :update] before_action :whitelist_query_limiting, only: [:index] - before_action only: :edit do - push_frontend_feature_flag(:integration_form_refactor, default_enabled: true) - end def index @services = Service.find_or_create_templates.sort_by(&:title) diff --git a/app/controllers/clusters/base_controller.rb b/app/controllers/clusters/base_controller.rb index c79a0bb01bc..188805c6106 100644 --- a/app/controllers/clusters/base_controller.rb +++ b/app/controllers/clusters/base_controller.rb @@ -6,10 +6,6 @@ class Clusters::BaseController < ApplicationController skip_before_action :authenticate_user! before_action :authorize_read_cluster! - before_action do - push_frontend_feature_flag(:managed_apps_local_tiller, clusterable, default_enabled: true) - end - helper_method :clusterable private diff --git a/app/controllers/concerns/authenticates_with_two_factor.rb b/app/controllers/concerns/authenticates_with_two_factor.rb index b885e55f902..4b4bcc8d37e 100644 --- a/app/controllers/concerns/authenticates_with_two_factor.rb +++ b/app/controllers/concerns/authenticates_with_two_factor.rb @@ -33,9 +33,7 @@ module AuthenticatesWithTwoFactor end def locked_user_redirect(user) - flash.now[:alert] = locked_user_redirect_alert(user) - - render 'devise/sessions/new' + redirect_to new_user_session_path, alert: locked_user_redirect_alert(user) end def authenticate_with_two_factor @@ -54,7 +52,13 @@ module AuthenticatesWithTwoFactor private def locked_user_redirect_alert(user) - user.access_locked? ? _('Your account is locked.') : _('Invalid Login or password') + if user.access_locked? + _('Your account is locked.') + elsif !user.confirmed? + I18n.t('devise.failure.unconfirmed') + else + _('Invalid Login or password') + end end def clear_two_factor_attempt! diff --git a/app/controllers/concerns/checks_collaboration.rb b/app/controllers/concerns/checks_collaboration.rb index 1fa82f7dcd4..87239facdeb 100644 --- a/app/controllers/concerns/checks_collaboration.rb +++ b/app/controllers/concerns/checks_collaboration.rb @@ -17,7 +17,7 @@ module ChecksCollaboration # used across multiple calls in the view def user_access(project) @user_access ||= {} - @user_access[project] ||= Gitlab::UserAccess.new(current_user, project: project) + @user_access[project] ||= Gitlab::UserAccess.new(current_user, container: project) end # rubocop:enable Gitlab/ModuleWithInstanceVariables end diff --git a/app/controllers/concerns/graceful_timeout_handling.rb b/app/controllers/concerns/graceful_timeout_handling.rb new file mode 100644 index 00000000000..490c0ec3b1d --- /dev/null +++ b/app/controllers/concerns/graceful_timeout_handling.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +module GracefulTimeoutHandling + extend ActiveSupport::Concern + + included do + rescue_from ActiveRecord::QueryCanceled do |exception| + raise exception unless request.format.json? + + log_exception(exception) + + render json: { error: _('There is too much data to calculate. Please change your selection.') } + end + end +end diff --git a/app/controllers/concerns/integrations_actions.rb b/app/controllers/concerns/integrations_actions.rb index 46febc44807..9a8e5d14123 100644 --- a/app/controllers/concerns/integrations_actions.rb +++ b/app/controllers/concerns/integrations_actions.rb @@ -8,9 +8,6 @@ module IntegrationsActions before_action :not_found, unless: :integrations_enabled? before_action :integration, only: [:edit, :update, :test] - before_action only: :edit do - push_frontend_feature_flag(:integration_form_refactor, default_enabled: true) - end end def edit diff --git a/app/controllers/concerns/issuable_collections.rb b/app/controllers/concerns/issuable_collections.rb index 4f61e5ed711..89ba2175b60 100644 --- a/app/controllers/concerns/issuable_collections.rb +++ b/app/controllers/concerns/issuable_collections.rb @@ -65,7 +65,7 @@ module IssuableCollections def page_count_for_relation(relation, row_count) limit = relation.limit_value.to_f - return 1 if limit.zero? + return 1 if limit == 0 (row_count.to_f / limit).ceil end diff --git a/app/controllers/concerns/packages_access.rb b/app/controllers/concerns/packages_access.rb new file mode 100644 index 00000000000..6df2e064bb2 --- /dev/null +++ b/app/controllers/concerns/packages_access.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true + +module PackagesAccess + extend ActiveSupport::Concern + + included do + before_action :verify_packages_enabled! + before_action :verify_read_package! + end + + private + + def verify_packages_enabled! + render_404 unless Gitlab.config.packages.enabled + end + + def verify_read_package! + authorize_read_package!(project) + end +end diff --git a/app/controllers/concerns/paginated_collection.rb b/app/controllers/concerns/paginated_collection.rb index be84215a9e2..fcee4493314 100644 --- a/app/controllers/concerns/paginated_collection.rb +++ b/app/controllers/concerns/paginated_collection.rb @@ -6,7 +6,7 @@ module PaginatedCollection private def redirect_out_of_range(collection, total_pages = collection.total_pages) - return false if total_pages.zero? + return false if total_pages == 0 out_of_range = collection.current_page > total_pages diff --git a/app/controllers/concerns/renders_blob.rb b/app/controllers/concerns/renders_blob.rb index b8026c7a01d..a15bf27a22f 100644 --- a/app/controllers/concerns/renders_blob.rb +++ b/app/controllers/concerns/renders_blob.rb @@ -29,6 +29,12 @@ module RendersBlob end def conditionally_expand_blob(blob) - blob.expand! if params[:expanded] == 'true' + conditionally_expand_blobs([blob]) + end + + def conditionally_expand_blobs(blobs) + return unless params[:expanded] == 'true' + + blobs.each { |blob| blob.expand! } end end diff --git a/app/controllers/concerns/send_file_upload.rb b/app/controllers/concerns/send_file_upload.rb index 2f5dc09be4a..7cb19fc7e58 100644 --- a/app/controllers/concerns/send_file_upload.rb +++ b/app/controllers/concerns/send_file_upload.rb @@ -18,7 +18,11 @@ module SendFileUpload send_params.merge!(filename: attachment, disposition: disposition) end - if file_upload.file_storage? + if image_scaling_request?(file_upload) + location = file_upload.file_storage? ? file_upload.path : file_upload.url + headers.store(*Gitlab::Workhorse.send_scaled_image(location, params[:width].to_i)) + head :ok + elsif file_upload.file_storage? send_file file_upload.path, send_params elsif file_upload.class.proxy_download_enabled? || proxy headers.store(*Gitlab::Workhorse.send_url(file_upload.url(**redirect_params))) @@ -37,4 +41,19 @@ module SendFileUpload "application/octet-stream" end end + + private + + def image_scaling_request?(file_upload) + avatar_image_upload?(file_upload) && valid_image_scaling_width? && current_user && + Feature.enabled?(:dynamic_image_resizing, current_user) + end + + def avatar_image_upload?(file_upload) + file_upload.try(:image?) && file_upload.try(:mounted_as)&.to_sym == :avatar + end + + def valid_image_scaling_width? + Avatarable::ALLOWED_IMAGE_SCALER_WIDTHS.include?(params[:width]&.to_i) + end end diff --git a/app/controllers/concerns/snippets_actions.rb b/app/controllers/concerns/snippets_actions.rb index 048b18c5c61..5552fd663f7 100644 --- a/app/controllers/concerns/snippets_actions.rb +++ b/app/controllers/concerns/snippets_actions.rb @@ -55,10 +55,9 @@ module SnippetsActions # rubocop:disable Gitlab/ModuleWithInstanceVariables def show - conditionally_expand_blob(blob) - respond_to do |format| format.html do + conditionally_expand_blob(blob) @note = Note.new(noteable: @snippet, project: @snippet.project) @noteable = @snippet @@ -68,11 +67,14 @@ module SnippetsActions end format.json do + conditionally_expand_blob(blob) render_blob_json(blob) end format.js do if @snippet.embeddable? + conditionally_expand_blobs(blobs) + render 'shared/snippets/show' else head :not_found @@ -109,13 +111,15 @@ module SnippetsActions # rubocop:disable Gitlab/ModuleWithInstanceVariables def blob - return unless snippet + @blob ||= blobs.first + end - @blob ||= if snippet.empty_repo? - snippet.blob - else - snippet.blobs.first - end + def blobs + @blobs ||= if snippet.empty_repo? + [snippet.blob] + else + snippet.blobs + end end # rubocop:enable Gitlab/ModuleWithInstanceVariables @@ -132,6 +136,8 @@ module SnippetsActions end def redirect_if_binary + return if Feature.enabled?(:snippets_binary_blob) + redirect_to gitlab_snippet_path(snippet) if blob&.binary? end end diff --git a/app/controllers/concerns/wiki_actions.rb b/app/controllers/concerns/wiki_actions.rb index a5182000f5b..5b953fe37d6 100644 --- a/app/controllers/concerns/wiki_actions.rb +++ b/app/controllers/concerns/wiki_actions.rb @@ -8,6 +8,8 @@ module WikiActions extend ActiveSupport::Concern included do + before_action { respond_to :html } + before_action :authorize_read_wiki! before_action :authorize_create_wiki!, only: [:edit, :create] before_action :authorize_admin_wiki!, only: :destroy @@ -65,6 +67,8 @@ module WikiActions @ref = params[:version_id] @path = page.path + Gitlab::UsageDataCounters::WikiPageCounter.count(:view) + render 'shared/wikis/show' elsif file_blob send_blob(wiki.repository, file_blob) @@ -107,14 +111,16 @@ module WikiActions # rubocop:disable Gitlab/ModuleWithInstanceVariables def create - @page = WikiPages::CreateService.new(container: container, current_user: current_user, params: wiki_params).execute + response = WikiPages::CreateService.new(container: container, current_user: current_user, params: wiki_params).execute + @page = response.payload[:page] - if page.persisted? + if response.success? redirect_to( wiki_page_path(wiki, page), notice: _('Wiki was successfully updated.') ) else + flash[:alert] = response.message render 'shared/wikis/edit' end rescue Gitlab::Git::Wiki::OperationError => e diff --git a/app/controllers/dashboard/projects_controller.rb b/app/controllers/dashboard/projects_controller.rb index ad64b6c4f94..91704f030cd 100644 --- a/app/controllers/dashboard/projects_controller.rb +++ b/app/controllers/dashboard/projects_controller.rb @@ -9,7 +9,7 @@ class Dashboard::ProjectsController < Dashboard::ApplicationController include FiltersEvents prepend_before_action(only: [:index]) { authenticate_sessionless_user!(:rss) } - before_action :set_non_archived_param + before_action :set_non_archived_param, only: [:index, :starred] before_action :set_sorting before_action :projects, only: [:index] skip_cross_project_access_check :index, :starred diff --git a/app/controllers/dashboard/todos_controller.rb b/app/controllers/dashboard/todos_controller.rb index db40b0bed77..4fc2f7b0571 100644 --- a/app/controllers/dashboard/todos_controller.rb +++ b/app/controllers/dashboard/todos_controller.rb @@ -9,8 +9,6 @@ class Dashboard::TodosController < Dashboard::ApplicationController before_action :authorize_read_group!, only: :index before_action :find_todos, only: [:index, :destroy_all] - track_unique_visits :index, target_id: 'u_analytics_todos' - def index @sort = params[:sort] @todos = @todos.page(params[:page]) diff --git a/app/controllers/explore/projects_controller.rb b/app/controllers/explore/projects_controller.rb index f1f41e67a4c..b3fa089a712 100644 --- a/app/controllers/explore/projects_controller.rb +++ b/app/controllers/explore/projects_controller.rb @@ -80,7 +80,7 @@ class Explore::ProjectsController < Explore::ApplicationController # rubocop: disable CodeReuse/ActiveRecord def preload_associations(projects) - projects.includes(:route, :creator, :group, namespace: [:route, :owner]) + projects.includes(:route, :creator, :group, :project_feature, namespace: [:route, :owner]) end # rubocop: enable CodeReuse/ActiveRecord diff --git a/app/controllers/groups/packages_controller.rb b/app/controllers/groups/packages_controller.rb new file mode 100644 index 00000000000..600acc72e67 --- /dev/null +++ b/app/controllers/groups/packages_controller.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +module Groups + class PackagesController < Groups::ApplicationController + before_action :verify_packages_enabled! + + private + + def verify_packages_enabled! + render_404 unless group.packages_feature_enabled? + end + end +end diff --git a/app/controllers/groups/releases_controller.rb b/app/controllers/groups/releases_controller.rb new file mode 100644 index 00000000000..500c57a6f3e --- /dev/null +++ b/app/controllers/groups/releases_controller.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true + +module Groups + class ReleasesController < Groups::ApplicationController + def index + respond_to do |format| + format.json do + render json: ReleaseSerializer.new.represent(releases) + end + end + end + + private + + def releases + ReleasesFinder + .new(@group, current_user, { include_subgroups: true }) + .execute(preload: false) + .page(params[:page]) + .per(30) + end + end +end diff --git a/app/controllers/groups/variables_controller.rb b/app/controllers/groups/variables_controller.rb index 02b015e8e53..fb639f6e472 100644 --- a/app/controllers/groups/variables_controller.rb +++ b/app/controllers/groups/variables_controller.rb @@ -15,7 +15,12 @@ module Groups end def update - if @group.update(group_variables_params) + update_result = Ci::ChangeVariablesService.new( + container: @group, current_user: current_user, + params: group_variables_params + ).execute + + if update_result respond_to do |format| format.json { render_group_variables } end diff --git a/app/controllers/import/available_namespaces_controller.rb b/app/controllers/import/available_namespaces_controller.rb new file mode 100644 index 00000000000..7983b4f20b5 --- /dev/null +++ b/app/controllers/import/available_namespaces_controller.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +class Import::AvailableNamespacesController < ApplicationController + def index + render json: NamespaceSerializer.new.represent(current_user.manageable_groups_with_routes) + end +end diff --git a/app/controllers/import/base_controller.rb b/app/controllers/import/base_controller.rb index bc05030f8af..8a7a4c92b37 100644 --- a/app/controllers/import/base_controller.rb +++ b/app/controllers/import/base_controller.rb @@ -41,6 +41,10 @@ class Import::BaseController < ApplicationController raise NotImplementedError end + def extra_representation_opts + {} + end + private def filter_attribute @@ -58,11 +62,11 @@ class Import::BaseController < ApplicationController end def serialized_provider_repos - Import::ProviderRepoSerializer.new(current_user: current_user).represent(importable_repos, provider: provider_name, provider_url: provider_url) + Import::ProviderRepoSerializer.new(current_user: current_user).represent(importable_repos, provider: provider_name, provider_url: provider_url, **extra_representation_opts) end def serialized_incompatible_repos - Import::ProviderRepoSerializer.new(current_user: current_user).represent(incompatible_repos, provider: provider_name, provider_url: provider_url) + Import::ProviderRepoSerializer.new(current_user: current_user).represent(incompatible_repos, provider: provider_name, provider_url: provider_url, **extra_representation_opts) end def serialized_imported_projects diff --git a/app/controllers/import/gitea_controller.rb b/app/controllers/import/gitea_controller.rb index efeff8439e4..4785a71b8a1 100644 --- a/app/controllers/import/gitea_controller.rb +++ b/app/controllers/import/gitea_controller.rb @@ -54,6 +54,16 @@ class Import::GiteaController < Import::GithubController end end + override :client_repos + def client_repos + @client_repos ||= filtered(client.repos) + end + + override :client + def client + @client ||= Gitlab::LegacyGithubImport::Client.new(session[access_token_key], client_options) + end + override :client_options def client_options { host: provider_url, api_version: 'v1' } diff --git a/app/controllers/import/github_controller.rb b/app/controllers/import/github_controller.rb index ac6b8c06d66..29fe34f0734 100644 --- a/app/controllers/import/github_controller.rb +++ b/app/controllers/import/github_controller.rb @@ -10,6 +10,9 @@ class Import::GithubController < Import::BaseController before_action :provider_auth, only: [:status, :realtime_changes, :create] before_action :expire_etag_cache, only: [:status, :create] + OAuthConfigMissingError = Class.new(StandardError) + + rescue_from OAuthConfigMissingError, with: :missing_oauth_config rescue_from Octokit::Unauthorized, with: :provider_unauthorized rescue_from Octokit::TooManyRequests, with: :provider_rate_limit @@ -22,7 +25,7 @@ class Import::GithubController < Import::BaseController end def callback - session[access_token_key] = client.get_token(params[:code]) + session[access_token_key] = get_token(params[:code]) redirect_to status_import_url end @@ -77,9 +80,7 @@ class Import::GithubController < Import::BaseController override :provider_url def provider_url strong_memoize(:provider_url) do - provider = Gitlab::Auth::OAuth::Provider.config_for('github') - - provider&.dig('url').presence || 'https://github.com' + oauth_config&.dig('url').presence || 'https://github.com' end end @@ -104,11 +105,66 @@ class Import::GithubController < Import::BaseController end def client - @client ||= Gitlab::LegacyGithubImport::Client.new(session[access_token_key], client_options) + @client ||= if Feature.enabled?(:remove_legacy_github_client) + Gitlab::GithubImport::Client.new(session[access_token_key]) + else + Gitlab::LegacyGithubImport::Client.new(session[access_token_key], client_options) + end end def client_repos - @client_repos ||= filtered(client.repos) + @client_repos ||= if Feature.enabled?(:remove_legacy_github_client) + filtered(concatenated_repos) + else + filtered(client.repos) + end + end + + def concatenated_repos + return [] unless client.respond_to?(:each_page) + + client.each_page(:repos).flat_map(&:objects) + end + + def oauth_client + raise OAuthConfigMissingError unless oauth_config + + @oauth_client ||= ::OAuth2::Client.new( + oauth_config.app_id, + oauth_config.app_secret, + oauth_options.merge(ssl: { verify: oauth_config['verify_ssl'] }) + ) + end + + def oauth_config + @oauth_config ||= Gitlab::Auth::OAuth::Provider.config_for('github') + end + + def oauth_options + if oauth_config + oauth_config.dig('args', 'client_options').deep_symbolize_keys + else + OmniAuth::Strategies::GitHub.default_options[:client_options].symbolize_keys + end + end + + def authorize_url + if Feature.enabled?(:remove_legacy_github_client) + oauth_client.auth_code.authorize_url( + redirect_uri: callback_import_url, + scope: 'repo, user, user:email' + ) + else + client.authorize_url(callback_import_url) + end + end + + def get_token(code) + if Feature.enabled?(:remove_legacy_github_client) + oauth_client.auth_code.get_token(code).token + else + client.get_token(code) + end end def verify_import_enabled @@ -116,7 +172,7 @@ class Import::GithubController < Import::BaseController end def go_to_provider_for_permissions - redirect_to client.authorize_url(callback_import_url) + redirect_to authorize_url end def import_enabled? @@ -152,6 +208,12 @@ class Import::GithubController < Import::BaseController alert: _("GitHub API rate limit exceeded. Try again after %{reset_time}") % { reset_time: reset_time } end + def missing_oauth_config + session[access_token_key] = nil + redirect_to new_import_url, + alert: _('Missing OAuth configuration for GitHub.') + end + def access_token_key :"#{provider_name}_access_token" end diff --git a/app/controllers/import/manifest_controller.rb b/app/controllers/import/manifest_controller.rb index 9aec870c6ea..9c47e6d4b0b 100644 --- a/app/controllers/import/manifest_controller.rb +++ b/app/controllers/import/manifest_controller.rb @@ -1,6 +1,8 @@ # frozen_string_literal: true class Import::ManifestController < Import::BaseController + extend ::Gitlab::Utils::Override + before_action :whitelist_query_limiting, only: [:create] before_action :verify_import_enabled before_action :ensure_import_vars, only: [:create, :status] @@ -8,16 +10,9 @@ class Import::ManifestController < Import::BaseController def new end - # rubocop: disable CodeReuse/ActiveRecord def status - @already_added_projects = find_already_added_projects - already_added_import_urls = @already_added_projects.pluck(:import_url) - - @pending_repositories = repositories.to_a.reject do |repository| - already_added_import_urls.include?(repository[:url]) - end + super end - # rubocop: enable CodeReuse/ActiveRecord def upload group = Group.find(params[:group_id]) @@ -42,8 +37,8 @@ class Import::ManifestController < Import::BaseController end end - def jobs - render json: find_jobs + def realtime_changes + super end def create @@ -54,12 +49,43 @@ class Import::ManifestController < Import::BaseController project = Gitlab::ManifestImport::ProjectCreator.new(repository, group, current_user).execute if project.persisted? - render json: ProjectSerializer.new.represent(project) + render json: ProjectSerializer.new.represent(project, serializer: :import) else render json: { errors: project_save_error(project) }, status: :unprocessable_entity end end + protected + + # rubocop: disable CodeReuse/ActiveRecord + override :importable_repos + def importable_repos + already_added_projects_names = already_added_projects.pluck(:import_url) + + repositories.reject { |repo| already_added_projects_names.include?(repo[:url]) } + end + # rubocop: enable CodeReuse/ActiveRecord + + override :incompatible_repos + def incompatible_repos + [] + end + + override :provider_name + def provider_name + :manifest + end + + override :provider_url + def provider_url + nil + end + + override :extra_representation_opts + def extra_representation_opts + { group_full_path: group.full_path } + end + private def ensure_import_vars @@ -82,15 +108,6 @@ class Import::ManifestController < Import::BaseController find_already_added_projects.to_json(only: [:id], methods: [:import_status]) end - # rubocop: disable CodeReuse/ActiveRecord - def find_already_added_projects - group.all_projects - .where(import_type: 'manifest') - .where(creator_id: current_user) - .with_import_state - end - # rubocop: enable CodeReuse/ActiveRecord - def verify_import_enabled render_404 unless manifest_import_enabled? end diff --git a/app/controllers/invites_controller.rb b/app/controllers/invites_controller.rb index 5bd9ac7f275..29cafbbbdb6 100644 --- a/app/controllers/invites_controller.rb +++ b/app/controllers/invites_controller.rb @@ -4,6 +4,7 @@ class InvitesController < ApplicationController include Gitlab::Utils::StrongMemoize before_action :member + before_action :invite_details skip_before_action :authenticate_user!, only: :decline helper_method :member?, :current_user_matches_invite? @@ -16,9 +17,8 @@ class InvitesController < ApplicationController def accept if member.accept_invite!(current_user) - label, path = source_info(member.source) - - redirect_to path, notice: _("You have been granted %{member_human_access} access to %{label}.") % { member_human_access: member.human_access, label: label } + redirect_to invite_details[:path], notice: _("You have been granted %{member_human_access} access to %{title} %{name}.") % + { member_human_access: member.human_access, title: invite_details[:title], name: invite_details[:name] } else redirect_back_or_default(options: { alert: _("The invitation could not be accepted.") }) end @@ -26,8 +26,6 @@ class InvitesController < ApplicationController def decline if member.decline_invite! - label, _ = source_info(member.source) - path = if current_user dashboard_projects_path @@ -35,7 +33,8 @@ class InvitesController < ApplicationController new_user_session_path end - redirect_to path, notice: _("You have declined the invitation to join %{label}.") % { label: label } + redirect_to path, notice: _("You have declined the invitation to join %{title} %{name}.") % + { title: invite_details[:title], name: invite_details[:name] } else redirect_back_or_default(options: { alert: _("The invitation could not be declined.") }) end @@ -76,24 +75,25 @@ class InvitesController < ApplicationController notice = notice.join(' ') + "." store_location_for :user, request.fullpath - redirect_to new_user_session_path, notice: notice + redirect_to new_user_session_path(invite_email: member.invite_email), notice: notice end - def source_info(source) - case source - when Project - project = member.source - label = "project #{project.full_name}" - path = project_path(project) - when Group - group = member.source - label = "group #{group.name}" - path = group_path(group) - else - label = "who knows what" - path = dashboard_projects_path - end - - [label, path] + def invite_details + @invite_details ||= case @member.source + when Project + { + name: @member.source.full_name, + url: project_url(@member.source), + title: _("project"), + path: project_path(@member.source) + } + when Group + { + name: @member.source.name, + url: group_url(@member.source), + title: _("group"), + path: group_path(@member.source) + } + end end end diff --git a/app/controllers/omniauth_callbacks_controller.rb b/app/controllers/omniauth_callbacks_controller.rb index 706a4843117..6a393405e4d 100644 --- a/app/controllers/omniauth_callbacks_controller.rb +++ b/app/controllers/omniauth_callbacks_controller.rb @@ -27,6 +27,7 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController user = User.by_login(params[:username]) user&.increment_failed_attempts! + log_failed_login(params[:username], failed_strategy.name) end super @@ -90,6 +91,10 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController private + def log_failed_login(user, provider) + # overridden in EE + end + def after_omniauth_failure_path_for(scope) if Feature.enabled?(:user_mode_in_session) return new_admin_session_path if current_user_mode.admin_mode_requested? @@ -198,6 +203,8 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController end def fail_login(user) + log_failed_login(user.username, oauth['provider']) + error_message = user.errors.full_messages.to_sentence redirect_to omniauth_error_path(oauth['provider'], error: error_message) diff --git a/app/controllers/profiles/passwords_controller.rb b/app/controllers/profiles/passwords_controller.rb index d2787c2e450..fccbc29f598 100644 --- a/app/controllers/profiles/passwords_controller.rb +++ b/app/controllers/profiles/passwords_controller.rb @@ -52,7 +52,7 @@ class Profiles::PasswordsController < Profiles::ApplicationController result = Users::UpdateService.new(current_user, password_attributes.merge(user: @user)).execute if result[:status] == :success - flash[:notice] = _('Password was successfully updated. Please login with it') + flash[:notice] = _('Password was successfully updated. Please sign in again.') redirect_to new_user_session_path else @user.reset diff --git a/app/controllers/profiles/personal_access_tokens_controller.rb b/app/controllers/profiles/personal_access_tokens_controller.rb index 30f25e8fdaa..21adc032940 100644 --- a/app/controllers/profiles/personal_access_tokens_controller.rb +++ b/app/controllers/profiles/personal_access_tokens_controller.rb @@ -20,12 +20,8 @@ class Profiles::PersonalAccessTokensController < Profiles::ApplicationController def revoke @personal_access_token = finder.find(params[:id]) - - if @personal_access_token.revoke! - flash[:notice] = _("Revoked personal access token %{personal_access_token_name}!") % { personal_access_token_name: @personal_access_token.name } - else - flash[:alert] = _("Could not revoke personal access token %{personal_access_token_name}.") % { personal_access_token_name: @personal_access_token.name } - end + service = PersonalAccessTokens::RevokeService.new(current_user, token: @personal_access_token).execute + service.success? ? flash[:notice] = service.message : flash[:alert] = service.message redirect_to profile_personal_access_tokens_path end diff --git a/app/controllers/projects/artifacts_controller.rb b/app/controllers/projects/artifacts_controller.rb index fef3c6cf424..652687932fd 100644 --- a/app/controllers/projects/artifacts_controller.rb +++ b/app/controllers/projects/artifacts_controller.rb @@ -108,7 +108,7 @@ class Projects::ArtifactsController < Projects::ApplicationController end def validate_artifacts! - render_404 unless build&.artifacts? + render_404 unless build&.available_artifacts? end def build diff --git a/app/controllers/projects/blob_controller.rb b/app/controllers/projects/blob_controller.rb index 7f14522e61b..d969e7bf771 100644 --- a/app/controllers/projects/blob_controller.rb +++ b/app/controllers/projects/blob_controller.rb @@ -257,5 +257,3 @@ class Projects::BlobController < Projects::ApplicationController params.permit(:full, :since, :to, :bottom, :unfold, :offset, :indent) end end - -Projects::BlobController.prepend_if_ee('EE::Projects::BlobController') diff --git a/app/controllers/projects/ci/lints_controller.rb b/app/controllers/projects/ci/lints_controller.rb index 73b3eb9c205..c13baaea8c6 100644 --- a/app/controllers/projects/ci/lints_controller.rb +++ b/app/controllers/projects/ci/lints_controller.rb @@ -8,16 +8,30 @@ class Projects::Ci::LintsController < Projects::ApplicationController def create @content = params[:content] - result = Gitlab::Ci::YamlProcessor.new_with_validation_errors(@content, yaml_processor_options) - - @status = result.valid? - @errors = result.errors - - if result.valid? - @config_processor = result.config - @stages = @config_processor.stages - @builds = @config_processor.builds - @jobs = @config_processor.jobs + @dry_run = params[:dry_run] + + if @dry_run && Gitlab::Ci::Features.lint_creates_pipeline_with_dry_run?(@project) + pipeline = Ci::CreatePipelineService + .new(@project, current_user, ref: @project.default_branch) + .execute(:push, dry_run: true, content: @content) + + @status = pipeline.error_messages.empty? + @stages = pipeline.stages + @errors = pipeline.error_messages.map(&:content) + @warnings = pipeline.warning_messages.map(&:content) + else + result = Gitlab::Ci::YamlProcessor.new_with_validation_errors(@content, yaml_processor_options) + + @status = result.valid? + @errors = result.errors + @warnings = result.warnings + + if result.valid? + @config_processor = result.config + @stages = @config_processor.stages + @builds = @config_processor.builds + @jobs = @config_processor.jobs + end end render :show diff --git a/app/controllers/projects/commit_controller.rb b/app/controllers/projects/commit_controller.rb index 3f2dc9b09fa..b0c6f3cc6a1 100644 --- a/app/controllers/projects/commit_controller.rb +++ b/app/controllers/projects/commit_controller.rb @@ -15,8 +15,8 @@ class Projects::CommitController < Projects::ApplicationController before_action :authorize_download_code! before_action :authorize_read_pipeline!, only: [:pipelines] before_action :commit - before_action :define_commit_vars, only: [:show, :diff_for_path, :pipelines, :merge_requests] - before_action :define_note_vars, only: [:show, :diff_for_path] + before_action :define_commit_vars, only: [:show, :diff_for_path, :diff_files, :pipelines, :merge_requests] + before_action :define_note_vars, only: [:show, :diff_for_path, :diff_files] before_action :authorize_edit_tree!, only: [:revert, :cherry_pick] BRANCH_SEARCH_LIMIT = 1000 @@ -41,6 +41,10 @@ class Projects::CommitController < Projects::ApplicationController render_diff_for_path(@commit.diffs(diff_options)) end + def diff_files + render json: { html: view_to_html_string('projects/commit/diff_files', diffs: @diffs, environment: @environment) } + end + # rubocop: disable CodeReuse/ActiveRecord def pipelines @pipelines = @commit.pipelines.order(id: :desc) diff --git a/app/controllers/projects/cycle_analytics/events_controller.rb b/app/controllers/projects/cycle_analytics/events_controller.rb index 673f53c221b..c69bf029c73 100644 --- a/app/controllers/projects/cycle_analytics/events_controller.rb +++ b/app/controllers/projects/cycle_analytics/events_controller.rb @@ -4,6 +4,7 @@ module Projects module CycleAnalytics class EventsController < Projects::ApplicationController include CycleAnalyticsParams + include GracefulTimeoutHandling before_action :authorize_read_cycle_analytics! before_action :authorize_read_build!, only: [:test, :staging] diff --git a/app/controllers/projects/cycle_analytics_controller.rb b/app/controllers/projects/cycle_analytics_controller.rb index 898d888c978..ef97bc795f9 100644 --- a/app/controllers/projects/cycle_analytics_controller.rb +++ b/app/controllers/projects/cycle_analytics_controller.rb @@ -5,6 +5,7 @@ class Projects::CycleAnalyticsController < Projects::ApplicationController include ActionView::Helpers::TextHelper include CycleAnalyticsParams include Analytics::UniqueVisitsHelper + include GracefulTimeoutHandling before_action :whitelist_query_limiting, only: [:show] before_action :authorize_read_cycle_analytics! diff --git a/app/controllers/projects/environments_controller.rb b/app/controllers/projects/environments_controller.rb index d5da24a76de..71195fdb892 100644 --- a/app/controllers/projects/environments_controller.rb +++ b/app/controllers/projects/environments_controller.rb @@ -13,6 +13,7 @@ class Projects::EnvironmentsController < Projects::ApplicationController authorize_metrics_dashboard! push_frontend_feature_flag(:prometheus_computed_alerts) + push_frontend_feature_flag(:disable_metric_dashboard_refresh_rate) end before_action :authorize_read_environment!, except: [:metrics, :additional_metrics, :metrics_dashboard, :metrics_redirect] before_action :authorize_create_environment!, only: [:new, :create] @@ -104,7 +105,7 @@ class Projects::EnvironmentsController < Projects::ApplicationController action_or_env_url = if stop_action - polymorphic_url([project.namespace.becomes(Namespace), project, stop_action]) + polymorphic_url([project, stop_action]) else project_environment_url(project, @environment) end @@ -158,18 +159,14 @@ class Projects::EnvironmentsController < Projects::ApplicationController end def metrics_redirect - environment = project.default_environment - - if environment - redirect_to environment_metrics_path(environment) - else - render :empty_metrics - end + redirect_to project_metrics_dashboard_path(project) end def metrics respond_to do |format| - format.html + format.html do + redirect_to project_metrics_dashboard_path(project, environment: environment ) + end format.json do # Currently, this acts as a hint to load the metrics details into the cache # if they aren't there already diff --git a/app/controllers/projects/forks_controller.rb b/app/controllers/projects/forks_controller.rb index b93f6384e0c..41631aea620 100644 --- a/app/controllers/projects/forks_controller.rb +++ b/app/controllers/projects/forks_controller.rb @@ -36,7 +36,19 @@ class Projects::ForksController < Projects::ApplicationController end def new - @namespaces = fork_service.valid_fork_targets - [project.namespace] + respond_to do |format| + format.html do + @own_namespace = current_user.namespace if fork_service.valid_fork_targets.include?(current_user.namespace) + @project = project + end + + format.json do + namespaces = fork_service.valid_fork_targets - [current_user.namespace, project.namespace] + render json: { + namespaces: ForkNamespaceSerializer.new.represent(namespaces, project: project, current_user: current_user) + } + end + end end # rubocop: disable CodeReuse/ActiveRecord diff --git a/app/controllers/projects/incidents_controller.rb b/app/controllers/projects/incidents_controller.rb new file mode 100644 index 00000000000..12cc4dde1f4 --- /dev/null +++ b/app/controllers/projects/incidents_controller.rb @@ -0,0 +1,8 @@ +# frozen_string_literal: true + +class Projects::IncidentsController < Projects::ApplicationController + before_action :authorize_read_incidents! + + def index + end +end diff --git a/app/controllers/projects/issues_controller.rb b/app/controllers/projects/issues_controller.rb index 12b5a538bc9..2200860a184 100644 --- a/app/controllers/projects/issues_controller.rb +++ b/app/controllers/projects/issues_controller.rb @@ -51,8 +51,10 @@ class Projects::IssuesController < Projects::ApplicationController end before_action only: :show do - push_frontend_feature_flag(:real_time_issue_sidebar, @project) - push_frontend_feature_flag(:confidential_apollo_sidebar, @project) + real_time_feature_flag = :real_time_issue_sidebar + real_time_enabled = Gitlab::ActionCable::Config.in_app? || Feature.enabled?(real_time_feature_flag, @project) + + gon.push({ features: { real_time_feature_flag.to_s.camelize(:lower) => real_time_enabled } }, true) end before_action only: :index do @@ -88,7 +90,7 @@ class Projects::IssuesController < Projects::ApplicationController params[:issue] ||= ActionController::Parameters.new( assignee_ids: "" ) - build_params = issue_params.merge( + build_params = issue_create_params.merge( merge_request_to_resolve_discussions_of: params[:merge_request_to_resolve_discussions_of], discussion_to_resolve: params[:discussion_to_resolve], confidential: !!Gitlab::Utils.to_boolean(params[:issue][:confidential]) @@ -108,7 +110,7 @@ class Projects::IssuesController < Projects::ApplicationController end def create - create_params = issue_params.merge(spammable_params).merge( + create_params = issue_create_params.merge(spammable_params).merge( merge_request_to_resolve_discussions_of: params[:merge_request_to_resolve_discussions_of], discussion_to_resolve: params[:discussion_to_resolve] ) @@ -291,6 +293,16 @@ class Projects::IssuesController < Projects::ApplicationController ] + [{ label_ids: [], assignee_ids: [], update_task: [:index, :checked, :line_number, :line_source] }] end + def issue_create_params + create_params = %i[ + issue_type + ] + + params.require(:issue).permit( + *create_params + ).merge(issue_params) + end + def reorder_params params.permit(:move_before_id, :move_after_id, :group_full_path) end diff --git a/app/controllers/projects/merge_requests/diffs_controller.rb b/app/controllers/projects/merge_requests/diffs_controller.rb index 98b0abc89e9..bceccc7063b 100644 --- a/app/controllers/projects/merge_requests/diffs_controller.rb +++ b/app/controllers/projects/merge_requests/diffs_controller.rb @@ -41,7 +41,7 @@ class Projects::MergeRequests::DiffsController < Projects::MergeRequests::Applic def diffs_metadata diffs = @compare.diffs(diff_options) - render json: DiffsMetadataSerializer.new(project: @merge_request.project) + render json: DiffsMetadataSerializer.new(project: @merge_request.project, current_user: current_user) .represent(diffs, additional_attributes) end diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb index 5d4514be838..e77d2f0f5ee 100644 --- a/app/controllers/projects/merge_requests_controller.rb +++ b/app/controllers/projects/merge_requests_controller.rb @@ -31,16 +31,19 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo push_frontend_feature_flag(:suggest_pipeline) if experiment_enabled?(:suggest_pipeline) push_frontend_feature_flag(:code_navigation, @project, default_enabled: true) push_frontend_feature_flag(:widget_visibility_polling, @project, default_enabled: true) - push_frontend_feature_flag(:merge_ref_head_comments, @project) + push_frontend_feature_flag(:merge_ref_head_comments, @project, default_enabled: true) push_frontend_feature_flag(:mr_commit_neighbor_nav, @project, default_enabled: true) - push_frontend_feature_flag(:multiline_comments, @project) + push_frontend_feature_flag(:multiline_comments, @project, default_enabled: true) push_frontend_feature_flag(:file_identifier_hash) push_frontend_feature_flag(:batch_suggestions, @project, default_enabled: true) + push_frontend_feature_flag(:auto_expand_collapsed_diffs, @project, default_enabled: true) + push_frontend_feature_flag(:approvals_commented_by, @project, default_enabled: true) + push_frontend_feature_flag(:hide_jump_to_next_unresolved_in_threads, default_enabled: true) + push_frontend_feature_flag(:merge_request_widget_graphql, @project) end before_action do push_frontend_feature_flag(:vue_issuable_sidebar, @project.group) - push_frontend_feature_flag(:junit_pipeline_view, @project.group) end around_action :allow_gitaly_ref_name_caching, only: [:index, :show, :discussions] @@ -80,7 +83,7 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo @note = @project.notes.new(noteable: @merge_request) @noteable = @merge_request - @commits_count = @merge_request.commits_count + @commits_count = @merge_request.commits_count + @merge_request.context_commits_count @issuable_sidebar = serializer.represent(@merge_request, serializer: 'sidebar') @current_user_data = UserSerializer.new(project: @project).represent(current_user, {}, MergeRequestUserEntity).to_json @show_whitespace_default = current_user.nil? || current_user.show_whitespace_in_diffs @@ -114,6 +117,12 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo end def commits + # Get context commits from repository + @context_commits = + set_commits_for_rendering( + @merge_request.recent_context_commits + ) + # Get commits from repository # or from cache if already merged @commits = @@ -403,7 +412,7 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo return access_denied! unless @merge_request.source_branch_exists? access_check = ::Gitlab::UserAccess - .new(current_user, project: @merge_request.source_project) + .new(current_user, container: @merge_request.source_project) .can_push_to_branch?(@merge_request.source_branch) access_denied! unless access_check diff --git a/app/controllers/projects/metrics/dashboards/builder_controller.rb b/app/controllers/projects/metrics/dashboards/builder_controller.rb new file mode 100644 index 00000000000..2ab574d7d10 --- /dev/null +++ b/app/controllers/projects/metrics/dashboards/builder_controller.rb @@ -0,0 +1,42 @@ +# frozen_string_literal: true + +module Projects + module Metrics + module Dashboards + class BuilderController < Projects::ApplicationController + before_action :authorize_metrics_dashboard! + + def panel_preview + respond_to do |format| + format.json do + if rendered_panel.success? + render json: rendered_panel.payload + else + render json: { message: rendered_panel.message }, status: :unprocessable_entity + end + end + end + end + + private + + def rendered_panel + @panel_preview ||= ::Metrics::Dashboard::PanelPreviewService.new(project, panel_yaml, environment).execute + end + + def panel_yaml + params.require(:panel_yaml) + end + + def environment + @environment ||= + if params[:environment] + project.environments.find(params[:environment]) + else + project.default_environment + end + end + end + end + end +end diff --git a/app/controllers/projects/metrics_dashboard_controller.rb b/app/controllers/projects/metrics_dashboard_controller.rb index 235ee1dfbf2..51307c3665c 100644 --- a/app/controllers/projects/metrics_dashboard_controller.rb +++ b/app/controllers/projects/metrics_dashboard_controller.rb @@ -9,13 +9,14 @@ module Projects before_action :authorize_metrics_dashboard! before_action do push_frontend_feature_flag(:prometheus_computed_alerts) + push_frontend_feature_flag(:disable_metric_dashboard_refresh_rate) end def show if environment render 'projects/environments/metrics' else - render_404 + render 'projects/environments/empty_metrics' end end diff --git a/app/controllers/projects/packages/package_files_controller.rb b/app/controllers/projects/packages/package_files_controller.rb new file mode 100644 index 00000000000..dd6d875cd1e --- /dev/null +++ b/app/controllers/projects/packages/package_files_controller.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +module Projects + module Packages + class PackageFilesController < ApplicationController + include PackagesAccess + include SendFileUpload + + def download + package_file = project.package_files.find(params[:id]) + + send_upload(package_file.file, attachment: package_file.file_name) + end + end + end +end diff --git a/app/controllers/projects/packages/packages_controller.rb b/app/controllers/projects/packages/packages_controller.rb new file mode 100644 index 00000000000..fc4ef7a01dc --- /dev/null +++ b/app/controllers/projects/packages/packages_controller.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true + +module Projects + module Packages + class PackagesController < Projects::ApplicationController + include PackagesAccess + + before_action :authorize_destroy_package!, only: [:destroy] + + def show + @package = project.packages.find(params[:id]) + @package_files = @package.package_files.recent + @maven_metadatum = @package.maven_metadatum + end + + def destroy + @package = project.packages.find(params[:id]) + @package.destroy + + redirect_to project_packages_path(@project), status: :found, notice: _('Package was removed') + end + end + end +end diff --git a/app/controllers/projects/pipelines/tests_controller.rb b/app/controllers/projects/pipelines/tests_controller.rb index f03274bf32e..1c212964df5 100644 --- a/app/controllers/projects/pipelines/tests_controller.rb +++ b/app/controllers/projects/pipelines/tests_controller.rb @@ -3,7 +3,6 @@ module Projects module Pipelines class TestsController < Projects::Pipelines::ApplicationController - before_action :validate_feature_flag! before_action :authorize_read_build! before_action :builds, only: [:show] @@ -29,29 +28,21 @@ module Projects private - def validate_feature_flag! - render_404 unless Feature.enabled?(:build_report_summary, project) - end - # rubocop: disable CodeReuse/ActiveRecord def builds - pipeline.latest_builds.where(id: build_params) + @builds ||= pipeline.latest_builds.for_ids(build_ids).presence || render_404 end - def build_params + def build_ids return [] unless params[:build_ids] params[:build_ids].split(",") end def test_suite - if builds.present? - builds.map do |build| - build.collect_test_reports!(Gitlab::Ci::Reports::TestReports.new) - end.sum - else - render_404 - end + builds.map do |build| + build.collect_test_reports!(Gitlab::Ci::Reports::TestReports.new) + end.sum end # rubocop: enable CodeReuse/ActiveRecord end diff --git a/app/controllers/projects/pipelines_controller.rb b/app/controllers/projects/pipelines_controller.rb index d8e11ddd423..bfe23eb1035 100644 --- a/app/controllers/projects/pipelines_controller.rb +++ b/app/controllers/projects/pipelines_controller.rb @@ -12,11 +12,10 @@ 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(:junit_pipeline_view, project) - push_frontend_feature_flag(:build_report_summary, project) push_frontend_feature_flag(:filter_pipelines_search, project, default_enabled: true) push_frontend_feature_flag(:dag_pipeline_tab, project, default_enabled: true) push_frontend_feature_flag(:pipelines_security_report_summary, project) + push_frontend_feature_flag(:new_pipeline_form) end before_action :ensure_pipeline, only: [:show] @@ -177,8 +176,6 @@ class Projects::PipelinesController < Projects::ApplicationController end def test_report - return unless Feature.enabled?(:junit_pipeline_view, project) - respond_to do |format| format.html do render 'show' @@ -192,12 +189,6 @@ class Projects::PipelinesController < Projects::ApplicationController end end - def test_reports_count - return unless Feature.enabled?(:junit_pipeline_view, project) - - render json: { total_count: pipeline.test_reports_count }.to_json - end - private def serialize_pipelines diff --git a/app/controllers/projects/product_analytics_controller.rb b/app/controllers/projects/product_analytics_controller.rb new file mode 100644 index 00000000000..badd7671dcf --- /dev/null +++ b/app/controllers/projects/product_analytics_controller.rb @@ -0,0 +1,53 @@ +# frozen_string_literal: true + +class Projects::ProductAnalyticsController < Projects::ApplicationController + before_action :feature_enabled! + before_action :authorize_read_product_analytics! + before_action :tracker_variables, only: [:setup, :test] + + def index + @events = product_analytics_events.order_by_time.page(params[:page]) + end + + def setup + end + + def test + @event = product_analytics_events.try(:first) + end + + def graphs + @graphs = [] + @timerange = 30 + + requested_graphs = %w(platform os_timezone br_lang doc_charset) + + requested_graphs.each do |graph| + @graphs << ProductAnalytics::BuildGraphService + .new(project, { graph: graph, timerange: @timerange }) + .execute + end + end + + private + + def product_analytics_events + @project.product_analytics_events + end + + def tracker_variables + # We use project id as Snowplow appId + @project_id = @project.id.to_s + + # Snowplow remembers values like appId and platform between reloads. + # That is why we have to rename the tracker with a random integer. + @random = rand(999999) + + # Generate random platform every time a tracker is rendered. + @platform = %w(web mob app)[(@random % 3)] + end + + def feature_enabled! + render_404 unless Feature.enabled?(:product_analytics, @project, default_enabled: false) + end +end diff --git a/app/controllers/projects/prometheus/alerts_controller.rb b/app/controllers/projects/prometheus/alerts_controller.rb index 2c0521edece..c6ae65f7832 100644 --- a/app/controllers/projects/prometheus/alerts_controller.rb +++ b/app/controllers/projects/prometheus/alerts_controller.rb @@ -39,7 +39,7 @@ module Projects render json: serialize_as_json(@alert) else - head :no_content + head :bad_request end end @@ -49,7 +49,7 @@ module Projects render json: serialize_as_json(alert) else - head :no_content + head :bad_request end end @@ -59,14 +59,14 @@ module Projects head :ok else - head :no_content + head :bad_request end end private def alerts_params - params.permit(:operator, :threshold, :environment_id, :prometheus_metric_id) + params.permit(:operator, :threshold, :environment_id, :prometheus_metric_id, :runbook_url) end def notify_service diff --git a/app/controllers/projects/protected_refs_controller.rb b/app/controllers/projects/protected_refs_controller.rb index d9921757502..060403a9cd9 100644 --- a/app/controllers/projects/protected_refs_controller.rb +++ b/app/controllers/projects/protected_refs_controller.rb @@ -62,7 +62,7 @@ class Projects::ProtectedRefsController < Projects::ApplicationController end def access_level_attributes - %i[access_level id] + %i[access_level id _destroy] end end diff --git a/app/controllers/projects/releases_controller.rb b/app/controllers/projects/releases_controller.rb index d58755c2655..c48d573edbf 100644 --- a/app/controllers/projects/releases_controller.rb +++ b/app/controllers/projects/releases_controller.rb @@ -29,7 +29,7 @@ class Projects::ReleasesController < Projects::ApplicationController end def new - unless Feature.enabled?(:new_release_page, project) + unless Feature.enabled?(:new_release_page, project, default_enabled: true) redirect_to(new_project_tag_path(@project)) end end diff --git a/app/controllers/projects/services_controller.rb b/app/controllers/projects/services_controller.rb index 6b7e253595c..ca2a19e67b0 100644 --- a/app/controllers/projects/services_controller.rb +++ b/app/controllers/projects/services_controller.rb @@ -12,7 +12,6 @@ class Projects::ServicesController < Projects::ApplicationController before_action :set_deprecation_notice_for_prometheus_service, only: [:edit, :update] before_action :redirect_deprecated_prometheus_service, only: [:update] before_action only: :edit do - push_frontend_feature_flag(:integration_form_refactor, default_enabled: true) push_frontend_feature_flag(:jira_issues_integration, @project, { default_enabled: true }) end diff --git a/app/controllers/projects/settings/operations_controller.rb b/app/controllers/projects/settings/operations_controller.rb index d7a6f1b0139..781b850ddfe 100644 --- a/app/controllers/projects/settings/operations_controller.rb +++ b/app/controllers/projects/settings/operations_controller.rb @@ -6,10 +6,6 @@ module Projects before_action :authorize_admin_operations! before_action :authorize_read_prometheus_alerts!, only: [:reset_alerting_token] - before_action do - push_frontend_feature_flag(:pagerduty_webhook, project) - end - respond_to :json, only: [:reset_alerting_token, :reset_pagerduty_token] helper_method :error_tracking_setting @@ -49,7 +45,7 @@ module Projects if result[:status] == :success pagerduty_token = project.incident_management_setting&.pagerduty_token - webhook_url = project_incidents_pagerduty_url(project, token: pagerduty_token) + webhook_url = project_incidents_integrations_pagerduty_url(project, token: pagerduty_token) render json: { pagerduty_webhook_url: webhook_url, pagerduty_token: pagerduty_token } else diff --git a/app/controllers/projects/snippets/blobs_controller.rb b/app/controllers/projects/snippets/blobs_controller.rb index 148fc7c96f8..eaec8600d77 100644 --- a/app/controllers/projects/snippets/blobs_controller.rb +++ b/app/controllers/projects/snippets/blobs_controller.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true class Projects::Snippets::BlobsController < Projects::Snippets::ApplicationController - include Snippets::BlobsActions + include ::Snippets::BlobsActions end diff --git a/app/controllers/projects/snippets_controller.rb b/app/controllers/projects/snippets_controller.rb index 49840e847f2..632e8db9796 100644 --- a/app/controllers/projects/snippets_controller.rb +++ b/app/controllers/projects/snippets_controller.rb @@ -14,6 +14,10 @@ class Projects::SnippetsController < Projects::Snippets::ApplicationController before_action :authorize_update_snippet!, only: [:edit, :update] before_action :authorize_admin_snippet!, only: [:destroy] + before_action do + push_frontend_feature_flag(:snippet_multiple_files, current_user) + end + def index @snippet_counts = ::Snippets::CountService .new(current_user, project: @project) diff --git a/app/controllers/projects/variables_controller.rb b/app/controllers/projects/variables_controller.rb index 2cc030d18fc..0fd047f90cf 100644 --- a/app/controllers/projects/variables_controller.rb +++ b/app/controllers/projects/variables_controller.rb @@ -12,7 +12,12 @@ class Projects::VariablesController < Projects::ApplicationController end def update - if @project.update(variables_params) + update_result = Ci::ChangeVariablesService.new( + container: @project, current_user: current_user, + params: variables_params + ).execute + + if update_result respond_to do |format| format.json { render_variables } end diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb index a5666cb70ac..ba21fbddde1 100644 --- a/app/controllers/projects_controller.rb +++ b/app/controllers/projects_controller.rb @@ -38,9 +38,16 @@ class ProjectsController < Projects::ApplicationController before_action only: [:new, :create] do frontend_experimentation_tracking_data(:new_create_project_ui, 'click_tab') push_frontend_feature_flag(:new_create_project_ui) if experiment_enabled?(:new_create_project_ui) + end + + before_action only: [:edit] do push_frontend_feature_flag(:service_desk_custom_address, @project) end + before_action only: [:edit] do + push_frontend_feature_flag(:approval_suggestions, @project) + end + layout :determine_layout def index @@ -392,6 +399,7 @@ class ProjectsController < Projects::ApplicationController :initialize_with_readme, :autoclose_referenced_issues, :suggestion_commit_message, + :packages_enabled, :service_desk_enabled, project_feature_attributes: %i[ diff --git a/app/controllers/registrations/experience_levels_controller.rb b/app/controllers/registrations/experience_levels_controller.rb index 97239b1bbac..5bb039bd9ba 100644 --- a/app/controllers/registrations/experience_levels_controller.rb +++ b/app/controllers/registrations/experience_levels_controller.rb @@ -2,9 +2,7 @@ module Registrations class ExperienceLevelsController < ApplicationController - # This will need to be changed to simply 'devise' as part of - # https://gitlab.com/gitlab-org/growth/engineering/issues/64 - layout 'devise_experimental_separate_sign_up_flow' + layout 'devise_experimental_onboarding_issues' before_action :check_experiment_enabled before_action :ensure_namespace_path_param diff --git a/app/controllers/registrations_controller.rb b/app/controllers/registrations_controller.rb index b1c1fe3ba74..2a865aac767 100644 --- a/app/controllers/registrations_controller.rb +++ b/app/controllers/registrations_controller.rb @@ -17,7 +17,8 @@ class RegistrationsController < Devise::RegistrationsController def new if experiment_enabled?(:signup_flow) - track_experiment_event(:signup_flow, 'start') # We want this event to be tracked when the user is _in_ the experimental group + track_experiment_event(:terms_opt_in, 'start') + @resource = build_resource else redirect_to new_user_session_path(anchor: 'register-pane') @@ -25,8 +26,7 @@ class RegistrationsController < Devise::RegistrationsController end def create - track_experiment_event(:signup_flow, 'end') unless experiment_enabled?(:signup_flow) # We want this event to be tracked when the user is _in_ the control group - + track_experiment_event(:terms_opt_in, 'end') accept_pending_invitations super do |new_user| @@ -62,9 +62,11 @@ class RegistrationsController < Devise::RegistrationsController result = ::Users::SignupService.new(current_user, user_params).execute if result[:status] == :success - track_experiment_event(:signup_flow, 'end') # We want this event to be tracked when the user is _in_ the experimental group + if ::Gitlab.com? && show_onboarding_issues_experiment? + track_experiment_event(:onboarding_issues, 'signed_up') + record_experiment_user(:onboarding_issues) + end - track_experiment_event(:onboarding_issues, 'signed_up') if ::Gitlab.com? && show_onboarding_issues_experiment? return redirect_to new_users_sign_up_group_path if experiment_enabled?(:onboarding_issues) && show_onboarding_issues_experiment? set_flash_message! :notice, :signed_up @@ -178,6 +180,8 @@ class RegistrationsController < Devise::RegistrationsController end def terms_accepted? + return true if experiment_enabled?(:terms_opt_in) + Gitlab::Utils.to_boolean(params[:terms_opt_in]) end diff --git a/app/controllers/repositories/git_http_controller.rb b/app/controllers/repositories/git_http_controller.rb index 6a27d63625e..aa6609bef2a 100644 --- a/app/controllers/repositories/git_http_controller.rb +++ b/app/controllers/repositories/git_http_controller.rb @@ -105,7 +105,7 @@ module Repositories access.check(git_command, Gitlab::GitAccess::ANY) if repo_type.project? && !container - @project = @container = access.project + @project = @container = access.container end end diff --git a/app/controllers/repositories/lfs_storage_controller.rb b/app/controllers/repositories/lfs_storage_controller.rb index ec5ca5bbeec..0436b740979 100644 --- a/app/controllers/repositories/lfs_storage_controller.rb +++ b/app/controllers/repositories/lfs_storage_controller.rb @@ -73,9 +73,8 @@ module Repositories # rubocop: enable CodeReuse/ActiveRecord def create_file!(oid, size) - uploaded_file = UploadedFile.from_params( - params, :file, LfsObjectUploader.workhorse_local_upload_path) - return unless uploaded_file + uploaded_file = params[:file] + return unless uploaded_file.is_a?(UploadedFile) LfsObject.create!(oid: oid, size: size, file: uploaded_file) end diff --git a/app/controllers/root_controller.rb b/app/controllers/root_controller.rb index 14469877e14..191134472c2 100644 --- a/app/controllers/root_controller.rb +++ b/app/controllers/root_controller.rb @@ -13,6 +13,7 @@ class RootController < Dashboard::ProjectsController before_action :redirect_unlogged_user, if: -> { current_user.nil? } before_action :redirect_logged_user, if: -> { current_user.present? } + before_action :customize_homepage, only: :index, if: -> { current_user.present? } # We only need to load the projects when the user is logged in but did not # configure a dashboard. In which case we render projects. We can do that straight # from the #index action. @@ -66,6 +67,10 @@ class RootController < Dashboard::ProjectsController root_urls.exclude?(home_page_url) end + + def customize_homepage + @customize_homepage = experiment_enabled?(:customize_homepage) + end end RootController.prepend_if_ee('EE::RootController') diff --git a/app/controllers/search_controller.rb b/app/controllers/search_controller.rb index ff6d9350a5c..56b6a5201e7 100644 --- a/app/controllers/search_controller.rb +++ b/app/controllers/search_controller.rb @@ -6,7 +6,8 @@ class SearchController < ApplicationController include RendersCommits SCOPE_PRELOAD_METHOD = { - projects: :with_web_entity_associations + projects: :with_web_entity_associations, + issues: :with_web_entity_associations }.freeze around_action :allow_gitaly_ref_name_caching @@ -113,4 +114,15 @@ class SearchController < ApplicationController Gitlab::UsageDataCounters::SearchCounter.count(:navbar_searches) end + + def append_info_to_payload(payload) + super + + # Merging to :metadata will ensure these are logged as top level keys + payload[:metadata] || {} + payload[:metadata]['meta.search.group_id'] = params[:group_id] + payload[:metadata]['meta.search.project_id'] = params[:project_id] + payload[:metadata]['meta.search.search'] = params[:search] + payload[:metadata]['meta.search.scope'] = params[:scope] + end end diff --git a/app/controllers/sessions_controller.rb b/app/controllers/sessions_controller.rb index 9e8075d4bcc..f82212591b6 100644 --- a/app/controllers/sessions_controller.rb +++ b/app/controllers/sessions_controller.rb @@ -25,7 +25,7 @@ class SessionsController < Devise::SessionsController before_action :store_unauthenticated_sessions, only: [:new] before_action :save_failed_login, if: :action_new_and_failed_login? before_action :load_recaptcha - before_action :frontend_tracking_data, only: [:new] + before_action :set_invite_params, only: [:new] after_action :log_failed_login, if: :action_new_and_failed_login? after_action :verify_known_sign_in, only: [:create] @@ -293,9 +293,8 @@ class SessionsController < Devise::SessionsController end end - def frontend_tracking_data - # We want tracking data pushed to the frontend when the user is _in_ the control group - frontend_experimentation_tracking_data(:signup_flow, 'start') unless experiment_enabled?(:signup_flow) + def set_invite_params + @invite_email = ActionController::Base.helpers.sanitize(params[:invite_email]) end end diff --git a/app/controllers/snippets_controller.rb b/app/controllers/snippets_controller.rb index e68b821459d..486c7f1d028 100644 --- a/app/controllers/snippets_controller.rb +++ b/app/controllers/snippets_controller.rb @@ -17,6 +17,10 @@ class SnippetsController < Snippets::ApplicationController layout 'snippets' + before_action do + push_frontend_feature_flag(:snippet_multiple_files, current_user) + end + def index if params[:username].present? @user = UserFinder.new(params[:username]).find_by_username! -- cgit v1.2.3