summaryrefslogtreecommitdiff
path: root/app/controllers
diff options
context:
space:
mode:
authorAlex Groleau <agroleau@gitlab.com>2019-08-27 12:41:39 -0400
committerAlex Groleau <agroleau@gitlab.com>2019-08-27 12:41:39 -0400
commitaa01f092829facd1044ad02f334422b7dbdc8b0e (patch)
treea754bf2497820432df7da0f2108bb7527a8dd7b8 /app/controllers
parenta1d9c9994a9a4d79b824c3fd9322688303ac8b03 (diff)
parent6b10779053ff4233c7a64c5ab57754fce63f6710 (diff)
downloadgitlab-ce-aa01f092829facd1044ad02f334422b7dbdc8b0e.tar.gz
Merge branch 'master' of gitlab_gitlab:gitlab-org/gitlab-cerunner-metrics-extractor
Diffstat (limited to 'app/controllers')
-rw-r--r--app/controllers/admin/application_settings_controller.rb13
-rw-r--r--app/controllers/admin/groups_controller.rb3
-rw-r--r--app/controllers/admin/requests_profiles_controller.rb12
-rw-r--r--app/controllers/admin/users_controller.rb6
-rw-r--r--app/controllers/application_controller.rb21
-rw-r--r--app/controllers/autocomplete_controller.rb4
-rw-r--r--app/controllers/boards/issues_controller.rb34
-rw-r--r--app/controllers/chaos_controller.rb89
-rw-r--r--app/controllers/concerns/authenticates_with_two_factor.rb4
-rw-r--r--app/controllers/concerns/confirm_email_warning.rb25
-rw-r--r--app/controllers/concerns/group_tree.rb20
-rw-r--r--app/controllers/concerns/invisible_captcha.rb51
-rw-r--r--app/controllers/concerns/issuable_actions.rb25
-rw-r--r--app/controllers/concerns/issuable_collections.rb61
-rw-r--r--app/controllers/concerns/issuable_collections_action.rb2
-rw-r--r--app/controllers/concerns/notes_actions.rb7
-rw-r--r--app/controllers/concerns/requires_whitelisted_monitoring_client.rb2
-rw-r--r--app/controllers/concerns/sessionless_authentication.rb2
-rw-r--r--app/controllers/concerns/sorting_preference.rb85
-rw-r--r--app/controllers/concerns/toggle_award_emoji.rb19
-rw-r--r--app/controllers/concerns/uploads_actions.rb2
-rw-r--r--app/controllers/concerns/with_performance_bar.rb4
-rw-r--r--app/controllers/confirmations_controller.rb2
-rw-r--r--app/controllers/dashboard/projects_controller.rb23
-rw-r--r--app/controllers/explore/projects_controller.rb19
-rw-r--r--app/controllers/graphql_controller.rb4
-rw-r--r--app/controllers/groups/group_members_controller.rb13
-rw-r--r--app/controllers/groups_controller.rb10
-rw-r--r--app/controllers/ide_controller.rb1
-rw-r--r--app/controllers/import/bitbucket_server_controller.rb8
-rw-r--r--app/controllers/import/github_controller.rb8
-rw-r--r--app/controllers/jwt_controller.rb1
-rw-r--r--app/controllers/omniauth_callbacks_controller.rb2
-rw-r--r--app/controllers/projects/artifacts_controller.rb5
-rw-r--r--app/controllers/projects/badges_controller.rb3
-rw-r--r--app/controllers/projects/blob_controller.rb6
-rw-r--r--app/controllers/projects/branches_controller.rb2
-rw-r--r--app/controllers/projects/build_artifacts_controller.rb2
-rw-r--r--app/controllers/projects/cycle_analytics/events_controller.rb10
-rw-r--r--app/controllers/projects/cycle_analytics_controller.rb12
-rw-r--r--app/controllers/projects/environments_controller.rb24
-rw-r--r--app/controllers/projects/git_http_client_controller.rb7
-rw-r--r--app/controllers/projects/issues_controller.rb6
-rw-r--r--app/controllers/projects/jobs_controller.rb6
-rw-r--r--app/controllers/projects/merge_requests/application_controller.rb2
-rw-r--r--app/controllers/projects/merge_requests/content_controller.rb23
-rw-r--r--app/controllers/projects/merge_requests/creations_controller.rb8
-rw-r--r--app/controllers/projects/merge_requests_controller.rb5
-rw-r--r--app/controllers/projects/notes_controller.rb4
-rw-r--r--app/controllers/projects/pipelines_controller.rb33
-rw-r--r--app/controllers/projects/raw_controller.rb20
-rw-r--r--app/controllers/projects/registry/tags_controller.rb34
-rw-r--r--app/controllers/projects/repositories_controller.rb60
-rw-r--r--app/controllers/projects/snippets_controller.rb3
-rw-r--r--app/controllers/projects/starrers_controller.rb20
-rw-r--r--app/controllers/projects/triggers_controller.rb12
-rw-r--r--app/controllers/projects/variables_controller.rb2
-rw-r--r--app/controllers/projects/wikis_controller.rb36
-rw-r--r--app/controllers/projects_controller.rb36
-rw-r--r--app/controllers/registrations_controller.rb16
-rw-r--r--app/controllers/search_controller.rb17
-rw-r--r--app/controllers/sessions_controller.rb18
-rw-r--r--app/controllers/snippets/notes_controller.rb4
-rw-r--r--app/controllers/snippets_controller.rb3
-rw-r--r--app/controllers/users_controller.rb41
65 files changed, 766 insertions, 296 deletions
diff --git a/app/controllers/admin/application_settings_controller.rb b/app/controllers/admin/application_settings_controller.rb
index a570da61d54..99411641874 100644
--- a/app/controllers/admin/application_settings_controller.rb
+++ b/app/controllers/admin/application_settings_controller.rb
@@ -103,8 +103,10 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController
[
*::ApplicationSettingsHelper.visible_attributes,
*::ApplicationSettingsHelper.external_authorization_service_attributes,
- *lets_encrypt_visible_attributes,
+ :lets_encrypt_notification_email,
+ :lets_encrypt_terms_of_service_accepted,
:domain_blacklist_file,
+ :raw_blob_request_limit,
disabled_oauth_sign_in_sources: [],
import_sources: [],
repository_storages: [],
@@ -143,13 +145,4 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController
render action
end
-
- def lets_encrypt_visible_attributes
- return [] unless Feature.enabled?(:pages_auto_ssl)
-
- [
- :lets_encrypt_notification_email,
- :lets_encrypt_terms_of_service_accepted
- ]
- end
end
diff --git a/app/controllers/admin/groups_controller.rb b/app/controllers/admin/groups_controller.rb
index 15f7ef881c8..6317fa7c8d1 100644
--- a/app/controllers/admin/groups_controller.rb
+++ b/app/controllers/admin/groups_controller.rb
@@ -90,7 +90,8 @@ class Admin::GroupsController < Admin::ApplicationController
:visibility_level,
:require_two_factor_authentication,
:two_factor_grace_period,
- :project_creation_level
+ :project_creation_level,
+ :subgroup_creation_level
]
end
end
diff --git a/app/controllers/admin/requests_profiles_controller.rb b/app/controllers/admin/requests_profiles_controller.rb
index 89d4c4f18d9..24383455064 100644
--- a/app/controllers/admin/requests_profiles_controller.rb
+++ b/app/controllers/admin/requests_profiles_controller.rb
@@ -3,17 +3,17 @@
class Admin::RequestsProfilesController < Admin::ApplicationController
def index
@profile_token = Gitlab::RequestProfiler.profile_token
- @profiles = Gitlab::RequestProfiler::Profile.all.group_by(&:request_path)
+ @profiles = Gitlab::RequestProfiler.all.group_by(&:request_path)
end
def show
clean_name = Rack::Utils.clean_path_info(params[:name])
- profile = Gitlab::RequestProfiler::Profile.find(clean_name)
+ profile = Gitlab::RequestProfiler.find(clean_name)
- if profile
- render html: profile.content.html_safe
- else
- redirect_to admin_requests_profiles_path, alert: 'Profile not found'
+ unless profile && profile.content_type
+ return redirect_to admin_requests_profiles_path, alert: 'Profile not found'
end
+
+ send_file profile.file_path, type: "#{profile.content_type}; charset=utf-8", disposition: 'inline'
end
end
diff --git a/app/controllers/admin/users_controller.rb b/app/controllers/admin/users_controller.rb
index a02d0843615..98883af6286 100644
--- a/app/controllers/admin/users_controller.rb
+++ b/app/controllers/admin/users_controller.rb
@@ -39,7 +39,7 @@ class Admin::UsersController < Admin::ApplicationController
warden.set_user(user, scope: :user)
- Gitlab::AppLogger.info(_("User %{current_user_username} has started impersonating %{username}") % { current_user_username: current_user.username, username: user.username })
+ log_impersonation_event
flash[:alert] = _("You are now impersonating %{username}") % { username: user.username }
@@ -236,4 +236,8 @@ class Admin::UsersController < Admin::ApplicationController
def check_impersonation_availability
access_denied! unless Gitlab.config.gitlab.impersonation_enabled
end
+
+ def log_impersonation_event
+ Gitlab::AppLogger.info(_("User %{current_user_username} has started impersonating %{username}") % { current_user_username: current_user.username, username: user.username })
+ end
end
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index 75108bf2646..af6644b8fcc 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -12,6 +12,7 @@ class ApplicationController < ActionController::Base
include EnforcesTwoFactorAuthentication
include WithPerformanceBar
include SessionlessAuthentication
+ include ConfirmEmailWarning
before_action :authenticate_user!
before_action :enforce_terms!, if: :should_enforce_terms?
@@ -116,7 +117,7 @@ class ApplicationController < ActionController::Base
def render(*args)
super.tap do
# Set a header for custom error pages to prevent them from being intercepted by gitlab-workhorse
- if response.content_type == 'text/html' && (400..599).cover?(response.status)
+ if (400..599).cover?(response.status) && workhorse_excluded_content_types.include?(response.content_type)
response.headers['X-GitLab-Custom-Error'] = '1'
end
end
@@ -124,6 +125,10 @@ class ApplicationController < ActionController::Base
protected
+ def workhorse_excluded_content_types
+ @workhorse_excluded_content_types ||= %w(text/html application/json)
+ end
+
def append_info_to_payload(payload)
super
@@ -421,7 +426,7 @@ class ApplicationController < ActionController::Base
end
def manifest_import_enabled?
- Group.supports_nested_objects? && Gitlab::CurrentSettings.import_sources.include?('manifest')
+ Gitlab::CurrentSettings.import_sources.include?('manifest')
end
def phabricator_import_enabled?
@@ -499,9 +504,7 @@ class ApplicationController < ActionController::Base
end
def stop_impersonation
- impersonated_user = current_user
-
- Gitlab::AppLogger.info("User #{impersonator.username} has stopped impersonating #{impersonated_user.username}")
+ log_impersonation_event
warden.set_user(impersonator, scope: :user)
session[:impersonator_id] = nil
@@ -509,6 +512,14 @@ class ApplicationController < ActionController::Base
impersonated_user
end
+ def impersonated_user
+ current_user
+ end
+
+ def log_impersonation_event
+ Gitlab::AppLogger.info("User #{impersonator.username} has stopped impersonating #{impersonated_user.username}")
+ end
+
def impersonator
@impersonator ||= User.find(session[:impersonator_id]) if session[:impersonator_id]
end
diff --git a/app/controllers/autocomplete_controller.rb b/app/controllers/autocomplete_controller.rb
index 091327931c2..30a567c3bef 100644
--- a/app/controllers/autocomplete_controller.rb
+++ b/app/controllers/autocomplete_controller.rb
@@ -16,7 +16,7 @@ class AutocompleteController < ApplicationController
.new(params: params, current_user: current_user, project: project, group: group)
.execute
- render json: UserSerializer.new.represent(users)
+ render json: UserSerializer.new(params).represent(users, project: project)
end
def user
@@ -36,7 +36,7 @@ class AutocompleteController < ApplicationController
end
def award_emojis
- render json: AwardedEmojiFinder.new(current_user).execute
+ render json: AwardEmojis::CollectUserEmojiService.new(current_user).execute
end
def merge_request_target_branches
diff --git a/app/controllers/boards/issues_controller.rb b/app/controllers/boards/issues_controller.rb
index 0dd7500623d..1d1a72d21f1 100644
--- a/app/controllers/boards/issues_controller.rb
+++ b/app/controllers/boards/issues_controller.rb
@@ -2,23 +2,31 @@
module Boards
class IssuesController < Boards::ApplicationController
+ # This is the maximum amount of issues which can be moved by one request to
+ # bulk_move for now. This is temporary and might be removed in future by
+ # introducing an alternative (async?) approach.
+ # (related: https://gitlab.com/groups/gitlab-org/-/epics/382)
+ MAX_MOVE_ISSUES_COUNT = 50
+
include BoardsResponses
include ControllerWithCrossProjectAccessCheck
requires_cross_project_access if: -> { board&.group_board? }
- before_action :whitelist_query_limiting, only: [:index, :update]
+ before_action :whitelist_query_limiting, only: [:index, :update, :bulk_move]
before_action :authorize_read_issue, only: [:index]
before_action :authorize_create_issue, only: [:create]
before_action :authorize_update_issue, only: [:update]
skip_before_action :authenticate_user!, only: [:index]
+ before_action :validate_id_list, only: [:bulk_move]
+ before_action :can_move_issues?, only: [:bulk_move]
# rubocop: disable CodeReuse/ActiveRecord
def index
list_service = Boards::Issues::ListService.new(board_parent, current_user, filter_params)
issues = list_service.execute
issues = issues.page(params[:page]).per(params[:per] || 20).without_count
- Issue.move_to_end(issues) if Gitlab::Database.read_write?
+ Issue.move_nulls_to_end(issues) if Gitlab::Database.read_write?
issues = issues.preload(:milestone,
:assignees,
project: [
@@ -46,6 +54,14 @@ module Boards
end
end
+ def bulk_move
+ service = Boards::Issues::MoveService.new(board_parent, current_user, move_params(true))
+
+ issues = Issue.find(params[:ids])
+
+ render json: service.execute_multiple(issues)
+ end
+
def update
service = Boards::Issues::MoveService.new(board_parent, current_user, move_params)
@@ -58,6 +74,10 @@ module Boards
private
+ def can_move_issues?
+ head(:forbidden) unless can?(current_user, :admin_issue, board)
+ end
+
def render_issues(issues, metadata)
data = { issues: serialize_as_json(issues) }
data.merge!(metadata)
@@ -90,8 +110,9 @@ module Boards
end
end
- def move_params
- params.permit(:board_id, :id, :from_list_id, :to_list_id, :move_before_id, :move_after_id)
+ def move_params(multiple = false)
+ id_param = multiple ? :ids : :id
+ params.permit(id_param, :board_id, :from_list_id, :to_list_id, :move_before_id, :move_after_id)
end
def issue_params
@@ -112,5 +133,10 @@ module Boards
# Also see https://gitlab.com/gitlab-org/gitlab-ce/issues/42439
Gitlab::QueryLimiting.whitelist('https://gitlab.com/gitlab-org/gitlab-ce/issues/42428')
end
+
+ def validate_id_list
+ head(:bad_request) unless params[:ids].is_a?(Array)
+ head(:unprocessable_entity) if params[:ids].size > MAX_MOVE_ISSUES_COUNT
+ end
end
end
diff --git a/app/controllers/chaos_controller.rb b/app/controllers/chaos_controller.rb
index 8d518c14b90..ac008165c16 100644
--- a/app/controllers/chaos_controller.rb
+++ b/app/controllers/chaos_controller.rb
@@ -1,56 +1,83 @@
# frozen_string_literal: true
class ChaosController < ActionController::Base
- before_action :validate_request
+ before_action :validate_chaos_secret, unless: :development_or_test?
def leakmem
- memory_mb = (params[:memory_mb]&.to_i || 100)
- duration_s = (params[:duration_s]&.to_i || 30).seconds
+ do_chaos :leak_mem, Chaos::LeakMemWorker, memory_mb, duration_s
+ end
- start = Time.now
- retainer = []
- # Add `n` 1mb chunks of memory to the retainer array
- memory_mb.times { retainer << "x" * 1.megabyte }
+ def cpu_spin
+ do_chaos :cpu_spin, Chaos::CpuSpinWorker, duration_s
+ end
- duration_taken = (Time.now - start).seconds
- Kernel.sleep duration_s - duration_taken if duration_s > duration_taken
+ def db_spin
+ do_chaos :db_spin, Chaos::DbSpinWorker, duration_s, interval_s
+ end
- render plain: "OK"
+ def sleep
+ do_chaos :sleep, Chaos::SleepWorker, duration_s
end
- def cpuspin
- duration_s = (params[:duration_s]&.to_i || 30).seconds
- end_time = Time.now + duration_s.seconds
+ def kill
+ do_chaos :kill, Chaos::KillWorker
+ end
- rand while Time.now < end_time
+ private
+
+ def do_chaos(method, worker, *args)
+ if async
+ worker.perform_async(*args)
+ else
+ Gitlab::Chaos.public_send(method, *args) # rubocop: disable GitlabSecurity/PublicSend
+ end
render plain: "OK"
end
- def sleep
- duration_s = (params[:duration_s]&.to_i || 30).seconds
- Kernel.sleep duration_s
+ def validate_chaos_secret
+ unless chaos_secret_configured
+ render plain: "chaos misconfigured: please configure GITLAB_CHAOS_SECRET",
+ status: :internal_server_error
+ return
+ end
- render plain: "OK"
+ unless Devise.secure_compare(chaos_secret_configured, chaos_secret_request)
+ render plain: "To experience chaos, please set a valid `X-Chaos-Secret` header or `token` param",
+ status: :unauthorized
+ return
+ end
end
- def kill
- Process.kill("KILL", Process.pid)
+ def chaos_secret_configured
+ ENV['GITLAB_CHAOS_SECRET']
end
- private
+ def chaos_secret_request
+ request.headers["HTTP_X_CHAOS_SECRET"] || params[:token]
+ end
- def validate_request
- secret = ENV['GITLAB_CHAOS_SECRET']
- # GITLAB_CHAOS_SECRET is required unless you're running in Development mode
- if !secret && !Rails.env.development?
- render plain: "chaos misconfigured: please configure GITLAB_CHAOS_SECRET when using GITLAB_ENABLE_CHAOS_ENDPOINTS outside of a development environment", status: :internal_server_error
- end
+ def interval_s
+ interval_s = params[:interval_s] || 1
+ interval_s.to_f.seconds
+ end
- return unless secret
+ def duration_s
+ duration_s = params[:duration_s] || 30
+ duration_s.to_i.seconds
+ end
- unless request.headers["HTTP_X_CHAOS_SECRET"] == secret
- render plain: "To experience chaos, please set X-Chaos-Secret header", status: :unauthorized
- end
+ def memory_mb
+ memory_mb = params[:memory_mb] || 100
+ memory_mb.to_i
+ end
+
+ def async
+ async = params[:async] || false
+ Gitlab::Utils.to_boolean(async)
+ end
+
+ def development_or_test?
+ Rails.env.development? || Rails.env.test?
end
end
diff --git a/app/controllers/concerns/authenticates_with_two_factor.rb b/app/controllers/concerns/authenticates_with_two_factor.rb
index 4926062f9ca..8c8f0b3a22e 100644
--- a/app/controllers/concerns/authenticates_with_two_factor.rb
+++ b/app/controllers/concerns/authenticates_with_two_factor.rb
@@ -55,7 +55,7 @@ module AuthenticatesWithTwoFactor
remember_me(user) if user_params[:remember_me] == '1'
user.save!
- sign_in(user, message: :two_factor_authenticated)
+ sign_in(user, message: :two_factor_authenticated, event: :authentication)
else
user.increment_failed_attempts!
Gitlab::AppLogger.info("Failed Login: user=#{user.username} ip=#{request.remote_ip} method=OTP")
@@ -72,7 +72,7 @@ module AuthenticatesWithTwoFactor
session.delete(:challenge)
remember_me(user) if user_params[:remember_me] == '1'
- sign_in(user, message: :two_factor_authenticated)
+ sign_in(user, message: :two_factor_authenticated, event: :authentication)
else
user.increment_failed_attempts!
Gitlab::AppLogger.info("Failed Login: user=#{user.username} ip=#{request.remote_ip} method=U2F")
diff --git a/app/controllers/concerns/confirm_email_warning.rb b/app/controllers/concerns/confirm_email_warning.rb
new file mode 100644
index 00000000000..5a4b5897a4f
--- /dev/null
+++ b/app/controllers/concerns/confirm_email_warning.rb
@@ -0,0 +1,25 @@
+# frozen_string_literal: true
+
+module ConfirmEmailWarning
+ extend ActiveSupport::Concern
+
+ included do
+ before_action :set_confirm_warning, if: -> { Feature.enabled?(:soft_email_confirmation) }
+ end
+
+ protected
+
+ 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
+
+ flash.now[:warning] = _("Please check your email (%{email}) to verify that you own this address. Didn't receive it? %{resend_link}. Wrong email address? %{update_link}.").html_safe % {
+ email: email,
+ resend_link: view_context.link_to(_('Resend it'), user_confirmation_path(user: { email: email }), method: :post),
+ update_link: view_context.link_to(_('Update it'), profile_path)
+ }
+ end
+end
diff --git a/app/controllers/concerns/group_tree.rb b/app/controllers/concerns/group_tree.rb
index e9a7d6a3152..d076c62c707 100644
--- a/app/controllers/concerns/group_tree.rb
+++ b/app/controllers/concerns/group_tree.rb
@@ -32,18 +32,14 @@ module GroupTree
def filtered_groups_with_ancestors(groups)
filtered_groups = groups.search(params[:filter]).page(params[:page])
- if Group.supports_nested_objects?
- # We find the ancestors by ID of the search results here.
- # Otherwise the ancestors would also have filters applied,
- # which would cause them not to be preloaded.
- #
- # Pagination needs to be applied before loading the ancestors to
- # make sure ancestors are not cut off by pagination.
- Gitlab::ObjectHierarchy.new(Group.where(id: filtered_groups.select(:id)))
- .base_and_ancestors
- else
- filtered_groups
- end
+ # We find the ancestors by ID of the search results here.
+ # Otherwise the ancestors would also have filters applied,
+ # which would cause them not to be preloaded.
+ #
+ # Pagination needs to be applied before loading the ancestors to
+ # make sure ancestors are not cut off by pagination.
+ Gitlab::ObjectHierarchy.new(Group.where(id: filtered_groups.select(:id)))
+ .base_and_ancestors
end
# rubocop: enable CodeReuse/ActiveRecord
end
diff --git a/app/controllers/concerns/invisible_captcha.rb b/app/controllers/concerns/invisible_captcha.rb
new file mode 100644
index 00000000000..45c0a5c58ef
--- /dev/null
+++ b/app/controllers/concerns/invisible_captcha.rb
@@ -0,0 +1,51 @@
+# frozen_string_literal: true
+
+module InvisibleCaptcha
+ extend ActiveSupport::Concern
+
+ included do
+ invisible_captcha only: :create, on_spam: :on_honeypot_spam_callback, on_timestamp_spam: :on_timestamp_spam_callback
+ end
+
+ def on_honeypot_spam_callback
+ return unless Feature.enabled?(:invisible_captcha)
+
+ invisible_captcha_honeypot_counter.increment
+ log_request('Invisible_Captcha_Honeypot_Request')
+
+ head(200)
+ end
+
+ def on_timestamp_spam_callback
+ return unless Feature.enabled?(:invisible_captcha)
+
+ invisible_captcha_timestamp_counter.increment
+ log_request('Invisible_Captcha_Timestamp_Request')
+
+ redirect_to new_user_session_path, alert: InvisibleCaptcha.timestamp_error_message
+ end
+
+ def invisible_captcha_honeypot_counter
+ @invisible_captcha_honeypot_counter ||=
+ Gitlab::Metrics.counter(:bot_blocked_by_invisible_captcha_honeypot,
+ 'Counter of blocked sign up attempts with filled honeypot')
+ end
+
+ def invisible_captcha_timestamp_counter
+ @invisible_captcha_timestamp_counter ||=
+ Gitlab::Metrics.counter(:bot_blocked_by_invisible_captcha_timestamp,
+ 'Counter of blocked sign up attempts with invalid timestamp')
+ end
+
+ def log_request(message)
+ request_information = {
+ message: message,
+ env: :invisible_captcha_signup_bot_detected,
+ remote_ip: request.ip,
+ request_method: request.request_method,
+ path: request.fullpath
+ }
+
+ Gitlab::AuthLogger.error(request_information)
+ end
+end
diff --git a/app/controllers/concerns/issuable_actions.rb b/app/controllers/concerns/issuable_actions.rb
index 6fa2f75be33..b86e4451a7e 100644
--- a/app/controllers/concerns/issuable_actions.rb
+++ b/app/controllers/concerns/issuable_actions.rb
@@ -98,13 +98,12 @@ module IssuableActions
render json: { notice: "#{quantity} #{resource_name.pluralize(quantity)} updated" }
end
- # rubocop: disable CodeReuse/ActiveRecord
+ # rubocop:disable CodeReuse/ActiveRecord
def discussions
- notes = issuable.discussion_notes
- .inc_relations_for_view
- .with_notes_filter(notes_filter)
- .includes(:noteable)
- .fresh
+ notes = NotesFinder.new(current_user, finder_params_for_issuable).execute
+ .inc_relations_for_view
+ .includes(:noteable)
+ .fresh
if notes_filter != UserPreference::NOTES_FILTERS[:only_comments]
notes = ResourceEvents::MergeIntoNotesService.new(issuable, current_user).execute(notes)
@@ -117,7 +116,7 @@ module IssuableActions
render json: discussion_serializer.represent(discussions, context: self)
end
- # rubocop: enable CodeReuse/ActiveRecord
+ # rubocop:enable CodeReuse/ActiveRecord
private
@@ -128,7 +127,8 @@ module IssuableActions
# GitLab Geo does not expect database UPDATE or INSERT statements to happen
# on GET requests.
# This is just a fail-safe in case notes_filter is sent via GET request in GitLab Geo.
- if Gitlab::Database.read_only?
+ # In some cases, we also force the filter to not be persisted with the `persist_filter` param
+ if Gitlab::Database.read_only? || params[:persist_filter] == 'false'
notes_filter_param || current_user&.notes_filter_for(issuable)
else
notes_filter = current_user&.set_notes_filter(notes_filter_param, issuable) || notes_filter_param
@@ -222,4 +222,13 @@ module IssuableActions
def parent
@project || @group # rubocop:disable Gitlab/ModuleWithInstanceVariables
end
+
+ # rubocop:disable Gitlab/ModuleWithInstanceVariables
+ def finder_params_for_issuable
+ {
+ target: @issuable,
+ notes_filter: notes_filter
+ }.tap { |new_params| new_params[:project] = project if respond_to?(:project, true) }
+ end
+ # rubocop:enable Gitlab/ModuleWithInstanceVariables
end
diff --git a/app/controllers/concerns/issuable_collections.rb b/app/controllers/concerns/issuable_collections.rb
index 21b3949e361..8ea77b994de 100644
--- a/app/controllers/concerns/issuable_collections.rb
+++ b/app/controllers/concerns/issuable_collections.rb
@@ -2,8 +2,8 @@
module IssuableCollections
extend ActiveSupport::Concern
- include CookiesHelper
include SortingHelper
+ include SortingPreference
include Gitlab::IssuableMetadata
include Gitlab::Utils::StrongMemoize
@@ -127,47 +127,8 @@ module IssuableCollections
'opened'
end
- def set_sort_order
- set_sort_order_from_user_preference || set_sort_order_from_cookie || default_sort_order
- end
-
- def set_sort_order_from_user_preference
- return unless current_user
- return unless issuable_sorting_field
-
- user_preference = current_user.user_preference
-
- sort_param = params[:sort]
- sort_param ||= user_preference[issuable_sorting_field]
-
- return sort_param if Gitlab::Database.read_only?
-
- if user_preference[issuable_sorting_field] != sort_param
- user_preference.update(issuable_sorting_field => sort_param)
- end
-
- sort_param
- end
-
- # Implement issuable_sorting_field method on controllers
- # to choose which column to store the sorting parameter.
- def issuable_sorting_field
- nil
- end
-
- def set_sort_order_from_cookie
- sort_param = params[:sort] if params[:sort].present?
- # fallback to legacy cookie value for backward compatibility
- sort_param ||= cookies['issuable_sort']
- sort_param ||= cookies[remember_sorting_key]
-
- sort_value = update_cookie_value(sort_param)
- set_secure_cookie(remember_sorting_key, sort_value)
- sort_value
- end
-
- def remember_sorting_key
- @remember_sorting_key ||= "#{collection_type.downcase}_sort"
+ def legacy_sort_cookie_name
+ 'issuable_sort'
end
def default_sort_order
@@ -178,26 +139,14 @@ module IssuableCollections
end
end
- # Update old values to the actual ones.
- def update_cookie_value(value)
- case value
- when 'id_asc' then sort_value_oldest_created
- when 'id_desc' then sort_value_recently_created
- when 'downvotes_asc' then sort_value_popularity
- when 'downvotes_desc' then sort_value_popularity
- else value
- end
- end
-
def finder
@finder ||= issuable_finder_for(finder_type)
end
def collection_type
- @collection_type ||= case finder_type.name
- when 'IssuesFinder'
+ @collection_type ||= if finder_type <= IssuesFinder
'Issue'
- when 'MergeRequestsFinder'
+ elsif finder_type <= MergeRequestsFinder
'MergeRequest'
end
end
diff --git a/app/controllers/concerns/issuable_collections_action.rb b/app/controllers/concerns/issuable_collections_action.rb
index 4ad287c4a13..0a6f684a9fc 100644
--- a/app/controllers/concerns/issuable_collections_action.rb
+++ b/app/controllers/concerns/issuable_collections_action.rb
@@ -32,7 +32,7 @@ module IssuableCollectionsAction
private
- def issuable_sorting_field
+ def sorting_field
case action_name
when 'issues'
Issue::SORTING_PREFERENCE_FIELD
diff --git a/app/controllers/concerns/notes_actions.rb b/app/controllers/concerns/notes_actions.rb
index 0098c4cdf4c..4b7899d469b 100644
--- a/app/controllers/concerns/notes_actions.rb
+++ b/app/controllers/concerns/notes_actions.rb
@@ -73,6 +73,11 @@ module NotesActions
# rubocop:disable Gitlab/ModuleWithInstanceVariables
def update
@note = Notes::UpdateService.new(project, current_user, update_note_params).execute(note)
+ unless @note
+ head :gone
+ return
+ end
+
prepare_notes_for_rendering([@note])
respond_to do |format|
@@ -243,7 +248,7 @@ module NotesActions
end
def notes_finder
- @notes_finder ||= NotesFinder.new(project, current_user, finder_params)
+ @notes_finder ||= NotesFinder.new(current_user, finder_params)
end
def note_serializer
diff --git a/app/controllers/concerns/requires_whitelisted_monitoring_client.rb b/app/controllers/concerns/requires_whitelisted_monitoring_client.rb
index f47ead2f0da..2e9905997db 100644
--- a/app/controllers/concerns/requires_whitelisted_monitoring_client.rb
+++ b/app/controllers/concerns/requires_whitelisted_monitoring_client.rb
@@ -28,7 +28,7 @@ module RequiresWhitelistedMonitoringClient
def valid_token?
token = params[:token].presence || request.headers['TOKEN']
token.present? &&
- ActiveSupport::SecurityUtils.variable_size_secure_compare(
+ ActiveSupport::SecurityUtils.secure_compare(
token,
Gitlab::CurrentSettings.health_check_access_token
)
diff --git a/app/controllers/concerns/sessionless_authentication.rb b/app/controllers/concerns/sessionless_authentication.rb
index 590eefc6dab..4304b8565ce 100644
--- a/app/controllers/concerns/sessionless_authentication.rb
+++ b/app/controllers/concerns/sessionless_authentication.rb
@@ -13,7 +13,7 @@ module SessionlessAuthentication
end
def sessionless_user?
- current_user && !session.keys.include?('warden.user.user.key')
+ current_user && !session.key?('warden.user.user.key')
end
def sessionless_sign_in(user)
diff --git a/app/controllers/concerns/sorting_preference.rb b/app/controllers/concerns/sorting_preference.rb
new file mode 100644
index 00000000000..a51b68147d5
--- /dev/null
+++ b/app/controllers/concerns/sorting_preference.rb
@@ -0,0 +1,85 @@
+# frozen_string_literal: true
+
+module SortingPreference
+ include SortingHelper
+ include CookiesHelper
+
+ def set_sort_order
+ set_sort_order_from_user_preference || set_sort_order_from_cookie || params[:sort] || default_sort_order
+ end
+
+ # Implement sorting_field method on controllers
+ # to choose which column to store the sorting parameter.
+ def sorting_field
+ nil
+ end
+
+ # Implement default_sort_order method on controllers
+ # to choose which default sort should be applied if
+ # sort param is not provided.
+ def default_sort_order
+ nil
+ end
+
+ # Implement legacy_sort_cookie_name method on controllers
+ # to set sort from cookie for backwards compatibility.
+ def legacy_sort_cookie_name
+ nil
+ end
+
+ private
+
+ def set_sort_order_from_user_preference
+ return unless current_user
+ return unless sorting_field
+
+ user_preference = current_user.user_preference
+
+ sort_param = params[:sort]
+ sort_param ||= user_preference[sorting_field]
+
+ return sort_param if Gitlab::Database.read_only?
+
+ if user_preference[sorting_field] != sort_param
+ user_preference.update(sorting_field => sort_param)
+ end
+
+ sort_param
+ end
+
+ def set_sort_order_from_cookie
+ return unless legacy_sort_cookie_name
+
+ sort_param = params[:sort] if params[:sort].present?
+ # fallback to legacy cookie value for backward compatibility
+ sort_param ||= cookies[legacy_sort_cookie_name]
+ sort_param ||= cookies[remember_sorting_key]
+
+ sort_value = update_cookie_value(sort_param)
+ set_secure_cookie(remember_sorting_key, sort_value)
+ sort_value
+ end
+
+ # Convert sorting_field to legacy cookie name for backwards compatibility
+ # :merge_requests_sort => 'mergerequest_sort'
+ # :issues_sort => 'issue_sort'
+ def remember_sorting_key
+ @remember_sorting_key ||= sorting_field
+ .to_s
+ .split('_')[0..-2]
+ .map(&:singularize)
+ .join('')
+ .concat('_sort')
+ end
+
+ # Update old values to the actual ones.
+ def update_cookie_value(value)
+ case value
+ when 'id_asc' then sort_value_oldest_created
+ when 'id_desc' then sort_value_recently_created
+ when 'downvotes_asc' then sort_value_popularity
+ when 'downvotes_desc' then sort_value_popularity
+ else value
+ end
+ end
+end
diff --git a/app/controllers/concerns/toggle_award_emoji.rb b/app/controllers/concerns/toggle_award_emoji.rb
index 97b343f8b1a..24d178781d6 100644
--- a/app/controllers/concerns/toggle_award_emoji.rb
+++ b/app/controllers/concerns/toggle_award_emoji.rb
@@ -7,12 +7,9 @@ module ToggleAwardEmoji
authenticate_user!
name = params.require(:name)
- if awardable.user_can_award?(current_user)
- awardable.toggle_award_emoji(name, current_user)
-
- todoable = to_todoable(awardable)
- TodoService.new.new_award_emoji(todoable, current_user) if todoable
+ service = AwardEmojis::ToggleService.new(awardable, name, current_user).execute
+ if service[:status] == :success
render json: { ok: true }
else
render json: { ok: false }
@@ -21,18 +18,6 @@ module ToggleAwardEmoji
private
- def to_todoable(awardable)
- case awardable
- when Note
- # we don't create todos for personal snippet comments for now
- awardable.for_personal_snippet? ? nil : awardable.noteable
- when MergeRequest, Issue
- awardable
- when Snippet
- nil
- end
- end
-
def awardable
raise NotImplementedError
end
diff --git a/app/controllers/concerns/uploads_actions.rb b/app/controllers/concerns/uploads_actions.rb
index 59f6d3452a3..f5d35379e10 100644
--- a/app/controllers/concerns/uploads_actions.rb
+++ b/app/controllers/concerns/uploads_actions.rb
@@ -90,7 +90,7 @@ module UploadsActions
return unless uploader = build_uploader
upload_paths = uploader.upload_paths(params[:filename])
- upload = Upload.find_by(uploader: uploader_class.to_s, path: upload_paths)
+ upload = Upload.find_by(model: model, uploader: uploader_class.to_s, path: upload_paths)
upload&.build_uploader
end
# rubocop: enable CodeReuse/ActiveRecord
diff --git a/app/controllers/concerns/with_performance_bar.rb b/app/controllers/concerns/with_performance_bar.rb
index 77c3d476ac6..4e0ae3c59eb 100644
--- a/app/controllers/concerns/with_performance_bar.rb
+++ b/app/controllers/concerns/with_performance_bar.rb
@@ -3,10 +3,6 @@
module WithPerformanceBar
extend ActiveSupport::Concern
- included do
- include Peek::Rblineprof::CustomControllerHelpers
- end
-
def peek_enabled?
return false unless Gitlab::PerformanceBar.enabled?(current_user)
diff --git a/app/controllers/confirmations_controller.rb b/app/controllers/confirmations_controller.rb
index 2ae500a2fdf..b192189ba3c 100644
--- a/app/controllers/confirmations_controller.rb
+++ b/app/controllers/confirmations_controller.rb
@@ -11,7 +11,7 @@ class ConfirmationsController < Devise::ConfirmationsController
protected
def after_resending_confirmation_instructions_path_for(resource)
- users_almost_there_path
+ Feature.enabled?(:soft_email_confirmation) ? stored_location_for(resource) || dashboard_projects_path : users_almost_there_path
end
def after_confirmation_path_for(resource_name, resource)
diff --git a/app/controllers/dashboard/projects_controller.rb b/app/controllers/dashboard/projects_controller.rb
index daeb8fda417..1dc89943f7f 100644
--- a/app/controllers/dashboard/projects_controller.rb
+++ b/app/controllers/dashboard/projects_controller.rb
@@ -4,10 +4,12 @@ class Dashboard::ProjectsController < Dashboard::ApplicationController
include ParamsBackwardCompatibility
include RendersMemberAccess
include OnboardingExperimentHelper
+ include SortingHelper
+ include SortingPreference
prepend_before_action(only: [:index]) { authenticate_sessionless_user!(:rss) }
before_action :set_non_archived_param
- before_action :default_sorting
+ before_action :set_sorting
before_action :projects, only: [:index]
skip_cross_project_access_check :index, :starred
@@ -59,11 +61,6 @@ class Dashboard::ProjectsController < Dashboard::ApplicationController
end
end
- def default_sorting
- params[:sort] ||= 'latest_activity_desc'
- @sort = params[:sort]
- end
-
# rubocop: disable CodeReuse/ActiveRecord
def load_projects(finder_params)
@total_user_projects_count = ProjectsFinder.new(params: { non_public: true }, current_user: current_user).execute
@@ -73,6 +70,7 @@ class Dashboard::ProjectsController < Dashboard::ApplicationController
.new(params: finder_params, current_user: current_user)
.execute
.includes(:route, :creator, :group, namespace: [:route, :owner])
+ .preload(:project_feature)
.page(finder_params[:page])
prepare_projects_for_rendering(projects)
@@ -88,4 +86,17 @@ class Dashboard::ProjectsController < Dashboard::ApplicationController
Events::RenderService.new(current_user).execute(@events, atom_request: request.format.atom?)
end
+
+ def set_sorting
+ params[:sort] = set_sort_order
+ @sort = params[:sort]
+ end
+
+ def default_sort_order
+ sort_value_latest_activity
+ end
+
+ def sorting_field
+ Project::SORTING_PREFERENCE_FIELD
+ end
end
diff --git a/app/controllers/explore/projects_controller.rb b/app/controllers/explore/projects_controller.rb
index ef86d5f981a..271f2b4b57d 100644
--- a/app/controllers/explore/projects_controller.rb
+++ b/app/controllers/explore/projects_controller.rb
@@ -3,12 +3,13 @@
class Explore::ProjectsController < Explore::ApplicationController
include ParamsBackwardCompatibility
include RendersMemberAccess
+ include SortingHelper
+ include SortingPreference
before_action :set_non_archived_param
+ before_action :set_sorting
def index
- params[:sort] ||= 'latest_activity_desc'
- @sort = params[:sort]
@projects = load_projects
respond_to do |format|
@@ -23,7 +24,6 @@ class Explore::ProjectsController < Explore::ApplicationController
def trending
params[:trending] = true
- @sort = params[:sort]
@projects = load_projects
respond_to do |format|
@@ -67,4 +67,17 @@ class Explore::ProjectsController < Explore::ApplicationController
prepare_projects_for_rendering(projects)
end
# rubocop: enable CodeReuse/ActiveRecord
+
+ def set_sorting
+ params[:sort] = set_sort_order
+ @sort = params[:sort]
+ end
+
+ def default_sort_order
+ sort_value_latest_activity
+ end
+
+ def sorting_field
+ Project::SORTING_PREFERENCE_FIELD
+ end
end
diff --git a/app/controllers/graphql_controller.rb b/app/controllers/graphql_controller.rb
index 9fbbe373b0d..72d40f709e6 100644
--- a/app/controllers/graphql_controller.rb
+++ b/app/controllers/graphql_controller.rb
@@ -30,6 +30,10 @@ class GraphqlController < ApplicationController
render_error(exception.message, status: :unprocessable_entity)
end
+ rescue_from Gitlab::Graphql::Errors::ArgumentError do |exception|
+ render_error(exception.message, status: :unprocessable_entity)
+ end
+
private
def execute_multiplex
diff --git a/app/controllers/groups/group_members_controller.rb b/app/controllers/groups/group_members_controller.rb
index f1d6fb00cfc..557888711ec 100644
--- a/app/controllers/groups/group_members_controller.rb
+++ b/app/controllers/groups/group_members_controller.rb
@@ -5,6 +5,8 @@ class Groups::GroupMembersController < Groups::ApplicationController
include MembersPresentation
include SortingHelper
+ MEMBER_PER_PAGE_LIMIT = 50
+
def self.admin_not_required_endpoints
%i[index leave request_access]
end
@@ -24,7 +26,14 @@ class Groups::GroupMembersController < Groups::ApplicationController
@project = @group.projects.find(params[:project_id]) if params[:project_id]
@members = GroupMembersFinder.new(@group).execute
- @members = @members.non_invite unless can_manage_members
+
+ if can_manage_members
+ @invited_members = @members.invite
+ @invited_members = @invited_members.search_invite_email(params[:search_invited]) if params[:search_invited].present?
+ @invited_members = present_members(@invited_members.page(params[:invited_members_page]).per(MEMBER_PER_PAGE_LIMIT))
+ end
+
+ @members = @members.non_invite
@members = @members.search(params[:search]) if params[:search].present?
@members = @members.sort_by_attribute(@sort)
@@ -32,7 +41,7 @@ class Groups::GroupMembersController < Groups::ApplicationController
@members = @members.filter_by_2fa(params[:two_factor])
end
- @members = @members.page(params[:page]).per(50)
+ @members = @members.page(params[:page]).per(MEMBER_PER_PAGE_LIMIT)
@members = present_members(@members)
@requesters = present_members(
diff --git a/app/controllers/groups_controller.rb b/app/controllers/groups_controller.rb
index 797833e3f91..886d1f99d69 100644
--- a/app/controllers/groups_controller.rb
+++ b/app/controllers/groups_controller.rb
@@ -7,10 +7,6 @@ class GroupsController < Groups::ApplicationController
include PreviewMarkdown
include RecordUserLastActivity
- before_action do
- push_frontend_feature_flag(:manual_sorting)
- end
-
respond_to :html
prepend_before_action(only: [:show, :issues]) { authenticate_sessionless_user!(:rss) }
@@ -107,7 +103,7 @@ class GroupsController < Groups::ApplicationController
if Groups::UpdateService.new(@group, current_user, group_params).execute
redirect_to edit_group_path(@group, anchor: params[:update_section]), notice: "Group '#{@group.name}' was successfully updated."
else
- @group.restore_path!
+ @group.path = @group.path_before_last_save || @group.path_was
render action: "edit"
end
@@ -180,6 +176,7 @@ class GroupsController < Groups::ApplicationController
[
:avatar,
:description,
+ :emails_disabled,
:lfs_enabled,
:name,
:path,
@@ -192,7 +189,8 @@ class GroupsController < Groups::ApplicationController
:chat_team_name,
:require_two_factor_authentication,
:two_factor_grace_period,
- :project_creation_level
+ :project_creation_level,
+ :subgroup_creation_level
]
end
diff --git a/app/controllers/ide_controller.rb b/app/controllers/ide_controller.rb
index eeeebe430a7..af1e6cc703b 100644
--- a/app/controllers/ide_controller.rb
+++ b/app/controllers/ide_controller.rb
@@ -4,5 +4,6 @@ class IdeController < ApplicationController
layout 'fullscreen'
def index
+ Gitlab::UsageDataCounters::WebIdeCounter.increment_views_count
end
end
diff --git a/app/controllers/import/bitbucket_server_controller.rb b/app/controllers/import/bitbucket_server_controller.rb
index f71ea8642cd..dc72a4e4fd9 100644
--- a/app/controllers/import/bitbucket_server_controller.rb
+++ b/app/controllers/import/bitbucket_server_controller.rb
@@ -1,6 +1,8 @@
# frozen_string_literal: true
class Import::BitbucketServerController < Import::BaseController
+ include ActionView::Helpers::SanitizeHelper
+
before_action :verify_bitbucket_server_import_enabled
before_action :bitbucket_auth, except: [:new, :configure]
before_action :validate_import_params, only: [:create]
@@ -57,7 +59,7 @@ class Import::BitbucketServerController < Import::BaseController
# rubocop: disable CodeReuse/ActiveRecord
def status
- @collection = bitbucket_client.repos(page_offset: page_offset, limit: limit_per_page)
+ @collection = bitbucket_client.repos(page_offset: page_offset, limit: limit_per_page, filter: sanitized_filter_param)
@repos, @incompatible_repos = @collection.partition { |repo| repo.valid? }
# Use the import URL to filter beyond what BaseService#find_already_added_projects
@@ -147,4 +149,8 @@ class Import::BitbucketServerController < Import::BaseController
def limit_per_page
BitbucketServer::Paginator::PAGE_LENGTH
end
+
+ def sanitized_filter_param
+ sanitize(params[:filter])
+ end
end
diff --git a/app/controllers/import/github_controller.rb b/app/controllers/import/github_controller.rb
index aa4aa0fbdac..ebb50fc8b10 100644
--- a/app/controllers/import/github_controller.rb
+++ b/app/controllers/import/github_controller.rb
@@ -10,7 +10,7 @@ class Import::GithubController < Import::BaseController
rescue_from Octokit::Unauthorized, with: :provider_unauthorized
def new
- if github_import_configured? && logged_in_with_provider?
+ if !ci_cd_only? && github_import_configured? && logged_in_with_provider?
go_to_provider_for_permissions
elsif session[access_token_key]
redirect_to status_import_url
@@ -169,11 +169,15 @@ class Import::GithubController < Import::BaseController
# rubocop: enable CodeReuse/ActiveRecord
def provider_auth
- if session[access_token_key].blank?
+ if !ci_cd_only? && session[access_token_key].blank?
go_to_provider_for_permissions
end
end
+ def ci_cd_only?
+ %w[1 true].include?(params[:ci_cd_only])
+ end
+
def client_options
{}
end
diff --git a/app/controllers/jwt_controller.rb b/app/controllers/jwt_controller.rb
index 5ecf4f114cf..da39d64c93d 100644
--- a/app/controllers/jwt_controller.rb
+++ b/app/controllers/jwt_controller.rb
@@ -1,6 +1,7 @@
# frozen_string_literal: true
class JwtController < ApplicationController
+ skip_around_action :set_session_storage
skip_before_action :authenticate_user!
skip_before_action :verify_authenticity_token
before_action :authenticate_project_or_user
diff --git a/app/controllers/omniauth_callbacks_controller.rb b/app/controllers/omniauth_callbacks_controller.rb
index 2a8dd997d04..b1efa767154 100644
--- a/app/controllers/omniauth_callbacks_controller.rb
+++ b/app/controllers/omniauth_callbacks_controller.rb
@@ -139,7 +139,7 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController
if user.two_factor_enabled? && !auth_user.bypass_two_factor?
prompt_for_two_factor(user)
else
- sign_in_and_redirect(user)
+ sign_in_and_redirect(user, event: :authentication)
end
else
fail_login(user)
diff --git a/app/controllers/projects/artifacts_controller.rb b/app/controllers/projects/artifacts_controller.rb
index 2ef18d900f2..da8a371acaa 100644
--- a/app/controllers/projects/artifacts_controller.rb
+++ b/app/controllers/projects/artifacts_controller.rb
@@ -92,7 +92,10 @@ class Projects::ArtifactsController < Projects::ApplicationController
def build_from_ref
return unless @ref_name
- project.latest_successful_build_for(params[:job], @ref_name)
+ commit = project.commit(@ref_name)
+ return unless commit
+
+ project.latest_successful_build_for_sha(params[:job], commit.id)
end
def artifacts_file
diff --git a/app/controllers/projects/badges_controller.rb b/app/controllers/projects/badges_controller.rb
index 09a384e89ab..66b51b17790 100644
--- a/app/controllers/projects/badges_controller.rb
+++ b/app/controllers/projects/badges_controller.rb
@@ -3,7 +3,8 @@
class Projects::BadgesController < Projects::ApplicationController
layout 'project_settings'
before_action :authorize_admin_project!, only: [:index]
- before_action :no_cache_headers, except: [:index]
+ before_action :no_cache_headers, only: [:pipeline, :coverage]
+ before_action :authorize_read_build!, only: [:pipeline, :coverage]
def pipeline
pipeline_status = Gitlab::Badge::Pipeline::Status
diff --git a/app/controllers/projects/blob_controller.rb b/app/controllers/projects/blob_controller.rb
index b04ffe80db4..4125f44d00a 100644
--- a/app/controllers/projects/blob_controller.rb
+++ b/app/controllers/projects/blob_controller.rb
@@ -92,7 +92,7 @@ class Projects::BlobController < Projects::ApplicationController
def diff
apply_diff_view_cookie!
- @form = Blobs::UnfoldPresenter.new(blob, params.to_unsafe_h)
+ @form = Blobs::UnfoldPresenter.new(blob, diff_params)
# keep only json rendering when
# https://gitlab.com/gitlab-org/gitlab-ce/issues/44988 is done
@@ -239,4 +239,8 @@ class Projects::BlobController < Projects::ApplicationController
def tree_path
@path.rpartition('/').first
end
+
+ def diff_params
+ params.permit(:full, :since, :to, :bottom, :unfold, :offset, :indent)
+ end
end
diff --git a/app/controllers/projects/branches_controller.rb b/app/controllers/projects/branches_controller.rb
index 141a7dfb923..e7bdb4b2042 100644
--- a/app/controllers/projects/branches_controller.rb
+++ b/app/controllers/projects/branches_controller.rb
@@ -49,7 +49,7 @@ class Projects::BranchesController < Projects::ApplicationController
branches = BranchesFinder.new(repository, params.permit(names: [])).execute
Gitlab::GitalyClient.allow_n_plus_1_calls do
- render json: branches.to_h { |branch| [branch.name, service.call(branch)] }
+ render json: branches.map { |branch| [branch.name, service.call(branch)] }.to_h
end
end
end
diff --git a/app/controllers/projects/build_artifacts_controller.rb b/app/controllers/projects/build_artifacts_controller.rb
index 4274c356227..99f4524eec5 100644
--- a/app/controllers/projects/build_artifacts_controller.rb
+++ b/app/controllers/projects/build_artifacts_controller.rb
@@ -51,6 +51,6 @@ class Projects::BuildArtifactsController < Projects::ApplicationController
def job_from_ref
return unless @ref_name
- project.latest_successful_build_for(params[:job], @ref_name)
+ project.latest_successful_build_for_ref(params[:job], @ref_name)
end
end
diff --git a/app/controllers/projects/cycle_analytics/events_controller.rb b/app/controllers/projects/cycle_analytics/events_controller.rb
index fb43356ff10..926592b9681 100644
--- a/app/controllers/projects/cycle_analytics/events_controller.rb
+++ b/app/controllers/projects/cycle_analytics/events_controller.rb
@@ -23,7 +23,7 @@ module Projects
end
def test
- options(events_params)[:branch] = events_params[:branch_name]
+ options(cycle_analytics_params)[:branch] = cycle_analytics_params[:branch_name]
render_events(cycle_analytics[:test].events)
end
@@ -50,13 +50,13 @@ module Projects
end
def cycle_analytics
- @cycle_analytics ||= ::CycleAnalytics.new(project, options(events_params))
+ @cycle_analytics ||= ::CycleAnalytics::ProjectLevel.new(project, options: options(cycle_analytics_params))
end
- def events_params
- return {} unless params[:events].present?
+ def cycle_analytics_params
+ return {} unless params[:cycle_analytics].present?
- params[:events].permit(:start_date, :branch_name)
+ params[:cycle_analytics].permit(:start_date, :branch_name)
end
end
end
diff --git a/app/controllers/projects/cycle_analytics_controller.rb b/app/controllers/projects/cycle_analytics_controller.rb
index 8c071496ba9..3b0abecf2c9 100644
--- a/app/controllers/projects/cycle_analytics_controller.rb
+++ b/app/controllers/projects/cycle_analytics_controller.rb
@@ -9,13 +9,19 @@ class Projects::CycleAnalyticsController < Projects::ApplicationController
before_action :authorize_read_cycle_analytics!
def show
- @cycle_analytics = ::CycleAnalytics.new(@project, options(cycle_analytics_params))
+ @cycle_analytics = ::CycleAnalytics::ProjectLevel.new(@project, options: options(cycle_analytics_params))
@cycle_analytics_no_data = @cycle_analytics.no_stats?
respond_to do |format|
- format.html
- format.json { render json: cycle_analytics_json }
+ format.html do
+ Gitlab::UsageDataCounters::CycleAnalyticsCounter.count(:views)
+
+ render :show
+ end
+ format.json do
+ render json: cycle_analytics_json
+ end
end
end
diff --git a/app/controllers/projects/environments_controller.rb b/app/controllers/projects/environments_controller.rb
index ecf05e6ea64..5a1f93dc609 100644
--- a/app/controllers/projects/environments_controller.rb
+++ b/app/controllers/projects/environments_controller.rb
@@ -11,8 +11,9 @@ class Projects::EnvironmentsController < Projects::ApplicationController
before_action :verify_api_request!, only: :terminal_websocket_authorize
before_action :expire_etag_cache, only: [:index]
before_action only: [:metrics, :additional_metrics, :metrics_dashboard] do
- push_frontend_feature_flag(:environment_metrics_use_prometheus_endpoint)
+ push_frontend_feature_flag(:environment_metrics_use_prometheus_endpoint, default_enabled: true)
push_frontend_feature_flag(:environment_metrics_show_multiple_dashboards)
+ push_frontend_feature_flag(:environment_metrics_additional_panel_types)
push_frontend_feature_flag(:prometheus_computed_alerts)
end
@@ -159,20 +160,23 @@ class Projects::EnvironmentsController < Projects::ApplicationController
end
def metrics_dashboard
- return render_403 unless Feature.enabled?(:environment_metrics_use_prometheus_endpoint, project)
-
- if Feature.enabled?(:environment_metrics_show_multiple_dashboards, project)
+ if params[:embedded]
result = dashboard_finder.find(
project,
current_user,
environment,
dashboard_path: params[:dashboard],
- embedded: params[:embedded]
+ **dashboard_params.to_h.symbolize_keys
+ )
+ elsif Feature.enabled?(:environment_metrics_show_multiple_dashboards, project)
+ result = dashboard_finder.find(
+ project,
+ current_user,
+ environment,
+ dashboard_path: params[:dashboard]
)
- unless params[:embedded]
- result[:all_dashboards] = dashboard_finder.find_all_paths(project)
- end
+ result[:all_dashboards] = dashboard_finder.find_all_paths(project)
else
result = dashboard_finder.find(project, current_user, environment)
end
@@ -230,6 +234,10 @@ class Projects::EnvironmentsController < Projects::ApplicationController
params.require([:start, :end])
end
+ def dashboard_params
+ params.permit(:embedded, :group, :title, :y_label)
+ end
+
def dashboard_finder
Gitlab::Metrics::Dashboard::Finder
end
diff --git a/app/controllers/projects/git_http_client_controller.rb b/app/controllers/projects/git_http_client_controller.rb
index 956093b972b..abf8407a51c 100644
--- a/app/controllers/projects/git_http_client_controller.rb
+++ b/app/controllers/projects/git_http_client_controller.rb
@@ -49,7 +49,8 @@ class Projects::GitHttpClientController < Projects::ApplicationController
send_final_spnego_response
return # Allow access
end
- elsif project && download_request? && Guest.can?(:download_code, project)
+ elsif project && download_request? && http_allowed? && Guest.can?(:download_code, project)
+
@authentication_result = Gitlab::Auth::Result.new(nil, project, :none, [:download_code])
return # Allow access
@@ -113,4 +114,8 @@ class Projects::GitHttpClientController < Projects::ApplicationController
def ci?
authentication_result.ci?(project)
end
+
+ def http_allowed?
+ Gitlab::ProtocolAccess.allowed?('http')
+ end
end
diff --git a/app/controllers/projects/issues_controller.rb b/app/controllers/projects/issues_controller.rb
index 228de8bc6f3..b7fd286bfe0 100644
--- a/app/controllers/projects/issues_controller.rb
+++ b/app/controllers/projects/issues_controller.rb
@@ -10,10 +10,6 @@ class Projects::IssuesController < Projects::ApplicationController
include SpammableActions
include RecordUserLastActivity
- before_action do
- push_frontend_feature_flag(:manual_sorting)
- end
-
def issue_except_actions
%i[index calendar new create bulk_update import_csv]
end
@@ -194,7 +190,7 @@ class Projects::IssuesController < Projects::ApplicationController
protected
- def issuable_sorting_field
+ def sorting_field
Issue::SORTING_PREFERENCE_FIELD
end
diff --git a/app/controllers/projects/jobs_controller.rb b/app/controllers/projects/jobs_controller.rb
index 02ff6e872c9..adbc0159358 100644
--- a/app/controllers/projects/jobs_controller.rb
+++ b/app/controllers/projects/jobs_controller.rb
@@ -94,7 +94,7 @@ class Projects::JobsController < Projects::ApplicationController
def play
return respond_422 unless @build.playable?
- build = @build.play(current_user)
+ build = @build.play(current_user, play_params[:job_variables_attributes])
redirect_to build_path(build)
end
@@ -190,6 +190,10 @@ class Projects::JobsController < Projects::ApplicationController
{ query: { 'response-content-type' => 'text/plain; charset=utf-8', 'response-content-disposition' => 'inline' } }
end
+ def play_params
+ params.permit(job_variables_attributes: %i[key secret_value])
+ end
+
def trace_artifact_file
@trace_artifact_file ||= build.job_artifacts_trace&.file
end
diff --git a/app/controllers/projects/merge_requests/application_controller.rb b/app/controllers/projects/merge_requests/application_controller.rb
index dcc272aecff..006731c0e66 100644
--- a/app/controllers/projects/merge_requests/application_controller.rb
+++ b/app/controllers/projects/merge_requests/application_controller.rb
@@ -45,7 +45,7 @@ class Projects::MergeRequests::ApplicationController < Projects::ApplicationCont
def set_pipeline_variables
@pipelines =
- if can?(current_user, :read_pipeline, @project)
+ if can?(current_user, :read_pipeline, @merge_request.source_project)
@merge_request.all_pipelines
else
Ci::Pipeline.none
diff --git a/app/controllers/projects/merge_requests/content_controller.rb b/app/controllers/projects/merge_requests/content_controller.rb
index 6e026b83ee3..eec5c1a4355 100644
--- a/app/controllers/projects/merge_requests/content_controller.rb
+++ b/app/controllers/projects/merge_requests/content_controller.rb
@@ -7,16 +7,33 @@ class Projects::MergeRequests::ContentController < Projects::MergeRequests::Appl
# for other types of serialization
before_action :close_merge_request_if_no_source_project
+ before_action :set_polling_header
around_action :allow_gitaly_ref_name_caching
def widget
respond_to do |format|
format.json do
- Gitlab::PollingInterval.set_header(response, interval: 10_000)
+ render json: serializer(MergeRequestPollWidgetEntity)
+ end
+ end
+ end
- serializer = MergeRequestSerializer.new(current_user: current_user, project: merge_request.project)
- render json: serializer.represent(merge_request, serializer: 'widget')
+ def cached_widget
+ respond_to do |format|
+ format.json do
+ render json: serializer(MergeRequestPollCachedWidgetEntity)
end
end
end
+
+ private
+
+ def set_polling_header
+ Gitlab::PollingInterval.set_header(response, interval: 10_000)
+ end
+
+ def serializer(entity)
+ serializer = MergeRequestSerializer.new(current_user: current_user, project: merge_request.project)
+ serializer.represent(merge_request, {}, entity)
+ end
end
diff --git a/app/controllers/projects/merge_requests/creations_controller.rb b/app/controllers/projects/merge_requests/creations_controller.rb
index 32cefe54613..6ac5bb90706 100644
--- a/app/controllers/projects/merge_requests/creations_controller.rb
+++ b/app/controllers/projects/merge_requests/creations_controller.rb
@@ -23,6 +23,8 @@ class Projects::MergeRequests::CreationsController < Projects::MergeRequests::Ap
@merge_request = ::MergeRequests::CreateService.new(project, current_user, merge_request_params).execute
if @merge_request.valid?
+ incr_count_webide_merge_request
+
redirect_to(merge_request_path(@merge_request))
else
@source_project = @merge_request.source_project
@@ -135,4 +137,10 @@ class Projects::MergeRequests::CreationsController < Projects::MergeRequests::Ap
def whitelist_query_limiting
Gitlab::QueryLimiting.whitelist('https://gitlab.com/gitlab-org/gitlab-ce/issues/42384')
end
+
+ def incr_count_webide_merge_request
+ return if params[:nav_source] != 'webide'
+
+ Gitlab::UsageDataCounters::WebIdeCounter.increment_merge_requests_count
+ end
end
diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb
index 2aa2508be16..f4cc0a5851b 100644
--- a/app/controllers/projects/merge_requests_controller.rb
+++ b/app/controllers/projects/merge_requests_controller.rb
@@ -82,7 +82,8 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
end
def pipelines
- @pipelines = @merge_request.all_pipelines.page(params[:page]).per(30)
+ set_pipeline_variables
+ @pipelines = @pipelines.page(params[:page]).per(30)
Gitlab::PollingInterval.set_header(response, interval: 10_000)
@@ -218,7 +219,7 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
alias_method :issuable, :merge_request
alias_method :awardable, :merge_request
- def issuable_sorting_field
+ def sorting_field
MergeRequest::SORTING_PREFERENCE_FIELD
end
diff --git a/app/controllers/projects/notes_controller.rb b/app/controllers/projects/notes_controller.rb
index 3152a38fd8e..13e8453ed00 100644
--- a/app/controllers/projects/notes_controller.rb
+++ b/app/controllers/projects/notes_controller.rb
@@ -6,7 +6,7 @@ class Projects::NotesController < Projects::ApplicationController
include NotesHelper
include ToggleAwardEmoji
- before_action :whitelist_query_limiting, only: [:create]
+ before_action :whitelist_query_limiting, only: [:create, :update]
before_action :authorize_read_note!
before_action :authorize_create_note!, only: [:create]
before_action :authorize_resolve_note!, only: [:resolve, :unresolve]
@@ -68,7 +68,7 @@ class Projects::NotesController < Projects::ApplicationController
alias_method :awardable, :note
def finder_params
- params.merge(last_fetched_at: last_fetched_at, notes_filter: notes_filter)
+ params.merge(project: project, last_fetched_at: last_fetched_at, notes_filter: notes_filter)
end
def authorize_admin_note!
diff --git a/app/controllers/projects/pipelines_controller.rb b/app/controllers/projects/pipelines_controller.rb
index db3b7c8b177..499d4918899 100644
--- a/app/controllers/projects/pipelines_controller.rb
+++ b/app/controllers/projects/pipelines_controller.rb
@@ -3,6 +3,7 @@
class Projects::PipelinesController < Projects::ApplicationController
before_action :whitelist_query_limiting, only: [:create, :retry]
before_action :pipeline, except: [:index, :new, :create, :charts]
+ before_action :set_pipeline_path, only: [:show]
before_action :authorize_read_pipeline!
before_action :authorize_read_build!, only: [:index]
before_action :authorize_create_pipeline!, only: [:new, :create]
@@ -174,14 +175,36 @@ class Projects::PipelinesController < Projects::ApplicationController
# rubocop: disable CodeReuse/ActiveRecord
def pipeline
- @pipeline ||= project
- .all_pipelines
- .includes(user: :status)
- .find_by!(id: params[:id])
- .present(current_user: current_user)
+ @pipeline ||= if params[:id].blank? && params[:latest]
+ latest_pipeline
+ else
+ project
+ .all_pipelines
+ .includes(builds: :tags, user: :status)
+ .find_by!(id: params[:id])
+ .present(current_user: current_user)
+ end
end
# rubocop: enable CodeReuse/ActiveRecord
+ def set_pipeline_path
+ @pipeline_path ||= if params[:id].blank? && params[:latest]
+ latest_project_pipelines_path(@project, params['ref'])
+ else
+ project_pipeline_path(@project, @pipeline)
+ end
+ end
+
+ def latest_pipeline
+ ref = params['ref'].presence || @project.default_branch
+ sha = @project.commit(ref)&.sha
+
+ @project.ci_pipelines
+ .newest_first(ref: ref, sha: sha)
+ .first
+ &.present(current_user: current_user)
+ end
+
def whitelist_query_limiting
# Also see https://gitlab.com/gitlab-org/gitlab-ce/issues/42343
Gitlab::QueryLimiting.whitelist('https://gitlab.com/gitlab-org/gitlab-ce/issues/42339')
diff --git a/app/controllers/projects/raw_controller.rb b/app/controllers/projects/raw_controller.rb
index 42ae5b0ef3c..c94fdd9483d 100644
--- a/app/controllers/projects/raw_controller.rb
+++ b/app/controllers/projects/raw_controller.rb
@@ -8,10 +8,30 @@ class Projects::RawController < Projects::ApplicationController
before_action :require_non_empty_project
before_action :assign_ref_vars
before_action :authorize_download_code!
+ before_action :show_rate_limit, only: [:show]
def show
@blob = @repository.blob_at(@commit.id, @path)
send_blob(@repository, @blob, inline: (params[:inline] != 'false'))
end
+
+ private
+
+ def show_rate_limit
+ limiter = ::Gitlab::ActionRateLimiter.new(action: :show_raw_controller)
+
+ return unless limiter.throttled?([@project, @commit, @path], raw_blob_request_limit)
+
+ 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
+
+ def raw_blob_request_limit
+ Gitlab::CurrentSettings
+ .current_application_settings
+ .raw_blob_request_limit
+ end
end
diff --git a/app/controllers/projects/registry/tags_controller.rb b/app/controllers/projects/registry/tags_controller.rb
index bf1d8d8b5fc..54e2faa2dd7 100644
--- a/app/controllers/projects/registry/tags_controller.rb
+++ b/app/controllers/projects/registry/tags_controller.rb
@@ -5,6 +5,8 @@ module Projects
class TagsController < ::Projects::Registry::ApplicationController
before_action :authorize_destroy_container_image!, only: [:destroy]
+ LIMIT = 15
+
def index
respond_to do |format|
format.json do
@@ -28,10 +30,40 @@ module Projects
end
end
+ def bulk_destroy
+ unless params[:ids].present?
+ head :bad_request
+ return
+ end
+
+ tag_names = params[:ids] || []
+ if tag_names.size > LIMIT
+ head :bad_request
+ return
+ end
+
+ @tags = tag_names.map { |tag_name| image.tag(tag_name) }
+ unless @tags.all? { |tag| tag.valid_name? }
+ head :bad_request
+ return
+ end
+
+ success_count = 0
+ @tags.each do |tag|
+ if tag.delete
+ success_count += 1
+ end
+ end
+
+ respond_to do |format|
+ format.json { head(success_count == @tags.size ? :no_content : :bad_request) }
+ end
+ end
+
private
def tags
- Kaminari::PaginatableArray.new(image.tags, limit: 15)
+ Kaminari::PaginatableArray.new(image.tags, limit: LIMIT)
end
def image
diff --git a/app/controllers/projects/repositories_controller.rb b/app/controllers/projects/repositories_controller.rb
index 3b4215b766e..a51759641e4 100644
--- a/app/controllers/projects/repositories_controller.rb
+++ b/app/controllers/projects/repositories_controller.rb
@@ -6,6 +6,7 @@ class Projects::RepositoriesController < Projects::ApplicationController
# Authorize
before_action :require_non_empty_project, except: :create
before_action :assign_archive_vars, only: :archive
+ before_action :assign_append_sha, only: :archive
before_action :authorize_download_code!
before_action :authorize_admin_project!, only: :create
@@ -16,19 +17,64 @@ class Projects::RepositoriesController < Projects::ApplicationController
end
def archive
- append_sha = params[:append_sha]
+ set_cache_headers
+ return if archive_not_modified?
- if @ref
- shortname = "#{@project.path}-#{@ref.tr('/', '-')}"
- append_sha = false if @filename == shortname
- end
-
- send_git_archive @repository, ref: @ref, path: params[:path], format: params[:format], append_sha: append_sha
+ send_git_archive @repository, **repo_params
rescue => ex
logger.error("#{self.class.name}: #{ex}")
git_not_found!
end
+ private
+
+ def repo_params
+ @repo_params ||= { ref: @ref, path: params[:path], format: params[:format], append_sha: @append_sha }
+ end
+
+ def set_cache_headers
+ expires_in cache_max_age(archive_metadata['CommitId']), public: project.public?
+ fresh_when(etag: archive_metadata['ArchivePath'])
+ end
+
+ def archive_not_modified?
+ # Check response freshness (Last-Modified and ETag)
+ # against request If-Modified-Since and If-None-Match conditions.
+ request.fresh?(response)
+ end
+
+ def archive_metadata
+ @archive_metadata ||= @repository.archive_metadata(
+ @ref,
+ '', # Where archives are stored isn't really important for ETag purposes
+ repo_params[:format],
+ path: repo_params[:path],
+ append_sha: @append_sha
+ )
+ end
+
+ def cache_max_age(commit_id)
+ if @ref == commit_id
+ # This is a link to an archive by a commit SHA. That means that the archive
+ # is immutable. The only reason to invalidate the cache is if the commit
+ # was deleted or if the user lost access to the repository.
+ Repository::ARCHIVE_CACHE_TIME_IMMUTABLE
+ else
+ # A branch or tag points at this archive. That means that the expected archive
+ # content may change over time.
+ Repository::ARCHIVE_CACHE_TIME
+ end
+ end
+
+ def assign_append_sha
+ @append_sha = params[:append_sha]
+
+ if @ref
+ shortname = "#{@project.path}-#{@ref.tr('/', '-')}"
+ @append_sha = false if @filename == shortname
+ end
+ end
+
def assign_archive_vars
if params[:id]
@ref, @filename = extract_ref(params[:id])
diff --git a/app/controllers/projects/snippets_controller.rb b/app/controllers/projects/snippets_controller.rb
index 255f1f3569a..59f948959d6 100644
--- a/app/controllers/projects/snippets_controller.rb
+++ b/app/controllers/projects/snippets_controller.rb
@@ -7,7 +7,8 @@ class Projects::SnippetsController < Projects::ApplicationController
include SnippetsActions
include RendersBlob
- skip_before_action :verify_authenticity_token, only: [:show], if: :js_request?
+ skip_before_action :verify_authenticity_token,
+ if: -> { action_name == 'show' && js_request? }
before_action :check_snippets_available!
before_action :snippet, only: [:show, :edit, :destroy, :update, :raw, :toggle_award_emoji, :mark_as_spam]
diff --git a/app/controllers/projects/starrers_controller.rb b/app/controllers/projects/starrers_controller.rb
new file mode 100644
index 00000000000..4efe956e973
--- /dev/null
+++ b/app/controllers/projects/starrers_controller.rb
@@ -0,0 +1,20 @@
+# frozen_string_literal: true
+
+class Projects::StarrersController < Projects::ApplicationController
+ include SortingHelper
+
+ def index
+ @starrers = UsersStarProjectsFinder.new(@project, params, current_user: @current_user).execute
+ @sort = params[:sort].presence || sort_value_name
+ @starrers = @starrers.preload_users.sort_by_attribute(@sort).page(params[:page])
+ @public_count = @project.starrers.with_public_profile.size
+ @total_count = @project.starrers.size
+ @private_count = @total_count - @public_count
+ end
+
+ private
+
+ def has_starred_project?(starrers)
+ starrers.first { |starrer| starrer.user_id == current_user.id }
+ end
+end
diff --git a/app/controllers/projects/triggers_controller.rb b/app/controllers/projects/triggers_controller.rb
index 284e119ca06..7159d0243a3 100644
--- a/app/controllers/projects/triggers_controller.rb
+++ b/app/controllers/projects/triggers_controller.rb
@@ -4,7 +4,7 @@ class Projects::TriggersController < Projects::ApplicationController
before_action :authorize_admin_build!
before_action :authorize_manage_trigger!, except: [:index, :create]
before_action :authorize_admin_trigger!, only: [:edit, :update]
- before_action :trigger, only: [:take_ownership, :edit, :update, :destroy]
+ before_action :trigger, only: [:edit, :update, :destroy]
layout 'project_settings'
@@ -24,16 +24,6 @@ class Projects::TriggersController < Projects::ApplicationController
redirect_to project_settings_ci_cd_path(@project, anchor: 'js-pipeline-triggers')
end
- def take_ownership
- if trigger.update(owner: current_user)
- flash[:notice] = _('Trigger was re-assigned.')
- else
- flash[:alert] = _('You could not take ownership of trigger.')
- end
-
- redirect_to project_settings_ci_cd_path(@project, anchor: 'js-pipeline-triggers')
- end
-
def edit
end
diff --git a/app/controllers/projects/variables_controller.rb b/app/controllers/projects/variables_controller.rb
index 646728e8167..1dffc57fcf0 100644
--- a/app/controllers/projects/variables_controller.rb
+++ b/app/controllers/projects/variables_controller.rb
@@ -38,6 +38,6 @@ class Projects::VariablesController < Projects::ApplicationController
end
def variable_params_attributes
- %i[id variable_type key secret_value protected masked _destroy]
+ %i[id variable_type key secret_value protected masked environment_scope _destroy]
end
end
diff --git a/app/controllers/projects/wikis_controller.rb b/app/controllers/projects/wikis_controller.rb
index fa5bdbc7d49..b187fdb2723 100644
--- a/app/controllers/projects/wikis_controller.rb
+++ b/app/controllers/projects/wikis_controller.rb
@@ -6,15 +6,20 @@ class Projects::WikisController < Projects::ApplicationController
include Gitlab::Utils::StrongMemoize
before_action :authorize_read_wiki!
- before_action :authorize_create_wiki!, only: [:edit, :create, :history]
+ before_action :authorize_create_wiki!, only: [:edit, :create]
before_action :authorize_admin_wiki!, only: :destroy
before_action :load_project_wiki
before_action :load_page, only: [:show, :edit, :update, :history, :destroy]
- before_action :valid_encoding?, only: [:show, :edit, :update], if: :load_page
+ before_action :valid_encoding?,
+ if: -> { %w[show edit update].include?(action_name) && load_page }
before_action only: [:edit, :update], unless: :valid_encoding? do
redirect_to(project_wiki_path(@project, @page))
end
+ def new
+ redirect_to project_wiki_path(@project, SecureRandom.uuid, random_title: true)
+ end
+
def pages
@wiki_pages = Kaminari.paginate_array(
@project_wiki.list_pages(sort: params[:sort], direction: params[:direction])
@@ -23,17 +28,25 @@ class Projects::WikisController < Projects::ApplicationController
@wiki_entries = WikiPage.group_by_directory(@wiki_pages)
end
+ # `#show` handles a number of scenarios:
+ #
+ # - If `id` matches a WikiPage, then show the wiki page.
+ # - If `id` is a file in the wiki repository, then send the file.
+ # - If we know the user wants to create a new page with the given `id`,
+ # then display a create form.
+ # - Otherwise show the empty wiki page and invite the user to create a page.
def show
- view_param = @project_wiki.empty? ? params[:view] : 'create'
-
if @page
set_encoding_error unless valid_encoding?
render 'show'
elsif file_blob
send_blob(@project_wiki.repository, file_blob)
- elsif can?(current_user, :create_wiki, @project) && view_param == 'create'
- @page = build_page(title: params[:id])
+ elsif show_create_form?
+ # Assign a title to the WikiPage unless `id` is a randomly generated slug from #new
+ title = params[:id] unless params[:random_title].present?
+
+ @page = build_page(title: title)
render 'edit'
else
@@ -109,6 +122,15 @@ class Projects::WikisController < Projects::ApplicationController
private
+ def show_create_form?
+ can?(current_user, :create_wiki, @project) &&
+ @page.nil? &&
+ # Always show the create form when the wiki has had at least one page created.
+ # Otherwise, we only show the form when the user has navigated from
+ # the 'empty wiki' page
+ (@project_wiki.exists? || params[:view] == 'create')
+ end
+
def load_project_wiki
@project_wiki = load_wiki
@@ -134,7 +156,7 @@ class Projects::WikisController < Projects::ApplicationController
params.require(:wiki).permit(:title, :content, :format, :message, :last_commit_sha)
end
- def build_page(args)
+ def build_page(args = {})
WikiPage.new(@project_wiki).tap do |page|
page.update_attributes(args) # rubocop:disable Rails/ActiveRecordAliases
end
diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb
index feefc7f8137..5f335de4d6b 100644
--- a/app/controllers/projects_controller.rb
+++ b/app/controllers/projects_controller.rb
@@ -18,15 +18,18 @@ class ProjectsController < Projects::ApplicationController
before_action :redirect_git_extension, only: [:show]
before_action :project, except: [:index, :new, :create, :resolve]
before_action :repository, except: [:index, :new, :create, :resolve]
- before_action :assign_ref_vars, only: [:show], if: :repo_exists?
- before_action :tree, only: [:show], if: [:repo_exists?, :project_view_files?]
- before_action :lfs_blob_ids, only: [:show], if: [:repo_exists?, :project_view_files?]
+ before_action :assign_ref_vars, if: -> { action_name == 'show' && repo_exists? }
+ before_action :tree,
+ if: -> { action_name == 'show' && repo_exists? && project_view_files? }
+ before_action :lfs_blob_ids,
+ if: -> { action_name == 'show' && repo_exists? && project_view_files? }
before_action :project_export_enabled, only: [:export, :download_export, :remove_export, :generate_new_export]
before_action :present_project, only: [:edit]
before_action :authorize_download_code!, only: [:refs]
# Authorize
before_action :authorize_admin_project!, only: [:edit, :update, :housekeeping, :download_export, :export, :remove_export, :generate_new_export]
+ before_action :authorize_archive_project!, only: [:archive, :unarchive]
before_action :event_filter, only: [:show, :activity]
layout :determine_layout
@@ -162,8 +165,6 @@ class ProjectsController < Projects::ApplicationController
end
def archive
- return access_denied! unless can?(current_user, :archive_project, @project)
-
::Projects::UpdateService.new(@project, current_user, archived: true).execute
respond_to do |format|
@@ -172,8 +173,6 @@ class ProjectsController < Projects::ApplicationController
end
def unarchive
- return access_denied! unless can?(current_user, :archive_project, @project)
-
::Projects::UpdateService.new(@project, current_user, archived: false).execute
respond_to do |format|
@@ -282,6 +281,18 @@ class ProjectsController < Projects::ApplicationController
end
# rubocop: enable CodeReuse/ActiveRecord
+ def resolve
+ @project = Project.find(params[:id])
+
+ if can?(current_user, :read_project, @project)
+ redirect_to @project
+ else
+ render_404
+ end
+ end
+
+ private
+
# Render project landing depending of which features are available
# So if page is not available in the list it renders the next page
#
@@ -347,6 +358,7 @@ class ProjectsController < Projects::ApplicationController
:container_registry_enabled,
:default_branch,
:description,
+ :emails_disabled,
:external_authorization_classification_label,
:import_url,
:issues_tracker,
@@ -451,14 +463,4 @@ class ProjectsController < Projects::ApplicationController
def present_project
@project = @project.present(current_user: current_user)
end
-
- def resolve
- @project = Project.find(params[:id])
-
- if can?(current_user, :read_project, @project)
- redirect_to @project
- else
- render_404
- end
- end
end
diff --git a/app/controllers/registrations_controller.rb b/app/controllers/registrations_controller.rb
index b2b151bbcf0..e773ec09924 100644
--- a/app/controllers/registrations_controller.rb
+++ b/app/controllers/registrations_controller.rb
@@ -4,12 +4,12 @@ class RegistrationsController < Devise::RegistrationsController
include Recaptcha::Verify
include AcceptsPendingInvitations
include RecaptchaExperimentHelper
+ include InvisibleCaptcha
prepend_before_action :check_captcha, only: :create
before_action :whitelist_query_limiting, only: [:destroy]
before_action :ensure_terms_accepted,
- if: -> { Gitlab::CurrentSettings.current_application_settings.enforce_terms? },
- only: [:create]
+ if: -> { action_name == 'create' && Gitlab::CurrentSettings.current_application_settings.enforce_terms? }
def new
redirect_to(new_user_session_path)
@@ -69,12 +69,12 @@ class RegistrationsController < Devise::RegistrationsController
def after_sign_up_path_for(user)
Gitlab::AppLogger.info(user_created_message(confirmed: user.confirmed?))
- user.confirmed? ? stored_location_for(user) || dashboard_projects_path : users_almost_there_path
+ confirmed_or_unconfirmed_access_allowed(user) ? stored_location_or_dashboard(user) : users_almost_there_path
end
def after_inactive_sign_up_path_for(resource)
Gitlab::AppLogger.info(user_created_message)
- users_almost_there_path
+ Feature.enabled?(:soft_email_confirmation) ? dashboard_projects_path : users_almost_there_path
end
private
@@ -135,4 +135,12 @@ class RegistrationsController < Devise::RegistrationsController
def terms_accepted?
Gitlab::Utils.to_boolean(params[:terms_opt_in])
end
+
+ def confirmed_or_unconfirmed_access_allowed(user)
+ user.confirmed? || Feature.enabled?(:soft_email_confirmation)
+ end
+
+ def stored_location_or_dashboard(user)
+ stored_location_for(user) || dashboard_projects_path
+ end
end
diff --git a/app/controllers/search_controller.rb b/app/controllers/search_controller.rb
index 8c674be58c5..e30935be4b6 100644
--- a/app/controllers/search_controller.rb
+++ b/app/controllers/search_controller.rb
@@ -31,9 +31,20 @@ class SearchController < ApplicationController
render_commits if @scope == 'commits'
eager_load_user_status if @scope == 'users'
+ increment_navbar_searches_counter
+
check_single_commit_result
end
+ def count
+ params.require([:search, :scope])
+
+ scope = search_service.scope
+ count = search_service.search_results.formatted_count(scope)
+
+ render json: { count: count }
+ end
+
# rubocop: disable CodeReuse/ActiveRecord
def autocomplete
term = params[:term]
@@ -70,4 +81,10 @@ class SearchController < ApplicationController
redirect_to project_commit_path(@project, only_commit) if found_by_commit_sha
end
end
+
+ def increment_navbar_searches_counter
+ return if params[:nav_source] != 'navbar'
+
+ Gitlab::UsageDataCounters::SearchCounter.increment_navbar_searches_count
+ end
end
diff --git a/app/controllers/sessions_controller.rb b/app/controllers/sessions_controller.rb
index a841859621e..1880bead3ee 100644
--- a/app/controllers/sessions_controller.rb
+++ b/app/controllers/sessions_controller.rb
@@ -13,20 +13,30 @@ class SessionsController < Devise::SessionsController
prepend_before_action :check_initial_setup, only: [:new]
prepend_before_action :authenticate_with_two_factor,
- if: :two_factor_enabled?, only: [:create]
+ if: -> { action_name == 'create' && two_factor_enabled? }
prepend_before_action :check_captcha, only: [:create]
prepend_before_action :store_redirect_uri, only: [:new]
prepend_before_action :ldap_servers, only: [:new, :create]
prepend_before_action :require_no_authentication_without_flash, only: [:new, :create]
- prepend_before_action :ensure_password_authentication_enabled!, if: :password_based_login?, only: [:create]
+ prepend_before_action :ensure_password_authentication_enabled!, if: -> { action_name == 'create' && password_based_login? }
before_action :auto_sign_in_with_provider, only: [:new]
before_action :load_recaptcha
- after_action :log_failed_login, only: [:new], if: :failed_login?
-
+ after_action :log_failed_login, if: -> { action_name == 'new' && failed_login? }
helper_method :captcha_enabled?
+ # protect_from_forgery is already prepended in ApplicationController but
+ # authenticate_with_two_factor which signs in the user is prepended before
+ # that here.
+ # We need to make sure CSRF token is verified before authenticating the user
+ # because Devise.clean_up_csrf_token_on_authentication is set to true by
+ # default to avoid CSRF token fixation attacks. Authenticating the user first
+ # would cause the CSRF token to be cleared and then
+ # RequestForgeryProtection#verify_authenticity_token would fail because of
+ # token mismatch.
+ protect_from_forgery with: :exception, prepend: true
+
CAPTCHA_HEADER = 'X-GitLab-Show-Login-Captcha'.freeze
def new
diff --git a/app/controllers/snippets/notes_controller.rb b/app/controllers/snippets/notes_controller.rb
index 612897f27e6..551b37cb3d3 100644
--- a/app/controllers/snippets/notes_controller.rb
+++ b/app/controllers/snippets/notes_controller.rb
@@ -27,7 +27,9 @@ class Snippets::NotesController < ApplicationController
alias_method :noteable, :snippet
def finder_params
- params.merge(last_fetched_at: last_fetched_at, target_id: snippet.id, target_type: 'personal_snippet')
+ params.merge(last_fetched_at: last_fetched_at, target_id: snippet.id, target_type: 'personal_snippet').tap do |merged_params|
+ merged_params[:project] = project if respond_to?(:project)
+ end
end
def authorize_read_snippet!
diff --git a/app/controllers/snippets_controller.rb b/app/controllers/snippets_controller.rb
index fad036b8df8..869655e9550 100644
--- a/app/controllers/snippets_controller.rb
+++ b/app/controllers/snippets_controller.rb
@@ -8,7 +8,8 @@ class SnippetsController < ApplicationController
include RendersBlob
include PreviewMarkdown
- skip_before_action :verify_authenticity_token, only: [:show], if: :js_request?
+ skip_before_action :verify_authenticity_token,
+ if: -> { action_name == 'show' && js_request? }
before_action :snippet, only: [:show, :edit, :destroy, :update, :raw]
diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb
index 072d62ddf38..91e0efcf45f 100644
--- a/app/controllers/users_controller.rb
+++ b/app/controllers/users_controller.rb
@@ -17,7 +17,7 @@ class UsersController < ApplicationController
prepend_before_action(only: [:show]) { authenticate_sessionless_user!(:rss) }
before_action :user, except: [:exists]
before_action :authorize_read_user_profile!,
- only: [:calendar, :calendar_activities, :groups, :projects, :contributed_projects, :snippets]
+ only: [:calendar, :calendar_activities, :groups, :projects, :contributed_projects, :starred_projects, :snippets]
def show
respond_to do |format|
@@ -57,27 +57,30 @@ class UsersController < ApplicationController
def projects
load_projects
- skip_pagination = Gitlab::Utils.to_boolean(params[:skip_pagination])
- skip_namespace = Gitlab::Utils.to_boolean(params[:skip_namespace])
- compact_mode = Gitlab::Utils.to_boolean(params[:compact_mode])
-
- respond_to do |format|
- format.html { render 'show' }
- format.json do
- pager_json("shared/projects/_list", @projects.count, projects: @projects, skip_pagination: skip_pagination, skip_namespace: skip_namespace, compact_mode: compact_mode)
- end
- end
+ present_projects(@projects)
end
def contributed
load_contributed_projects
+ present_projects(@contributed_projects)
+ end
+
+ def starred
+ load_starred_projects
+
+ present_projects(@starred_projects)
+ end
+
+ def present_projects(projects)
+ skip_pagination = Gitlab::Utils.to_boolean(params[:skip_pagination])
+ skip_namespace = Gitlab::Utils.to_boolean(params[:skip_namespace])
+ compact_mode = Gitlab::Utils.to_boolean(params[:compact_mode])
+
respond_to do |format|
format.html { render 'show' }
format.json do
- render json: {
- html: view_to_html_string("shared/projects/_list", projects: @contributed_projects)
- }
+ pager_json("shared/projects/_list", projects.count, projects: projects, skip_pagination: skip_pagination, skip_namespace: skip_namespace, compact_mode: compact_mode)
end
end
end
@@ -120,6 +123,10 @@ class UsersController < ApplicationController
ContributedProjectsFinder.new(user).execute(current_user)
end
+ def starred_projects
+ StarredProjectsFinder.new(user, current_user: current_user).execute
+ end
+
def contributions_calendar
@contributions_calendar ||= Gitlab::ContributionsCalendar.new(user, current_user)
end
@@ -145,6 +152,12 @@ class UsersController < ApplicationController
prepare_projects_for_rendering(@contributed_projects)
end
+ def load_starred_projects
+ @starred_projects = starred_projects
+
+ prepare_projects_for_rendering(@starred_projects)
+ end
+
def load_groups
@groups = JoinedGroupsFinder.new(user).execute(current_user)