summaryrefslogtreecommitdiff
path: root/app/controllers
diff options
context:
space:
mode:
authorLin Jen-Shin <godfat@godfat.org>2017-05-23 02:10:29 +0800
committerLin Jen-Shin <godfat@godfat.org>2017-05-23 02:10:29 +0800
commit1a4130d3a6cfb4956f8bb1186cc499ea549d8e18 (patch)
tree076adcb3e6f3800a1a7bbc6809839d5cb3b3f372 /app/controllers
parent3c8a6fba67998eb17240b15db85f8d1c8aff338e (diff)
parent18a6d9c5326bc2b90a1f0cc8664d638a39885924 (diff)
downloadgitlab-ce-27377-preload-pipeline-entity.tar.gz
Merge remote-tracking branch 'upstream/master' into 27377-preload-pipeline-entity27377-preload-pipeline-entity
* upstream/master: (2534 commits) Update VERSION to 9.3.0-pre Update CHANGELOG.md for 9.2.0 removes unnecessary redundacy in usage ping doc Respect the typo as rubocop said Add a test to ensure this works on MySQL Change pipelines schedules help page path change domain to hostname in usage ping doc Fixes broken MySQL migration for retried Show password field mask while editing service settings Add notes for supported schedulers and cloud providers Move environment monitoring to environments doc Add docs for change of Cache/Artifact restore order" Avoid resource intensive login checks if password is not provided Change translation for 'coding' by 'desarrollo' for Spanish Add to docs: issues multiple assignees rename "Add emoji" and "Award emoji" to "Add reaction" where appropriate Add project and group notification settings info 32570 Fix border-bottom for project activity tab Add users endpoint to frontend API class Rename users on mysql ...
Diffstat (limited to 'app/controllers')
-rw-r--r--app/controllers/admin/abuse_reports_controller.rb1
-rw-r--r--app/controllers/admin/application_controller.rb2
-rw-r--r--app/controllers/admin/application_settings_controller.rb16
-rw-r--r--app/controllers/admin/cohorts_controller.rb11
-rw-r--r--app/controllers/admin/groups_controller.rb14
-rw-r--r--app/controllers/admin/hooks_controller.rb27
-rw-r--r--app/controllers/admin/impersonations_controller.rb2
-rw-r--r--app/controllers/admin/projects_controller.rb1
-rw-r--r--app/controllers/admin/services_controller.rb2
-rw-r--r--app/controllers/admin/spam_logs_controller.rb2
-rw-r--r--app/controllers/application_controller.rb46
-rw-r--r--app/controllers/autocomplete_controller.rb2
-rw-r--r--app/controllers/concerns/continue_params.rb1
-rw-r--r--app/controllers/concerns/creates_commit.rb62
-rw-r--r--app/controllers/concerns/enforces_two_factor_authentication.rb58
-rw-r--r--app/controllers/concerns/filter_projects.rb17
-rw-r--r--app/controllers/concerns/issuable_actions.rb12
-rw-r--r--app/controllers/concerns/issuable_collections.rb7
-rw-r--r--app/controllers/concerns/lfs_request.rb6
-rw-r--r--app/controllers/concerns/membership_actions.rb42
-rw-r--r--app/controllers/concerns/milestone_actions.rb53
-rw-r--r--app/controllers/concerns/notes_actions.rb180
-rw-r--r--app/controllers/concerns/params_backward_compatibility.rb7
-rw-r--r--app/controllers/concerns/renders_blob.rb24
-rw-r--r--app/controllers/concerns/renders_notes.rb22
-rw-r--r--app/controllers/concerns/requires_health_token.rb25
-rw-r--r--app/controllers/concerns/routable_actions.rb38
-rw-r--r--app/controllers/concerns/service_params.rb1
-rw-r--r--app/controllers/concerns/snippets_actions.rb4
-rw-r--r--app/controllers/concerns/toggle_award_emoji.rb3
-rw-r--r--app/controllers/concerns/uploads_actions.rb27
-rw-r--r--app/controllers/dashboard/labels_controller.rb2
-rw-r--r--app/controllers/dashboard/projects_controller.rb27
-rw-r--r--app/controllers/dashboard/snippets_controller.rb7
-rw-r--r--app/controllers/dashboard/todos_controller.rb2
-rw-r--r--app/controllers/explore/groups_controller.rb2
-rw-r--r--app/controllers/explore/projects_controller.rb34
-rw-r--r--app/controllers/explore/snippets_controller.rb2
-rw-r--r--app/controllers/groups/application_controller.rb31
-rw-r--r--app/controllers/groups/group_members_controller.rb25
-rw-r--r--app/controllers/groups/labels_controller.rb2
-rw-r--r--app/controllers/groups/milestones_controller.rb4
-rw-r--r--app/controllers/groups_controller.rb27
-rw-r--r--app/controllers/health_check_controller.rb21
-rw-r--r--app/controllers/health_controller.rb60
-rw-r--r--app/controllers/import/base_controller.rb28
-rw-r--r--app/controllers/jwt_controller.rb2
-rw-r--r--app/controllers/omniauth_callbacks_controller.rb2
-rw-r--r--app/controllers/profiles/accounts_controller.rb13
-rw-r--r--app/controllers/profiles/preferences_controller.rb2
-rw-r--r--app/controllers/profiles/two_factor_auths_controller.rb25
-rw-r--r--app/controllers/profiles_controller.rb3
-rw-r--r--app/controllers/projects/application_controller.rb69
-rw-r--r--app/controllers/projects/artifacts_controller.rb36
-rw-r--r--app/controllers/projects/blob_controller.rb49
-rw-r--r--app/controllers/projects/boards/issues_controller.rb2
-rw-r--r--app/controllers/projects/branches_controller.rb47
-rw-r--r--app/controllers/projects/builds_controller.rb84
-rw-r--r--app/controllers/projects/commit_controller.rb34
-rw-r--r--app/controllers/projects/compare_controller.rb1
-rw-r--r--app/controllers/projects/container_registry_controller.rb34
-rw-r--r--app/controllers/projects/deploy_keys_controller.rb20
-rw-r--r--app/controllers/projects/deployments_controller.rb34
-rw-r--r--app/controllers/projects/discussions_controller.rb2
-rw-r--r--app/controllers/projects/environments_controller.rb18
-rw-r--r--app/controllers/projects/forks_controller.rb2
-rw-r--r--app/controllers/projects/git_http_controller.rb8
-rw-r--r--app/controllers/projects/hooks_controller.rb17
-rw-r--r--app/controllers/projects/issues_controller.rb78
-rw-r--r--app/controllers/projects/labels_controller.rb2
-rw-r--r--app/controllers/projects/lfs_api_controller.rb4
-rw-r--r--[-rwxr-xr-x]app/controllers/projects/merge_requests_controller.rb309
-rw-r--r--app/controllers/projects/milestones_controller.rb9
-rw-r--r--app/controllers/projects/notes_controller.rb175
-rw-r--r--app/controllers/projects/pages_controller.rb1
-rw-r--r--app/controllers/projects/pages_domains_controller.rb1
-rw-r--r--app/controllers/projects/pipeline_schedules_controller.rb68
-rw-r--r--app/controllers/projects/pipelines_controller.rb80
-rw-r--r--app/controllers/projects/pipelines_settings_controller.rb4
-rw-r--r--app/controllers/projects/project_members_controller.rb24
-rw-r--r--app/controllers/projects/protected_branches_controller.rb57
-rw-r--r--app/controllers/projects/protected_refs_controller.rb47
-rw-r--r--app/controllers/projects/protected_tags_controller.rb23
-rw-r--r--app/controllers/projects/raw_controller.rb2
-rw-r--r--app/controllers/projects/registry/application_controller.rb16
-rw-r--r--app/controllers/projects/registry/repositories_controller.rb43
-rw-r--r--app/controllers/projects/registry/tags_controller.rb28
-rw-r--r--app/controllers/projects/settings/integrations_controller.rb2
-rw-r--r--app/controllers/projects/settings/repository_controller.rb48
-rw-r--r--app/controllers/projects/snippets_controller.rb27
-rw-r--r--app/controllers/projects/tags_controller.rb6
-rw-r--r--app/controllers/projects/tree_controller.rb10
-rw-r--r--app/controllers/projects/triggers_controller.rb15
-rw-r--r--app/controllers/projects/uploads_controller.rb32
-rw-r--r--app/controllers/projects/wikis_controller.rb16
-rw-r--r--app/controllers/projects_controller.rb45
-rw-r--r--app/controllers/registrations_controller.rb6
-rw-r--r--app/controllers/search_controller.rb40
-rw-r--r--app/controllers/sessions_controller.rb9
-rw-r--r--app/controllers/snippets/notes_controller.rb35
-rw-r--r--app/controllers/snippets_controller.rb67
-rw-r--r--app/controllers/unicorn_test_controller.rb12
-rw-r--r--app/controllers/uploads_controller.rb84
-rw-r--r--app/controllers/users_controller.rb22
104 files changed, 1876 insertions, 1064 deletions
diff --git a/app/controllers/admin/abuse_reports_controller.rb b/app/controllers/admin/abuse_reports_controller.rb
index 5055c318a5f..dc9a6df5f75 100644
--- a/app/controllers/admin/abuse_reports_controller.rb
+++ b/app/controllers/admin/abuse_reports_controller.rb
@@ -1,6 +1,7 @@
class Admin::AbuseReportsController < Admin::ApplicationController
def index
@abuse_reports = AbuseReport.order(id: :desc).page(params[:page])
+ @abuse_reports.includes(:reporter, :user)
end
def destroy
diff --git a/app/controllers/admin/application_controller.rb b/app/controllers/admin/application_controller.rb
index cf795d977ce..a4648b33cfa 100644
--- a/app/controllers/admin/application_controller.rb
+++ b/app/controllers/admin/application_controller.rb
@@ -6,6 +6,6 @@ class Admin::ApplicationController < ApplicationController
layout 'admin'
def authenticate_admin!
- render_404 unless current_user.is_admin?
+ render_404 unless current_user.admin?
end
end
diff --git a/app/controllers/admin/application_settings_controller.rb b/app/controllers/admin/application_settings_controller.rb
index 0bfbe47eb4f..152d7baad49 100644
--- a/app/controllers/admin/application_settings_controller.rb
+++ b/app/controllers/admin/application_settings_controller.rb
@@ -17,6 +17,18 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController
end
end
+ def usage_data
+ respond_to do |format|
+ format.html do
+ usage_data = Gitlab::UsageData.data
+ usage_data_json = params[:pretty] ? JSON.pretty_generate(usage_data) : usage_data.to_json
+
+ render html: Gitlab::Highlight.highlight('payload.json', usage_data_json)
+ end
+ format.json { render json: Gitlab::UsageData.to_json }
+ end
+ end
+
def reset_runners_token
@application_setting.reset_runners_registration_token!
flash[:notice] = 'New runners registration token has been generated!'
@@ -121,6 +133,8 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController
:signup_enabled,
:sentry_dsn,
:sentry_enabled,
+ :clientside_sentry_dsn,
+ :clientside_sentry_enabled,
:send_user_confirmation_email,
:shared_runners_enabled,
:shared_runners_text,
@@ -134,6 +148,8 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController
:unique_ips_limit_enabled,
:version_check_enabled,
:terminal_max_session_time,
+ :polling_interval_multiplier,
+ :usage_ping_enabled,
disabled_oauth_sign_in_sources: [],
import_sources: [],
diff --git a/app/controllers/admin/cohorts_controller.rb b/app/controllers/admin/cohorts_controller.rb
new file mode 100644
index 00000000000..9b77c554908
--- /dev/null
+++ b/app/controllers/admin/cohorts_controller.rb
@@ -0,0 +1,11 @@
+class Admin::CohortsController < Admin::ApplicationController
+ def index
+ if current_application_settings.usage_ping_enabled
+ cohorts_results = Rails.cache.fetch('cohorts', expires_in: 1.day) do
+ CohortsService.new.execute
+ end
+
+ @cohorts = CohortsSerializer.new.represent(cohorts_results)
+ end
+ end
+end
diff --git a/app/controllers/admin/groups_controller.rb b/app/controllers/admin/groups_controller.rb
index cea3d088e94..5885b3543bb 100644
--- a/app/controllers/admin/groups_controller.rb
+++ b/app/controllers/admin/groups_controller.rb
@@ -28,7 +28,7 @@ class Admin::GroupsController < Admin::ApplicationController
if @group.save
@group.add_owner(current_user)
- redirect_to [:admin, @group], notice: 'Group was successfully created.'
+ redirect_to [:admin, @group], notice: "Group '#{@group.name}' was successfully created."
else
render "new"
end
@@ -43,9 +43,13 @@ class Admin::GroupsController < Admin::ApplicationController
end
def members_update
- @group.add_users(params[:user_ids].split(','), params[:access_level], current_user: current_user)
+ status = Members::CreateService.new(@group, current_user, params).execute
- redirect_to [:admin, @group], notice: 'Users were successfully added.'
+ if status
+ redirect_to [:admin, @group], notice: 'Users were successfully added.'
+ else
+ redirect_to [:admin, @group], alert: 'No users specified.'
+ end
end
def destroy
@@ -72,7 +76,9 @@ class Admin::GroupsController < Admin::ApplicationController
:name,
:path,
:request_access_enabled,
- :visibility_level
+ :visibility_level,
+ :require_two_factor_authentication,
+ :two_factor_grace_period
]
end
end
diff --git a/app/controllers/admin/hooks_controller.rb b/app/controllers/admin/hooks_controller.rb
index cbfc4581411..ccfe553c89e 100644
--- a/app/controllers/admin/hooks_controller.rb
+++ b/app/controllers/admin/hooks_controller.rb
@@ -1,4 +1,6 @@
class Admin::HooksController < Admin::ApplicationController
+ before_action :hook, only: :edit
+
def index
@hooks = SystemHook.all
@hook = SystemHook.new
@@ -15,15 +17,25 @@ class Admin::HooksController < Admin::ApplicationController
end
end
+ def edit
+ end
+
+ def update
+ if hook.update_attributes(hook_params)
+ flash[:notice] = 'System hook was successfully updated.'
+ redirect_to admin_hooks_path
+ else
+ render 'edit'
+ end
+ end
+
def destroy
- @hook = SystemHook.find(params[:id])
- @hook.destroy
+ hook.destroy
redirect_to admin_hooks_path
end
def test
- @hook = SystemHook.find(params[:hook_id])
data = {
event_name: "project_create",
name: "Ruby",
@@ -32,16 +44,23 @@ class Admin::HooksController < Admin::ApplicationController
owner_name: "Someone",
owner_email: "example@gitlabhq.com"
}
- @hook.execute(data, 'system_hooks')
+ hook.execute(data, 'system_hooks')
redirect_back_or_default
end
+ private
+
+ def hook
+ @hook ||= SystemHook.find(params[:id])
+ end
+
def hook_params
params.require(:hook).permit(
:enable_ssl_verification,
:push_events,
:tag_push_events,
+ :repository_update_events,
:token,
:url
)
diff --git a/app/controllers/admin/impersonations_controller.rb b/app/controllers/admin/impersonations_controller.rb
index 9433da02f64..8e7adc06584 100644
--- a/app/controllers/admin/impersonations_controller.rb
+++ b/app/controllers/admin/impersonations_controller.rb
@@ -21,6 +21,6 @@ class Admin::ImpersonationsController < Admin::ApplicationController
end
def authenticate_impersonator!
- render_404 unless impersonator && impersonator.is_admin? && !impersonator.blocked?
+ render_404 unless impersonator && impersonator.admin? && !impersonator.blocked?
end
end
diff --git a/app/controllers/admin/projects_controller.rb b/app/controllers/admin/projects_controller.rb
index daecfc832bf..a1975c0e341 100644
--- a/app/controllers/admin/projects_controller.rb
+++ b/app/controllers/admin/projects_controller.rb
@@ -3,6 +3,7 @@ class Admin::ProjectsController < Admin::ApplicationController
before_action :group, only: [:show, :transfer]
def index
+ params[:sort] ||= 'latest_activity_desc'
@projects = Project.with_statistics
@projects = @projects.in_namespace(params[:namespace_id]) if params[:namespace_id].present?
@projects = @projects.where(visibility_level: params[:visibility_level]) if params[:visibility_level].present?
diff --git a/app/controllers/admin/services_controller.rb b/app/controllers/admin/services_controller.rb
index 37a1a23178e..4c3d336b3af 100644
--- a/app/controllers/admin/services_controller.rb
+++ b/app/controllers/admin/services_controller.rb
@@ -16,6 +16,8 @@ class Admin::ServicesController < Admin::ApplicationController
def update
if service.update_attributes(service_params[:service])
+ PropagateServiceTemplateWorker.perform_async(service.id) if service.active?
+
redirect_to admin_application_settings_services_path,
notice: 'Application settings saved successfully'
else
diff --git a/app/controllers/admin/spam_logs_controller.rb b/app/controllers/admin/spam_logs_controller.rb
index 2abfa22712d..1d66955bb71 100644
--- a/app/controllers/admin/spam_logs_controller.rb
+++ b/app/controllers/admin/spam_logs_controller.rb
@@ -7,7 +7,7 @@ class Admin::SpamLogsController < Admin::ApplicationController
spam_log = SpamLog.find(params[:id])
if params[:remove_user]
- spam_log.remove_user
+ spam_log.remove_user(deleted_by: current_user)
redirect_to admin_spam_logs_path, notice: "User #{spam_log.user.username} was successfully removed."
else
spam_log.destroy
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index 6a6e335d314..8ce9150e4a9 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -8,12 +8,12 @@ class ApplicationController < ActionController::Base
include PageLayoutHelper
include SentryHelper
include WorkhorseHelper
+ include EnforcesTwoFactorAuthentication
before_action :authenticate_user_from_private_token!
before_action :authenticate_user!
before_action :validate_user_service_ticket!
before_action :check_password_expiration
- before_action :check_2fa_requirement
before_action :ldap_security_check
before_action :sentry_context
before_action :default_headers
@@ -21,6 +21,8 @@ class ApplicationController < ActionController::Base
before_action :configure_permitted_parameters, if: :devise_controller?
before_action :require_email, unless: :devise_controller?
+ around_action :set_locale
+
protect_from_forgery with: :exception
helper_method :can?, :current_application_settings
@@ -56,7 +58,7 @@ class ApplicationController < ActionController::Base
if current_user
not_found
else
- redirect_to new_user_session_path
+ authenticate_user!
end
end
@@ -98,7 +100,10 @@ class ApplicationController < ActionController::Base
end
def access_denied!
- render "errors/access_denied", layout: "errors", status: 404
+ respond_to do |format|
+ format.json { head :not_found }
+ format.any { render "errors/access_denied", layout: "errors", status: 404 }
+ end
end
def git_not_found!
@@ -118,6 +123,10 @@ class ApplicationController < ActionController::Base
end
end
+ def respond_422
+ head :unprocessable_entity
+ end
+
def no_cache_headers
response.headers["Cache-Control"] = "no-cache, no-store, max-age=0, must-revalidate"
response.headers["Pragma"] = "no-cache"
@@ -151,12 +160,6 @@ class ApplicationController < ActionController::Base
end
end
- def check_2fa_requirement
- if two_factor_authentication_required? && current_user && !current_user.two_factor_enabled? && !skip_two_factor?
- redirect_to profile_two_factor_auth_path
- end
- end
-
def ldap_security_check
if current_user && current_user.requires_ldap_check?
return unless current_user.try_obtain_ldap_lease
@@ -265,27 +268,18 @@ class ApplicationController < ActionController::Base
current_application_settings.import_sources.include?('gitlab_project')
end
- def two_factor_authentication_required?
- current_application_settings.require_two_factor_authentication
- end
-
- def two_factor_grace_period
- current_application_settings.two_factor_grace_period
- end
-
- def two_factor_grace_period_expired?
- date = current_user.otp_grace_period_started_at
- date && (date + two_factor_grace_period.hours) < Time.current
- end
-
- def skip_two_factor?
- session[:skip_tfa] && session[:skip_tfa] > Time.current
- end
-
# U2F (universal 2nd factor) devices need a unique identifier for the application
# to perform authentication.
# https://developers.yubico.com/U2F/App_ID.html
def u2f_app_id
request.base_url
end
+
+ def set_locale
+ Gitlab::I18n.set_locale(current_user)
+
+ yield
+ ensure
+ Gitlab::I18n.reset_locale
+ end
end
diff --git a/app/controllers/autocomplete_controller.rb b/app/controllers/autocomplete_controller.rb
index b79ca034c5b..e2f5aa8508e 100644
--- a/app/controllers/autocomplete_controller.rb
+++ b/app/controllers/autocomplete_controller.rb
@@ -41,7 +41,7 @@ class AutocompleteController < ApplicationController
no_project = {
id: 0,
- name_with_namespace: 'No project',
+ name_with_namespace: 'No project'
}
projects.unshift(no_project) unless params[:offset_id].present?
diff --git a/app/controllers/concerns/continue_params.rb b/app/controllers/concerns/continue_params.rb
index 0a995c45bdf..eb3a623acdd 100644
--- a/app/controllers/concerns/continue_params.rb
+++ b/app/controllers/concerns/continue_params.rb
@@ -7,6 +7,7 @@ module ContinueParams
continue_params = continue_params.permit(:to, :notice, :notice_now)
return unless continue_params[:to] && continue_params[:to].start_with?('/')
+ return if continue_params[:to].start_with?('//')
continue_params
end
diff --git a/app/controllers/concerns/creates_commit.rb b/app/controllers/concerns/creates_commit.rb
index 9ac8197e45a..183eb00ef67 100644
--- a/app/controllers/concerns/creates_commit.rb
+++ b/app/controllers/concerns/creates_commit.rb
@@ -1,17 +1,29 @@
module CreatesCommit
extend ActiveSupport::Concern
+ def set_start_branch_to_branch_name
+ branch_exists = @repository.find_branch(@branch_name)
+ @start_branch = @branch_name if branch_exists
+ end
+
def create_commit(service, success_path:, failure_path:, failure_view: nil, success_notice: nil)
- set_commit_variables
+ if can?(current_user, :push_code, @project)
+ @project_to_commit_into = @project
+ @branch_name ||= @ref
+ else
+ @project_to_commit_into = current_user.fork_of(@project)
+ @branch_name ||= @project_to_commit_into.repository.next_branch('patch')
+ end
+
+ @start_branch ||= @ref || @branch_name
commit_params = @commit_params.merge(
- start_project: @mr_target_project,
- start_branch: @mr_target_branch,
- target_branch: @mr_source_branch
+ start_project: @project,
+ start_branch: @start_branch,
+ branch_name: @branch_name
)
- result = service.new(
- @mr_source_project, current_user, commit_params).execute
+ result = service.new(@project_to_commit_into, current_user, commit_params).execute
if result[:status] == :success
update_flash_notice(success_notice)
@@ -72,30 +84,30 @@ module CreatesCommit
def new_merge_request_path
new_namespace_project_merge_request_path(
- @mr_source_project.namespace,
- @mr_source_project,
+ @project_to_commit_into.namespace,
+ @project_to_commit_into,
merge_request: {
- source_project_id: @mr_source_project.id,
- target_project_id: @mr_target_project.id,
- source_branch: @mr_source_branch,
- target_branch: @mr_target_branch
+ source_project_id: @project_to_commit_into.id,
+ target_project_id: @project.id,
+ source_branch: @branch_name,
+ target_branch: @start_branch
}
)
end
def existing_merge_request_path
- namespace_project_merge_request_path(@mr_target_project.namespace, @mr_target_project, @merge_request)
+ namespace_project_merge_request_path(@project.namespace, @project, @merge_request)
end
def merge_request_exists?
return @merge_request if defined?(@merge_request)
- @merge_request = MergeRequestsFinder.new(current_user, project_id: @mr_target_project.id).execute.opened.
- find_by(source_branch: @mr_source_branch, target_branch: @mr_target_branch, source_project_id: @mr_source_project)
+ @merge_request = MergeRequestsFinder.new(current_user, project_id: @project.id).execute.opened.
+ find_by(source_project_id: @project_to_commit_into, source_branch: @branch_name, target_branch: @start_branch)
end
def different_project?
- @mr_source_project != @mr_target_project
+ @project_to_commit_into != @project
end
def create_merge_request?
@@ -103,22 +115,6 @@ module CreatesCommit
# as the target branch in the same project,
# we don't want to create a merge request.
params[:create_merge_request].present? &&
- (different_project? || @mr_target_branch != @mr_source_branch)
- end
-
- def set_commit_variables
- if can?(current_user, :push_code, @project)
- @mr_source_project = @project
- @target_branch ||= @ref
- else
- @mr_source_project = current_user.fork_of(@project)
- @target_branch ||= @mr_source_project.repository.next_branch('patch')
- end
-
- # Merge request to this project
- @mr_target_project = @project
- @mr_target_branch ||= @ref || @target_branch
-
- @mr_source_branch = @target_branch
+ (different_project? || @start_branch != @branch_name)
end
end
diff --git a/app/controllers/concerns/enforces_two_factor_authentication.rb b/app/controllers/concerns/enforces_two_factor_authentication.rb
new file mode 100644
index 00000000000..688e8bd4a37
--- /dev/null
+++ b/app/controllers/concerns/enforces_two_factor_authentication.rb
@@ -0,0 +1,58 @@
+# == EnforcesTwoFactorAuthentication
+#
+# Controller concern to enforce two-factor authentication requirements
+#
+# Upon inclusion, adds `check_two_factor_requirement` as a before_action,
+# and makes `two_factor_grace_period_expired?` and `two_factor_skippable?`
+# available as view helpers.
+module EnforcesTwoFactorAuthentication
+ extend ActiveSupport::Concern
+
+ included do
+ before_action :check_two_factor_requirement
+ helper_method :two_factor_grace_period_expired?, :two_factor_skippable?
+ end
+
+ def check_two_factor_requirement
+ if two_factor_authentication_required? && current_user && !current_user.two_factor_enabled? && !skip_two_factor?
+ redirect_to profile_two_factor_auth_path
+ end
+ end
+
+ def two_factor_authentication_required?
+ current_application_settings.require_two_factor_authentication? ||
+ current_user.try(:require_two_factor_authentication_from_group?)
+ end
+
+ def two_factor_authentication_reason(global: -> {}, group: -> {})
+ if two_factor_authentication_required?
+ if current_application_settings.require_two_factor_authentication?
+ global.call
+ else
+ groups = current_user.expanded_groups_requiring_two_factor_authentication.reorder(name: :asc)
+ group.call(groups)
+ end
+ end
+ end
+
+ def two_factor_grace_period
+ periods = [current_application_settings.two_factor_grace_period]
+ periods << current_user.two_factor_grace_period if current_user.try(:require_two_factor_authentication_from_group?)
+ periods.min
+ end
+
+ def two_factor_grace_period_expired?
+ date = current_user.otp_grace_period_started_at
+ date && (date + two_factor_grace_period.hours) < Time.current
+ end
+
+ def two_factor_skippable?
+ two_factor_authentication_required? &&
+ !current_user.two_factor_enabled? &&
+ !two_factor_grace_period_expired?
+ end
+
+ def skip_two_factor?
+ session[:skip_two_factor] && session[:skip_two_factor] > Time.current
+ end
+end
diff --git a/app/controllers/concerns/filter_projects.rb b/app/controllers/concerns/filter_projects.rb
deleted file mode 100644
index 6014112256a..00000000000
--- a/app/controllers/concerns/filter_projects.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-# == FilterProjects
-#
-# Controller concern to handle projects filtering
-# * by name
-# * by archived state
-#
-module FilterProjects
- extend ActiveSupport::Concern
-
- def filter_projects(projects)
- projects = projects.search(params[:name]) if params[:name].present?
- projects = projects.non_archived if params[:archived].blank?
- projects = projects.personal(current_user) if params[:personal].present? && current_user
-
- projects
- end
-end
diff --git a/app/controllers/concerns/issuable_actions.rb b/app/controllers/concerns/issuable_actions.rb
index 3ccf2a9ce33..4cf645d6341 100644
--- a/app/controllers/concerns/issuable_actions.rb
+++ b/app/controllers/concerns/issuable_actions.rb
@@ -60,7 +60,7 @@ module IssuableActions
end
def bulk_update_params
- params.require(:update).permit(
+ permitted_keys = [
:issuable_ids,
:assignee_id,
:milestone_id,
@@ -69,7 +69,15 @@ module IssuableActions
label_ids: [],
add_label_ids: [],
remove_label_ids: []
- )
+ ]
+
+ if resource_name == 'issue'
+ permitted_keys << { assignee_ids: [] }
+ else
+ permitted_keys.unshift(:assignee_id)
+ end
+
+ params.require(:update).permit(permitted_keys)
end
def resource_name
diff --git a/app/controllers/concerns/issuable_collections.rb b/app/controllers/concerns/issuable_collections.rb
index 85ae4985e58..650ec1e326a 100644
--- a/app/controllers/concerns/issuable_collections.rb
+++ b/app/controllers/concerns/issuable_collections.rb
@@ -15,6 +15,9 @@ module IssuableCollections
# a new order into the collection.
# We cannot use reorder to not mess up the paginated collection.
issuable_ids = issuable_collection.map(&:id)
+
+ return {} if issuable_ids.empty?
+
issuable_note_count = Note.count_for_collection(issuable_ids, @collection_type)
issuable_votes_count = AwardEmoji.votes_for_collection(issuable_ids, @collection_type)
issuable_merge_requests_count =
@@ -40,11 +43,11 @@ module IssuableCollections
end
def issues_collection
- issues_finder.execute.preload(:project, :author, :assignee, :labels, :milestone, project: :namespace)
+ issues_finder.execute.preload(:project, :author, :assignees, :labels, :milestone, project: :namespace)
end
def merge_requests_collection
- merge_requests_finder.execute.preload(:source_project, :target_project, :author, :assignee, :labels, :milestone, :merge_request_diff, target_project: :namespace)
+ merge_requests_finder.execute.preload(:source_project, :target_project, :author, :assignee, :labels, :milestone, :merge_request_diff, :head_pipeline, target_project: :namespace)
end
def issues_finder
diff --git a/app/controllers/concerns/lfs_request.rb b/app/controllers/concerns/lfs_request.rb
index ed22b1e5470..ae91e02488a 100644
--- a/app/controllers/concerns/lfs_request.rb
+++ b/app/controllers/concerns/lfs_request.rb
@@ -23,7 +23,7 @@ module LfsRequest
render(
json: {
message: 'Git LFS is not enabled on this GitLab server, contact your admin.',
- documentation_url: help_url,
+ documentation_url: help_url
},
status: 501
)
@@ -48,7 +48,7 @@ module LfsRequest
render(
json: {
message: 'Access forbidden. Check your access level.',
- documentation_url: help_url,
+ documentation_url: help_url
},
content_type: "application/vnd.git-lfs+json",
status: 403
@@ -59,7 +59,7 @@ module LfsRequest
render(
json: {
message: 'Not found.',
- documentation_url: help_url,
+ documentation_url: help_url
},
content_type: "application/vnd.git-lfs+json",
status: 404
diff --git a/app/controllers/concerns/membership_actions.rb b/app/controllers/concerns/membership_actions.rb
index c13333641d3..b1bacc8ffe5 100644
--- a/app/controllers/concerns/membership_actions.rb
+++ b/app/controllers/concerns/membership_actions.rb
@@ -1,6 +1,32 @@
module MembershipActions
extend ActiveSupport::Concern
+ def create
+ status = Members::CreateService.new(membershipable, current_user, params).execute
+
+ redirect_url = members_page_url
+
+ if status
+ redirect_to redirect_url, notice: 'Users were successfully added.'
+ else
+ redirect_to redirect_url, alert: 'No users specified.'
+ end
+ end
+
+ def destroy
+ Members::DestroyService.new(membershipable, current_user, params).
+ execute(:all)
+
+ respond_to do |format|
+ format.html do
+ message = "User was successfully removed from #{source_type}."
+ redirect_to members_page_url, notice: message
+ end
+
+ format.js { head :ok }
+ end
+ end
+
def request_access
membershipable.request_access(current_user)
@@ -11,20 +37,20 @@ module MembershipActions
def approve_access_request
Members::ApproveAccessRequestService.new(membershipable, current_user, params).execute
- redirect_to polymorphic_url([membershipable, :members])
+ redirect_to members_page_url
end
def leave
member = Members::DestroyService.new(membershipable, current_user, user_id: current_user.id).
execute(:all)
- source_type = membershipable.class.to_s.humanize(capitalize: false)
notice =
if member.request?
"Your access request to the #{source_type} has been withdrawn."
else
"You left the \"#{membershipable.human_name}\" #{source_type}."
end
+
redirect_path = member.request? ? member.source : [:dashboard, membershipable.class.to_s.tableize]
redirect_to redirect_path, notice: notice
@@ -35,4 +61,16 @@ module MembershipActions
def membershipable
raise NotImplementedError
end
+
+ def members_page_url
+ if membershipable.is_a?(Project)
+ project_settings_members_path(membershipable)
+ else
+ polymorphic_url([membershipable, :members])
+ end
+ end
+
+ def source_type
+ @source_type ||= membershipable.class.to_s.humanize(capitalize: false)
+ end
end
diff --git a/app/controllers/concerns/milestone_actions.rb b/app/controllers/concerns/milestone_actions.rb
new file mode 100644
index 00000000000..3e2a0fe4f8b
--- /dev/null
+++ b/app/controllers/concerns/milestone_actions.rb
@@ -0,0 +1,53 @@
+module MilestoneActions
+ extend ActiveSupport::Concern
+
+ def merge_requests
+ respond_to do |format|
+ format.html { redirect_to milestone_redirect_path }
+ format.json do
+ render json: tabs_json("shared/milestones/_merge_requests_tab", {
+ merge_requests: @milestone.merge_requests,
+ show_project_name: true
+ })
+ end
+ end
+ end
+
+ def participants
+ respond_to do |format|
+ format.html { redirect_to milestone_redirect_path }
+ format.json do
+ render json: tabs_json("shared/milestones/_participants_tab", {
+ users: @milestone.participants
+ })
+ end
+ end
+ end
+
+ def labels
+ respond_to do |format|
+ format.html { redirect_to milestone_redirect_path }
+ format.json do
+ render json: tabs_json("shared/milestones/_labels_tab", {
+ labels: @milestone.labels
+ })
+ end
+ end
+ end
+
+ private
+
+ def tabs_json(partial, data = {})
+ {
+ html: view_to_html_string(partial, data)
+ }
+ end
+
+ def milestone_redirect_path
+ if @project
+ namespace_project_milestone_path(@project.namespace, @project, @milestone)
+ else
+ group_milestone_path(@group, @milestone.safe_title, title: @milestone.title)
+ end
+ end
+end
diff --git a/app/controllers/concerns/notes_actions.rb b/app/controllers/concerns/notes_actions.rb
new file mode 100644
index 00000000000..a57d9e6e6c0
--- /dev/null
+++ b/app/controllers/concerns/notes_actions.rb
@@ -0,0 +1,180 @@
+module NotesActions
+ include RendersNotes
+ extend ActiveSupport::Concern
+
+ included do
+ before_action :authorize_admin_note!, only: [:update, :destroy]
+ end
+
+ def index
+ current_fetched_at = Time.now.to_i
+
+ notes_json = { notes: [], last_fetched_at: current_fetched_at }
+
+ @notes = notes_finder.execute.inc_relations_for_view
+ @notes = prepare_notes_for_rendering(@notes)
+
+ @notes.each do |note|
+ next if note.cross_reference_not_visible_for?(current_user)
+
+ notes_json[:notes] << note_json(note)
+ end
+
+ render json: notes_json
+ end
+
+ def create
+ create_params = note_params.merge(
+ merge_request_diff_head_sha: params[:merge_request_diff_head_sha],
+ in_reply_to_discussion_id: params[:in_reply_to_discussion_id]
+ )
+ @note = Notes::CreateService.new(project, current_user, create_params).execute
+
+ if @note.is_a?(Note)
+ Banzai::NoteRenderer.render([@note], @project, current_user)
+ end
+
+ respond_to do |format|
+ format.json { render json: note_json(@note) }
+ format.html { redirect_back_or_default }
+ end
+ end
+
+ def update
+ @note = Notes::UpdateService.new(project, current_user, note_params).execute(note)
+
+ if @note.is_a?(Note)
+ Banzai::NoteRenderer.render([@note], @project, current_user)
+ end
+
+ respond_to do |format|
+ format.json { render json: note_json(@note) }
+ format.html { redirect_back_or_default }
+ end
+ end
+
+ def destroy
+ if note.editable?
+ Notes::DestroyService.new(project, current_user).execute(note)
+ end
+
+ respond_to do |format|
+ format.js { head :ok }
+ end
+ end
+
+ private
+
+ def note_html(note)
+ render_to_string(
+ "shared/notes/_note",
+ layout: false,
+ formats: [:html],
+ locals: { note: note }
+ )
+ end
+
+ def note_json(note)
+ attrs = {
+ commands_changes: note.commands_changes
+ }
+
+ if note.persisted?
+ attrs.merge!(
+ valid: true,
+ id: note.id,
+ discussion_id: note.discussion_id(noteable),
+ html: note_html(note),
+ note: note.note
+ )
+
+ discussion = note.to_discussion(noteable)
+ unless discussion.individual_note?
+ attrs.merge!(
+ discussion_resolvable: discussion.resolvable?,
+
+ diff_discussion_html: diff_discussion_html(discussion),
+ discussion_html: discussion_html(discussion)
+ )
+ end
+ else
+ attrs.merge!(
+ valid: false,
+ errors: note.errors
+ )
+ end
+
+ attrs
+ end
+
+ def diff_discussion_html(discussion)
+ return unless discussion.diff_discussion?
+
+ if params[:view] == 'parallel'
+ template = "discussions/_parallel_diff_discussion"
+ locals =
+ if params[:line_type] == 'old'
+ { discussions_left: [discussion], discussions_right: nil }
+ else
+ { discussions_left: nil, discussions_right: [discussion] }
+ end
+ else
+ template = "discussions/_diff_discussion"
+ locals = { discussions: [discussion] }
+ end
+
+ render_to_string(
+ template,
+ layout: false,
+ formats: [:html],
+ locals: locals
+ )
+ end
+
+ def discussion_html(discussion)
+ return if discussion.individual_note?
+
+ render_to_string(
+ "discussions/_discussion",
+ layout: false,
+ formats: [:html],
+ locals: { discussion: discussion }
+ )
+ end
+
+ def authorize_admin_note!
+ return access_denied! unless can?(current_user, :admin_note, note)
+ end
+
+ def note_params
+ params.require(:note).permit(
+ :project_id,
+ :noteable_type,
+ :noteable_id,
+ :commit_id,
+ :noteable,
+ :type,
+
+ :note,
+ :attachment,
+
+ # LegacyDiffNote
+ :line_code,
+
+ # DiffNote
+ :position
+ )
+ end
+
+ def noteable
+ @noteable ||= notes_finder.target
+ end
+
+ def last_fetched_at
+ request.headers['X-Last-Fetched-At']
+ end
+
+ def notes_finder
+ @notes_finder ||= NotesFinder.new(project, current_user, finder_params)
+ end
+end
diff --git a/app/controllers/concerns/params_backward_compatibility.rb b/app/controllers/concerns/params_backward_compatibility.rb
new file mode 100644
index 00000000000..b0e3d9c7b34
--- /dev/null
+++ b/app/controllers/concerns/params_backward_compatibility.rb
@@ -0,0 +1,7 @@
+module ParamsBackwardCompatibility
+ private
+
+ def set_non_archived_param
+ params[:non_archived] = params[:archived].blank?
+ end
+end
diff --git a/app/controllers/concerns/renders_blob.rb b/app/controllers/concerns/renders_blob.rb
new file mode 100644
index 00000000000..1d37e4cb3bd
--- /dev/null
+++ b/app/controllers/concerns/renders_blob.rb
@@ -0,0 +1,24 @@
+module RendersBlob
+ extend ActiveSupport::Concern
+
+ def render_blob_json(blob)
+ viewer =
+ case params[:viewer]
+ when 'rich'
+ blob.rich_viewer
+ when 'auxiliary'
+ blob.auxiliary_viewer
+ else
+ blob.simple_viewer
+ end
+ return render_404 unless viewer
+
+ render json: {
+ html: view_to_html_string("projects/blob/_viewer", viewer: viewer, load_async: false)
+ }
+ end
+
+ def override_max_blob_size(blob)
+ blob.override_max_size! if params[:override_max_size] == 'true'
+ end
+end
diff --git a/app/controllers/concerns/renders_notes.rb b/app/controllers/concerns/renders_notes.rb
new file mode 100644
index 00000000000..41c3114ad1e
--- /dev/null
+++ b/app/controllers/concerns/renders_notes.rb
@@ -0,0 +1,22 @@
+module RendersNotes
+ def prepare_notes_for_rendering(notes)
+ preload_noteable_for_regular_notes(notes)
+ preload_max_access_for_authors(notes, @project)
+ Banzai::NoteRenderer.render(notes, @project, current_user)
+
+ notes
+ end
+
+ private
+
+ def preload_max_access_for_authors(notes, project)
+ return nil unless project
+
+ user_ids = notes.map(&:author_id)
+ project.team.max_member_access_for_user_ids(user_ids)
+ end
+
+ def preload_noteable_for_regular_notes(notes)
+ ActiveRecord::Associations::Preloader.new.preload(notes.reject(&:for_commit?), :noteable)
+ end
+end
diff --git a/app/controllers/concerns/requires_health_token.rb b/app/controllers/concerns/requires_health_token.rb
new file mode 100644
index 00000000000..34ab1a97649
--- /dev/null
+++ b/app/controllers/concerns/requires_health_token.rb
@@ -0,0 +1,25 @@
+module RequiresHealthToken
+ extend ActiveSupport::Concern
+ included do
+ before_action :validate_health_check_access!
+ end
+
+ private
+
+ def validate_health_check_access!
+ render_404 unless token_valid?
+ end
+
+ def token_valid?
+ token = params[:token].presence || request.headers['TOKEN']
+ token.present? &&
+ ActiveSupport::SecurityUtils.variable_size_secure_compare(
+ token,
+ current_application_settings.health_check_access_token
+ )
+ end
+
+ def render_404
+ render file: Rails.root.join('public', '404'), layout: false, status: '404'
+ end
+end
diff --git a/app/controllers/concerns/routable_actions.rb b/app/controllers/concerns/routable_actions.rb
new file mode 100644
index 00000000000..4199da9cdf5
--- /dev/null
+++ b/app/controllers/concerns/routable_actions.rb
@@ -0,0 +1,38 @@
+module RoutableActions
+ extend ActiveSupport::Concern
+
+ def find_routable!(routable_klass, requested_full_path, extra_authorization_proc: nil)
+ routable = routable_klass.find_by_full_path(requested_full_path, follow_redirects: request.get?)
+
+ if routable_authorized?(routable, extra_authorization_proc)
+ ensure_canonical_path(routable, requested_full_path)
+ routable
+ else
+ route_not_found
+ nil
+ end
+ end
+
+ def routable_authorized?(routable, extra_authorization_proc)
+ action = :"read_#{routable.class.to_s.underscore}"
+ return false unless can?(current_user, action, routable)
+
+ if extra_authorization_proc
+ extra_authorization_proc.call(routable)
+ else
+ true
+ end
+ end
+
+ def ensure_canonical_path(routable, requested_full_path)
+ return unless request.get?
+
+ canonical_path = routable.full_path
+ if canonical_path != requested_full_path
+ if canonical_path.casecmp(requested_full_path) != 0
+ flash[:notice] = "#{routable.class.to_s.titleize} '#{requested_full_path}' was moved to '#{canonical_path}'. Please update any links and bookmarks that may still have the old path."
+ end
+ redirect_to build_canonical_path(routable)
+ end
+ end
+end
diff --git a/app/controllers/concerns/service_params.rb b/app/controllers/concerns/service_params.rb
index a8c0937569c..be2e6c7f193 100644
--- a/app/controllers/concerns/service_params.rb
+++ b/app/controllers/concerns/service_params.rb
@@ -38,6 +38,7 @@ module ServiceParams
:new_issue_url,
:notify,
:notify_only_broken_pipelines,
+ :notify_only_default_branch,
:password,
:priority,
:project_key,
diff --git a/app/controllers/concerns/snippets_actions.rb b/app/controllers/concerns/snippets_actions.rb
index ca6dffe1cc5..ffea712a833 100644
--- a/app/controllers/concerns/snippets_actions.rb
+++ b/app/controllers/concerns/snippets_actions.rb
@@ -5,10 +5,12 @@ module SnippetsActions
end
def raw
+ disposition = params[:inline] == 'false' ? 'attachment' : 'inline'
+
send_data(
convert_line_endings(@snippet.content),
type: 'text/plain; charset=utf-8',
- disposition: 'inline',
+ disposition: disposition,
filename: @snippet.sanitized_file_name
)
end
diff --git a/app/controllers/concerns/toggle_award_emoji.rb b/app/controllers/concerns/toggle_award_emoji.rb
index fbf9a026b10..ba5b7d33f87 100644
--- a/app/controllers/concerns/toggle_award_emoji.rb
+++ b/app/controllers/concerns/toggle_award_emoji.rb
@@ -22,7 +22,8 @@ module ToggleAwardEmoji
def to_todoable(awardable)
case awardable
when Note
- awardable.noteable
+ # we don't create todos for personal snippet comments for now
+ awardable.for_personal_snippet? ? nil : awardable.noteable
when MergeRequest, Issue
awardable
when Snippet
diff --git a/app/controllers/concerns/uploads_actions.rb b/app/controllers/concerns/uploads_actions.rb
new file mode 100644
index 00000000000..dec2e27335a
--- /dev/null
+++ b/app/controllers/concerns/uploads_actions.rb
@@ -0,0 +1,27 @@
+module UploadsActions
+ def create
+ link_to_file = UploadService.new(model, params[:file], uploader_class).execute
+
+ respond_to do |format|
+ if link_to_file
+ format.json do
+ render json: { link: link_to_file }
+ end
+ else
+ format.json do
+ render json: 'Invalid file.', status: :unprocessable_entity
+ end
+ end
+ end
+ end
+
+ def show
+ return render_404 unless uploader.exists?
+
+ disposition = uploader.image_or_video? ? 'inline' : 'attachment'
+
+ expires_in 0.seconds, must_revalidate: true, private: true
+
+ send_file uploader.file.path, disposition: disposition
+ end
+end
diff --git a/app/controllers/dashboard/labels_controller.rb b/app/controllers/dashboard/labels_controller.rb
index d5031da867a..dd1d46a68c7 100644
--- a/app/controllers/dashboard/labels_controller.rb
+++ b/app/controllers/dashboard/labels_controller.rb
@@ -3,7 +3,7 @@ class Dashboard::LabelsController < Dashboard::ApplicationController
labels = LabelsFinder.new(current_user).execute
respond_to do |format|
- format.json { render json: labels.as_json(only: [:id, :title, :color]) }
+ format.json { render json: LabelSerializer.new.represent_appearance(labels) }
end
end
end
diff --git a/app/controllers/dashboard/projects_controller.rb b/app/controllers/dashboard/projects_controller.rb
index be00d765f73..5a1efcab1a3 100644
--- a/app/controllers/dashboard/projects_controller.rb
+++ b/app/controllers/dashboard/projects_controller.rb
@@ -1,10 +1,11 @@
class Dashboard::ProjectsController < Dashboard::ApplicationController
- include FilterProjects
+ include ParamsBackwardCompatibility
+
+ before_action :set_non_archived_param
+ before_action :default_sorting
def index
- @projects = load_projects(current_user.authorized_projects)
- @projects = @projects.sort(@sort = params[:sort])
- @projects = @projects.page(params[:page])
+ @projects = load_projects(params.merge(non_public: true)).page(params[:page])
respond_to do |format|
format.html { @last_push = current_user.recent_push }
@@ -21,10 +22,8 @@ class Dashboard::ProjectsController < Dashboard::ApplicationController
end
def starred
- @projects = load_projects(current_user.viewable_starred_projects)
- @projects = @projects.includes(:forked_from_project, :tags)
- @projects = @projects.sort(@sort = params[:sort])
- @projects = @projects.page(params[:page])
+ @projects = load_projects(params.merge(starred: true)).
+ includes(:forked_from_project, :tags).page(params[:page])
@last_push = current_user.recent_push
@groups = []
@@ -41,14 +40,18 @@ class Dashboard::ProjectsController < Dashboard::ApplicationController
private
- def load_projects(base_scope)
- projects = base_scope.sorted_by_activity.includes(:route, namespace: :route)
+ def default_sorting
+ params[:sort] ||= 'latest_activity_desc'
+ @sort = params[:sort]
+ end
- filter_projects(projects)
+ def load_projects(finder_params)
+ ProjectsFinder.new(params: finder_params, current_user: current_user).
+ execute.includes(:route, namespace: :route)
end
def load_events
- @events = Event.in_projects(load_projects(current_user.authorized_projects))
+ @events = Event.in_projects(load_projects(params.merge(non_public: true)))
@events = event_filter.apply_filter(@events).with_associations
@events = @events.limit(20).offset(params[:offset] || 0)
end
diff --git a/app/controllers/dashboard/snippets_controller.rb b/app/controllers/dashboard/snippets_controller.rb
index bcfdbe14be9..8dd91264451 100644
--- a/app/controllers/dashboard/snippets_controller.rb
+++ b/app/controllers/dashboard/snippets_controller.rb
@@ -1,11 +1,10 @@
class Dashboard::SnippetsController < Dashboard::ApplicationController
def index
- @snippets = SnippetsFinder.new.execute(
+ @snippets = SnippetsFinder.new(
current_user,
- filter: :by_user,
- user: current_user,
+ author: current_user,
scope: params[:scope]
- )
+ ).execute
@snippets = @snippets.page(params[:page])
end
end
diff --git a/app/controllers/dashboard/todos_controller.rb b/app/controllers/dashboard/todos_controller.rb
index 498690e8f11..4d7d45787fc 100644
--- a/app/controllers/dashboard/todos_controller.rb
+++ b/app/controllers/dashboard/todos_controller.rb
@@ -7,7 +7,7 @@ class Dashboard::TodosController < Dashboard::ApplicationController
@sort = params[:sort]
@todos = @todos.page(params[:page])
if @todos.out_of_range? && @todos.total_pages != 0
- redirect_to url_for(params.merge(page: @todos.total_pages))
+ redirect_to url_for(params.merge(page: @todos.total_pages, only_path: true))
end
end
diff --git a/app/controllers/explore/groups_controller.rb b/app/controllers/explore/groups_controller.rb
index 68228c095da..81883c543ba 100644
--- a/app/controllers/explore/groups_controller.rb
+++ b/app/controllers/explore/groups_controller.rb
@@ -1,6 +1,6 @@
class Explore::GroupsController < Explore::ApplicationController
def index
- @groups = GroupsFinder.new.execute(current_user)
+ @groups = GroupsFinder.new(current_user).execute
@groups = @groups.search(params[:filter_groups]) if params[:filter_groups].present?
@groups = @groups.sort(@sort = params[:sort])
@groups = @groups.page(params[:page])
diff --git a/app/controllers/explore/projects_controller.rb b/app/controllers/explore/projects_controller.rb
index 6167f9bd335..8f1870759e4 100644
--- a/app/controllers/explore/projects_controller.rb
+++ b/app/controllers/explore/projects_controller.rb
@@ -1,14 +1,12 @@
class Explore::ProjectsController < Explore::ApplicationController
- include FilterProjects
+ include ParamsBackwardCompatibility
+
+ before_action :set_non_archived_param
def index
- @projects = load_projects
- @tags = @projects.tags_on(:tags)
- @projects = @projects.tagged_with(params[:tag]) if params[:tag].present?
- @projects = @projects.where(visibility_level: params[:visibility_level]) if params[:visibility_level].present?
- @projects = filter_projects(@projects)
- @projects = @projects.sort(@sort = params[:sort])
- @projects = @projects.includes(:namespace).page(params[:page])
+ params[:sort] ||= 'latest_activity_desc'
+ @sort = params[:sort]
+ @projects = load_projects.page(params[:page])
respond_to do |format|
format.html
@@ -21,10 +19,9 @@ class Explore::ProjectsController < Explore::ApplicationController
end
def trending
- @projects = load_projects(Project.trending)
- @projects = filter_projects(@projects)
- @projects = @projects.sort(@sort = params[:sort])
- @projects = @projects.page(params[:page])
+ params[:trending] = true
+ @sort = params[:sort]
+ @projects = load_projects.page(params[:page])
respond_to do |format|
format.html
@@ -37,10 +34,7 @@ class Explore::ProjectsController < Explore::ApplicationController
end
def starred
- @projects = load_projects
- @projects = filter_projects(@projects)
- @projects = @projects.reorder('star_count DESC')
- @projects = @projects.page(params[:page])
+ @projects = load_projects.reorder('star_count DESC').page(params[:page])
respond_to do |format|
format.html
@@ -52,10 +46,10 @@ class Explore::ProjectsController < Explore::ApplicationController
end
end
- protected
+ private
- def load_projects(base_scope = nil)
- base_scope ||= ProjectsFinder.new.execute(current_user)
- base_scope.includes(:route, namespace: :route)
+ def load_projects
+ ProjectsFinder.new(current_user: current_user, params: params).
+ execute.includes(:route, namespace: :route)
end
end
diff --git a/app/controllers/explore/snippets_controller.rb b/app/controllers/explore/snippets_controller.rb
index 28760c3f84b..d3f0e033068 100644
--- a/app/controllers/explore/snippets_controller.rb
+++ b/app/controllers/explore/snippets_controller.rb
@@ -1,6 +1,6 @@
class Explore::SnippetsController < Explore::ApplicationController
def index
- @snippets = SnippetsFinder.new.execute(current_user, filter: :all)
+ @snippets = SnippetsFinder.new(current_user).execute
@snippets = @snippets.page(params[:page])
end
end
diff --git a/app/controllers/groups/application_controller.rb b/app/controllers/groups/application_controller.rb
index c411c21bb80..c0ac47e363d 100644
--- a/app/controllers/groups/application_controller.rb
+++ b/app/controllers/groups/application_controller.rb
@@ -1,4 +1,6 @@
class Groups::ApplicationController < ApplicationController
+ include RoutableActions
+
layout 'group'
skip_before_action :authenticate_user!
@@ -7,26 +9,15 @@ class Groups::ApplicationController < ApplicationController
private
def group
- unless @group
- id = params[:group_id] || params[:id]
- @group = Group.find_by_full_path(id)
-
- unless @group && can?(current_user, :read_group, @group)
- @group = nil
-
- if current_user.nil?
- authenticate_user!
- else
- render_404
- end
- end
- end
-
- @group
+ @group ||= find_routable!(Group, params[:group_id] || params[:id])
end
def group_projects
- @projects ||= GroupProjectsFinder.new(group).execute(current_user)
+ @projects ||= GroupProjectsFinder.new(group: group, current_user: current_user).execute
+ end
+
+ def group_merge_requests
+ @group_merge_requests = MergeRequestsFinder.new(current_user, group_id: @group.id).execute
end
def authorize_admin_group!
@@ -40,4 +31,10 @@ class Groups::ApplicationController < ApplicationController
return render_403
end
end
+
+ def build_canonical_path(group)
+ params[:group_id] = group.to_param
+
+ url_for(params)
+ end
end
diff --git a/app/controllers/groups/group_members_controller.rb b/app/controllers/groups/group_members_controller.rb
index 0cbf3eb58a3..8fc234a62b1 100644
--- a/app/controllers/groups/group_members_controller.rb
+++ b/app/controllers/groups/group_members_controller.rb
@@ -14,27 +14,13 @@ class Groups::GroupMembersController < Groups::ApplicationController
@members = @members.search(params[:search]) if params[:search].present?
@members = @members.sort(@sort)
@members = @members.page(params[:page]).per(50)
+ @members.includes(:user)
@requesters = AccessRequestsFinder.new(@group).execute(current_user)
@group_member = @group.group_members.new
end
- def create
- if params[:user_ids].blank?
- return redirect_to(group_group_members_path(@group), alert: 'No users specified.')
- end
-
- @group.add_users(
- params[:user_ids].split(','),
- params[:access_level],
- current_user: current_user,
- expires_at: params[:expires_at]
- )
-
- redirect_to group_group_members_path(@group), notice: 'Users were successfully added.'
- end
-
def update
@group_member = @group.group_members.find(params[:id])
@@ -43,15 +29,6 @@ class Groups::GroupMembersController < Groups::ApplicationController
@group_member.update_attributes(member_params)
end
- def destroy
- Members::DestroyService.new(@group, current_user, id: params[:id]).execute(:all)
-
- respond_to do |format|
- format.html { redirect_to group_group_members_path(@group), notice: 'User was successfully removed from group.' }
- format.js { head :ok }
- end
- end
-
def resend_invite
redirect_path = group_group_members_path(@group)
diff --git a/app/controllers/groups/labels_controller.rb b/app/controllers/groups/labels_controller.rb
index facb25525b5..3fa0516fb0c 100644
--- a/app/controllers/groups/labels_controller.rb
+++ b/app/controllers/groups/labels_controller.rb
@@ -15,7 +15,7 @@ class Groups::LabelsController < Groups::ApplicationController
format.json do
available_labels = LabelsFinder.new(current_user, group_id: @group.id).execute
- render json: available_labels.as_json(only: [:id, :title, :color])
+ render json: LabelSerializer.new.represent_appearance(available_labels)
end
end
end
diff --git a/app/controllers/groups/milestones_controller.rb b/app/controllers/groups/milestones_controller.rb
index 43102596201..e52fa766044 100644
--- a/app/controllers/groups/milestones_controller.rb
+++ b/app/controllers/groups/milestones_controller.rb
@@ -1,6 +1,8 @@
class Groups::MilestonesController < Groups::ApplicationController
+ include MilestoneActions
+
before_action :group_projects
- before_action :milestone, only: [:show, :update]
+ before_action :milestone, only: [:show, :update, :merge_requests, :participants, :labels]
before_action :authorize_admin_milestones!, only: [:new, :create, :update]
def index
diff --git a/app/controllers/groups_controller.rb b/app/controllers/groups_controller.rb
index 05f9ee1ee90..965ced4d372 100644
--- a/app/controllers/groups_controller.rb
+++ b/app/controllers/groups_controller.rb
@@ -1,7 +1,7 @@
class GroupsController < Groups::ApplicationController
- include FilterProjects
include IssuesAction
include MergeRequestsAction
+ include ParamsBackwardCompatibility
respond_to :html
@@ -12,8 +12,8 @@ class GroupsController < Groups::ApplicationController
before_action :authorize_admin_group!, only: [:edit, :update, :destroy, :projects]
before_action :authorize_create_group!, only: [:new, :create]
- # Load group projects
before_action :group_projects, only: [:projects, :activity, :issues, :merge_requests]
+ before_action :group_merge_requests, only: [:merge_requests]
before_action :event_filter, only: [:activity]
before_action :user_actions, only: [:show, :subgroups]
@@ -64,7 +64,7 @@ class GroupsController < Groups::ApplicationController
end
def subgroups
- @nested_groups = group.children
+ @nested_groups = GroupsFinder.new(current_user, parent: group).execute
@nested_groups = @nested_groups.search(params[:filter_groups]) if params[:filter_groups].present?
end
@@ -105,15 +105,16 @@ class GroupsController < Groups::ApplicationController
protected
def setup_projects
+ set_non_archived_param
+ params[:sort] ||= 'latest_activity_desc'
+ @sort = params[:sort]
+
options = {}
options[:only_owned] = true if params[:shared] == '0'
options[:only_shared] = true if params[:shared] == '1'
- @projects = GroupProjectsFinder.new(group, options).execute(current_user)
+ @projects = GroupProjectsFinder.new(params: params, group: group, options: options, current_user: current_user).execute
@projects = @projects.includes(:namespace)
- @projects = @projects.sorted_by_activity
- @projects = filter_projects(@projects)
- @projects = @projects.sort(@sort = params[:sort])
@projects = @projects.page(params[:page]) if params[:name].blank?
end
@@ -150,7 +151,9 @@ class GroupsController < Groups::ApplicationController
:visibility_level,
:parent_id,
:create_chat_team,
- :chat_team_name
+ :chat_team_name,
+ :require_two_factor_authentication,
+ :two_factor_grace_period
]
end
@@ -166,4 +169,12 @@ class GroupsController < Groups::ApplicationController
@notification_setting = current_user.notification_settings_for(group)
end
end
+
+ def build_canonical_path(group)
+ return group_path(group) if action_name == 'show' # root group path
+
+ params[:id] = group.to_param
+
+ url_for(params)
+ end
end
diff --git a/app/controllers/health_check_controller.rb b/app/controllers/health_check_controller.rb
index 037da7d2bce..5d3109b7187 100644
--- a/app/controllers/health_check_controller.rb
+++ b/app/controllers/health_check_controller.rb
@@ -1,22 +1,3 @@
class HealthCheckController < HealthCheck::HealthCheckController
- before_action :validate_health_check_access!
-
- private
-
- def validate_health_check_access!
- render_404 unless token_valid?
- end
-
- def token_valid?
- token = params[:token].presence || request.headers['TOKEN']
- token.present? &&
- ActiveSupport::SecurityUtils.variable_size_secure_compare(
- token,
- current_application_settings.health_check_access_token
- )
- end
-
- def render_404
- render file: Rails.root.join('public', '404'), layout: false, status: '404'
- end
+ include RequiresHealthToken
end
diff --git a/app/controllers/health_controller.rb b/app/controllers/health_controller.rb
new file mode 100644
index 00000000000..125746d0426
--- /dev/null
+++ b/app/controllers/health_controller.rb
@@ -0,0 +1,60 @@
+class HealthController < ActionController::Base
+ protect_from_forgery with: :exception
+ include RequiresHealthToken
+
+ CHECKS = [
+ Gitlab::HealthChecks::DbCheck,
+ Gitlab::HealthChecks::RedisCheck,
+ Gitlab::HealthChecks::FsShardsCheck
+ ].freeze
+
+ def readiness
+ results = CHECKS.map { |check| [check.name, check.readiness] }
+
+ render_check_results(results)
+ end
+
+ def liveness
+ results = CHECKS.map { |check| [check.name, check.liveness] }
+
+ render_check_results(results)
+ end
+
+ def metrics
+ results = CHECKS.flat_map(&:metrics)
+
+ response = results.map(&method(:metric_to_prom_line)).join("\n")
+
+ render text: response, content_type: 'text/plain; version=0.0.4'
+ end
+
+ private
+
+ def metric_to_prom_line(metric)
+ labels = metric.labels&.map { |key, value| "#{key}=\"#{value}\"" }&.join(',') || ''
+ if labels.empty?
+ "#{metric.name} #{metric.value}"
+ else
+ "#{metric.name}{#{labels}} #{metric.value}"
+ end
+ end
+
+ def render_check_results(results)
+ flattened = results.flat_map do |name, result|
+ if result.is_a?(Gitlab::HealthChecks::Result)
+ [[name, result]]
+ else
+ result.map { |r| [name, r] }
+ end
+ end
+ success = flattened.all? { |name, r| r.success }
+
+ response = flattened.map do |name, r|
+ info = { status: r.success ? 'ok' : 'failed' }
+ info['message'] = r.message if r.message
+ info[:labels] = r.labels if r.labels
+ [name, info]
+ end
+ render json: response.to_h, status: success ? :ok : :service_unavailable
+ end
+end
diff --git a/app/controllers/import/base_controller.rb b/app/controllers/import/base_controller.rb
index eeee027ef2d..9de0297ecfd 100644
--- a/app/controllers/import/base_controller.rb
+++ b/app/controllers/import/base_controller.rb
@@ -1,17 +1,27 @@
class Import::BaseController < ApplicationController
private
- def find_or_create_namespace(name, owner)
- return current_user.namespace if name == owner
+ def find_or_create_namespace(names, owner)
+ return current_user.namespace if names == owner
return current_user.namespace unless current_user.can_create_group?
- begin
- name = params[:target_namespace].presence || name
- namespace = Group.create!(name: name, path: name, owner: current_user)
- namespace.add_owner(current_user)
- namespace
- rescue ActiveRecord::RecordNotUnique, ActiveRecord::RecordInvalid
- Namespace.find_by_full_path(name)
+ names = params[:target_namespace].presence || names
+ full_path_namespace = Namespace.find_by_full_path(names)
+
+ return full_path_namespace if full_path_namespace
+
+ names.split('/').inject(nil) do |parent, name|
+ begin
+ namespace = Group.create!(name: name,
+ path: name,
+ owner: current_user,
+ parent: parent)
+ namespace.add_owner(current_user)
+
+ namespace
+ rescue ActiveRecord::RecordNotUnique, ActiveRecord::RecordInvalid
+ Namespace.where(parent: parent).find_by_path_or_name(name)
+ end
end
end
end
diff --git a/app/controllers/jwt_controller.rb b/app/controllers/jwt_controller.rb
index 3109439b2ff..1c01be06451 100644
--- a/app/controllers/jwt_controller.rb
+++ b/app/controllers/jwt_controller.rb
@@ -4,7 +4,7 @@ class JwtController < ApplicationController
before_action :authenticate_project_or_user
SERVICES = {
- Auth::ContainerRegistryAuthenticationService::AUDIENCE => Auth::ContainerRegistryAuthenticationService,
+ Auth::ContainerRegistryAuthenticationService::AUDIENCE => Auth::ContainerRegistryAuthenticationService
}.freeze
def auth
diff --git a/app/controllers/omniauth_callbacks_controller.rb b/app/controllers/omniauth_callbacks_controller.rb
index 58d50ad647b..2a8c8ca4bad 100644
--- a/app/controllers/omniauth_callbacks_controller.rb
+++ b/app/controllers/omniauth_callbacks_controller.rb
@@ -67,7 +67,7 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController
def omniauth_error
@provider = params[:provider]
@error = params[:error]
- render 'errors/omniauth_error', layout: "errors", status: 422
+ render 'errors/omniauth_error', layout: "oauth_error", status: 422
end
def cas3
diff --git a/app/controllers/profiles/accounts_controller.rb b/app/controllers/profiles/accounts_controller.rb
index 69959fe3687..7d1aa8d1ce0 100644
--- a/app/controllers/profiles/accounts_controller.rb
+++ b/app/controllers/profiles/accounts_controller.rb
@@ -1,11 +1,22 @@
class Profiles::AccountsController < Profiles::ApplicationController
+ include AuthHelper
+
def show
@user = current_user
end
def unlink
provider = params[:provider]
- current_user.identities.find_by(provider: provider).destroy unless provider.to_s == 'saml'
+ identity = current_user.identities.find_by(provider: provider)
+
+ return render_404 unless identity
+
+ if unlink_allowed?(provider)
+ identity.destroy
+ else
+ flash[:alert] = "You are not allowed to unlink your primary login account"
+ end
+
redirect_to profile_account_path
end
end
diff --git a/app/controllers/profiles/preferences_controller.rb b/app/controllers/profiles/preferences_controller.rb
index 0d891ef4004..5414142e2df 100644
--- a/app/controllers/profiles/preferences_controller.rb
+++ b/app/controllers/profiles/preferences_controller.rb
@@ -33,7 +33,7 @@ class Profiles::PreferencesController < Profiles::ApplicationController
:color_scheme_id,
:layout,
:dashboard,
- :project_view,
+ :project_view
)
end
end
diff --git a/app/controllers/profiles/two_factor_auths_controller.rb b/app/controllers/profiles/two_factor_auths_controller.rb
index 26e7e93533e..d3fa81cd623 100644
--- a/app/controllers/profiles/two_factor_auths_controller.rb
+++ b/app/controllers/profiles/two_factor_auths_controller.rb
@@ -1,5 +1,5 @@
class Profiles::TwoFactorAuthsController < Profiles::ApplicationController
- skip_before_action :check_2fa_requirement
+ skip_before_action :check_two_factor_requirement
def show
unless current_user.otp_secret
@@ -13,11 +13,24 @@ class Profiles::TwoFactorAuthsController < Profiles::ApplicationController
current_user.save! if current_user.changed?
if two_factor_authentication_required? && !current_user.two_factor_enabled?
- if two_factor_grace_period_expired?
- flash.now[:alert] = 'You must enable Two-Factor Authentication for your account.'
- else
+ two_factor_authentication_reason(
+ global: lambda do
+ flash.now[:alert] =
+ 'The global settings require you to enable Two-Factor Authentication for your account.'
+ end,
+ group: lambda do |groups|
+ group_links = groups.map { |group| view_context.link_to group.full_name, group_path(group) }.to_sentence
+
+ flash.now[:alert] = %{
+ The group settings for #{group_links} require you to enable
+ Two-Factor Authentication for your account.
+ }.html_safe
+ end
+ )
+
+ unless two_factor_grace_period_expired?
grace_period_deadline = current_user.otp_grace_period_started_at + two_factor_grace_period.hours
- flash.now[:alert] = "You must enable Two-Factor Authentication for your account before #{l(grace_period_deadline)}."
+ flash.now[:alert] << " You need to do this before #{l(grace_period_deadline)}."
end
end
@@ -71,7 +84,7 @@ class Profiles::TwoFactorAuthsController < Profiles::ApplicationController
if two_factor_grace_period_expired?
redirect_to new_profile_two_factor_auth_path, alert: 'Cannot skip two factor authentication setup'
else
- session[:skip_tfa] = current_user.otp_grace_period_started_at + two_factor_grace_period.hours
+ session[:skip_two_factor] = current_user.otp_grace_period_started_at + two_factor_grace_period.hours
redirect_to root_path
end
end
diff --git a/app/controllers/profiles_controller.rb b/app/controllers/profiles_controller.rb
index 987b95e89b9..57e23cea00e 100644
--- a/app/controllers/profiles_controller.rb
+++ b/app/controllers/profiles_controller.rb
@@ -85,7 +85,8 @@ class ProfilesController < Profiles::ApplicationController
:twitter,
:username,
:website_url,
- :organization
+ :organization,
+ :preferred_language
)
end
end
diff --git a/app/controllers/projects/application_controller.rb b/app/controllers/projects/application_controller.rb
index f1a93ccb3ad..cb4bd0ad5f5 100644
--- a/app/controllers/projects/application_controller.rb
+++ b/app/controllers/projects/application_controller.rb
@@ -1,5 +1,8 @@
class Projects::ApplicationController < ApplicationController
+ include RoutableActions
+
skip_before_action :authenticate_user!
+ before_action :redirect_git_extension
before_action :project
before_action :repository
layout 'project'
@@ -8,40 +11,29 @@ class Projects::ApplicationController < ApplicationController
private
+ def redirect_git_extension
+ # Redirect from
+ # localhost/group/project.git
+ # to
+ # localhost/group/project
+ #
+ redirect_to url_for(params.merge(format: nil)) if params[:format] == 'git'
+ end
+
def project
- unless @project
- namespace = params[:namespace_id]
- id = params[:project_id] || params[:id]
-
- # Redirect from
- # localhost/group/project.git
- # to
- # localhost/group/project
- #
- if params[:format] == 'git'
- redirect_to request.original_url.gsub(/\.git\/?\Z/, '')
- return
- end
-
- project_path = "#{namespace}/#{id}"
- @project = Project.find_by_full_path(project_path)
-
- if can?(current_user, :read_project, @project) && !@project.pending_delete?
- if @project.path_with_namespace != project_path
- redirect_to request.original_url.gsub(project_path, @project.path_with_namespace)
- end
- else
- @project = nil
-
- if current_user.nil?
- authenticate_user!
- else
- render_404
- end
- end
- end
+ return @project if @project
+
+ path = File.join(params[:namespace_id], params[:project_id] || params[:id])
+ auth_proc = ->(project) { !project.pending_delete? }
- @project
+ @project = find_routable!(Project, path, extra_authorization_proc: auth_proc)
+ end
+
+ def build_canonical_path(project)
+ params[:namespace_id] = project.namespace.to_param
+ params[:project_id] = project.to_param
+
+ url_for(params)
end
def repository
@@ -55,13 +47,15 @@ class Projects::ApplicationController < ApplicationController
(current_user && current_user.already_forked?(project))
end
- def authorize_project!(action)
- return access_denied! unless can?(current_user, action, project)
+ def authorize_action!(action)
+ unless can?(current_user, action, project)
+ return access_denied!
+ end
end
def method_missing(method_sym, *arguments, &block)
if method_sym.to_s =~ /\Aauthorize_(.*)!\z/
- authorize_project!($1.to_sym)
+ authorize_action!($1.to_sym)
else
super
end
@@ -90,8 +84,7 @@ class Projects::ApplicationController < ApplicationController
return render_404 unless @project.feature_available?(:builds, current_user)
end
- def update_ref
- branch_exists = @repository.find_branch(@target_branch)
- @ref = @target_branch if branch_exists
+ def require_pages_enabled!
+ not_found unless Gitlab.config.pages.enabled
end
end
diff --git a/app/controllers/projects/artifacts_controller.rb b/app/controllers/projects/artifacts_controller.rb
index 59222637961..1224e9503c9 100644
--- a/app/controllers/projects/artifacts_controller.rb
+++ b/app/controllers/projects/artifacts_controller.rb
@@ -1,11 +1,13 @@
class Projects::ArtifactsController < Projects::ApplicationController
include ExtractsPath
+ include RendersBlob
layout 'project'
before_action :authorize_read_build!
before_action :authorize_update_build!, only: [:keep]
before_action :extract_ref_name_and_path
before_action :validate_artifacts!
+ before_action :set_path_and_entry, only: [:file, :raw]
def download
if artifacts_file.file_storage?
@@ -16,22 +18,32 @@ class Projects::ArtifactsController < Projects::ApplicationController
end
def browse
- directory = params[:path] ? "#{params[:path]}/" : ''
+ @path = params[:path]
+ directory = @path ? "#{@path}/" : ''
@entry = build.artifacts_metadata_entry(directory)
render_404 unless @entry.exists?
end
def file
- entry = build.artifacts_metadata_entry(params[:path])
+ blob = @entry.blob
+ override_max_blob_size(blob)
- if entry.exists?
- send_artifacts_entry(build, entry)
- else
- render_404
+ respond_to do |format|
+ format.html do
+ render 'file'
+ end
+
+ format.json do
+ render_blob_json(blob)
+ end
end
end
+ def raw
+ send_artifacts_entry(build, @entry)
+ end
+
def keep
build.keep_artifacts!
redirect_to namespace_project_build_path(project.namespace, project, build)
@@ -60,7 +72,10 @@ class Projects::ArtifactsController < Projects::ApplicationController
end
def build
- @build ||= build_from_id || build_from_ref
+ @build ||= begin
+ build = build_from_id || build_from_ref
+ build&.present(current_user: current_user)
+ end
end
def build_from_id
@@ -77,4 +92,11 @@ class Projects::ArtifactsController < Projects::ApplicationController
def artifacts_file
@artifacts_file ||= build.artifacts_file
end
+
+ def set_path_and_entry
+ @path = params[:path]
+ @entry = build.artifacts_metadata_entry(@path)
+
+ render_404 unless @entry.exists?
+ end
end
diff --git a/app/controllers/projects/blob_controller.rb b/app/controllers/projects/blob_controller.rb
index 80a95c6158b..87721fbe2f5 100644
--- a/app/controllers/projects/blob_controller.rb
+++ b/app/controllers/projects/blob_controller.rb
@@ -2,14 +2,17 @@
class Projects::BlobController < Projects::ApplicationController
include ExtractsPath
include CreatesCommit
+ include RendersBlob
include ActionView::Helpers::SanitizeHelper
# Raised when given an invalid file path
InvalidPathError = Class.new(StandardError)
+ prepend_before_action :authenticate_user!, only: [:edit]
+
before_action :require_non_empty_project, except: [:new, :create]
before_action :authorize_download_code!
- before_action :authorize_edit_tree!, only: [:new, :create, :edit, :update, :destroy]
+ before_action :authorize_edit_tree!, only: [:new, :create, :update, :destroy]
before_action :assign_blob_vars
before_action :commit, except: [:new, :create]
before_action :blob, except: [:new, :create]
@@ -23,21 +26,39 @@ class Projects::BlobController < Projects::ApplicationController
end
def create
- update_ref
+ set_start_branch_to_branch_name
create_commit(Files::CreateService, success_notice: "The file has been successfully created.",
- success_path: -> { namespace_project_blob_path(@project.namespace, @project, File.join(@target_branch, @file_path)) },
+ success_path: -> { namespace_project_blob_path(@project.namespace, @project, File.join(@branch_name, @file_path)) },
failure_view: :new,
failure_path: namespace_project_new_blob_path(@project.namespace, @project, @ref))
end
def show
- environment_params = @repository.branch_exists?(@ref) ? { ref: @ref } : { commit: @commit }
- @environment = EnvironmentsFinder.new(@project, current_user, environment_params).execute.last
+ override_max_blob_size(@blob)
+
+ respond_to do |format|
+ format.html do
+ environment_params = @repository.branch_exists?(@ref) ? { ref: @ref } : { commit: @commit }
+ @environment = EnvironmentsFinder.new(@project, current_user, environment_params).execute.last
+
+ @last_commit = @repository.last_commit_for_path(@commit.id, @blob.path)
+
+ render 'show'
+ end
+
+ format.json do
+ render_blob_json(@blob)
+ end
+ end
end
def edit
- blob.load_all_data!(@repository)
+ if can_collaborate_with_project?
+ blob.load_all_data!(@repository)
+ else
+ redirect_to action: 'show'
+ end
end
def update
@@ -63,10 +84,10 @@ class Projects::BlobController < Projects::ApplicationController
end
def destroy
- create_commit(Files::DestroyService, success_notice: "The file has been successfully deleted.",
- success_path: -> { namespace_project_tree_path(@project.namespace, @project, @target_branch) },
- failure_view: :show,
- failure_path: namespace_project_blob_path(@project.namespace, @project, @id))
+ create_commit(Files::DeleteService, success_notice: "The file has been successfully deleted.",
+ success_path: -> { namespace_project_tree_path(@project.namespace, @project, @branch_name) },
+ failure_view: :show,
+ failure_path: namespace_project_blob_path(@project.namespace, @project, @id))
end
def diff
@@ -90,7 +111,7 @@ class Projects::BlobController < Projects::ApplicationController
private
def blob
- @blob ||= Blob.decorate(@repository.blob_at(@commit.id, @path))
+ @blob ||= Blob.decorate(@repository.blob_at(@commit.id, @path), @project)
if @blob
@blob
@@ -121,16 +142,16 @@ class Projects::BlobController < Projects::ApplicationController
def after_edit_path
from_merge_request = MergeRequestsFinder.new(current_user, project_id: @project.id).execute.find_by(iid: params[:from_merge_request_iid])
- if from_merge_request && @target_branch == @ref
+ if from_merge_request && @branch_name == @ref
diffs_namespace_project_merge_request_path(from_merge_request.target_project.namespace, from_merge_request.target_project, from_merge_request) +
"##{hexdigest(@path)}"
else
- namespace_project_blob_path(@project.namespace, @project, File.join(@target_branch, @path))
+ namespace_project_blob_path(@project.namespace, @project, File.join(@branch_name, @path))
end
end
def editor_variables
- @target_branch = params[:target_branch]
+ @branch_name = params[:branch_name]
@file_path =
if action_name.to_s == 'create'
diff --git a/app/controllers/projects/boards/issues_controller.rb b/app/controllers/projects/boards/issues_controller.rb
index 28c9646910d..da9b789d617 100644
--- a/app/controllers/projects/boards/issues_controller.rb
+++ b/app/controllers/projects/boards/issues_controller.rb
@@ -82,7 +82,7 @@ module Projects
labels: true,
only: [:id, :iid, :title, :confidential, :due_date, :relative_position],
include: {
- assignee: { only: [:id, :name, :username], methods: [:avatar_url] },
+ assignees: { only: [:id, :name, :username], methods: [:avatar_url] },
milestone: { only: [:id, :title] }
},
user: current_user
diff --git a/app/controllers/projects/branches_controller.rb b/app/controllers/projects/branches_controller.rb
index 840405f38cb..d8ed470e461 100644
--- a/app/controllers/projects/branches_controller.rb
+++ b/app/controllers/projects/branches_controller.rb
@@ -46,32 +46,45 @@ class Projects::BranchesController < Projects::ApplicationController
SystemNoteService.new_issue_branch(issue, @project, current_user, branch_name) if issue
end
- if result[:status] == :success
- @branch = result[:branch]
-
- if redirect_to_autodeploy
- redirect_to(
- url_to_autodeploy_setup(project, branch_name),
- notice: view_context.autodeploy_flash_notice(branch_name))
- else
- redirect_to namespace_project_tree_path(@project.namespace, @project,
- @branch.name)
+ respond_to do |format|
+ format.html do
+ if result[:status] == :success
+ if redirect_to_autodeploy
+ redirect_to url_to_autodeploy_setup(project, branch_name),
+ notice: view_context.autodeploy_flash_notice(branch_name)
+ else
+ redirect_to namespace_project_tree_path(@project.namespace, @project, branch_name)
+ end
+ else
+ @error = result[:message]
+ render action: 'new'
+ end
+ end
+
+ format.json do
+ if result[:status] == :success
+ render json: { name: branch_name, url: namespace_project_tree_url(@project.namespace, @project, branch_name) }
+ else
+ render json: result[:messsage], status: :unprocessable_entity
+ end
end
- else
- @error = result[:message]
- render action: 'new'
end
end
def destroy
@branch_name = Addressable::URI.unescape(params[:id])
- status = DeleteBranchService.new(project, current_user).execute(@branch_name)
+ result = DeleteBranchService.new(project, current_user).execute(@branch_name)
+
respond_to do |format|
format.html do
- redirect_to namespace_project_branches_path(@project.namespace,
- @project), status: 303
+ flash_type = result[:status] == :error ? :alert : :notice
+ flash[flash_type] = result[:message]
+
+ redirect_to namespace_project_branches_path(@project.namespace, @project), status: 303
end
- format.js { render nothing: true, status: status[:return_code] }
+
+ format.js { render nothing: true, status: result[:return_code] }
+ format.json { render json: { message: result[:message] }, status: result[:return_code] }
end
end
diff --git a/app/controllers/projects/builds_controller.rb b/app/controllers/projects/builds_controller.rb
index 3f3c90a49ab..dfaaea71b9c 100644
--- a/app/controllers/projects/builds_controller.rb
+++ b/app/controllers/projects/builds_controller.rb
@@ -1,7 +1,11 @@
class Projects::BuildsController < Projects::ApplicationController
before_action :build, except: [:index, :cancel_all]
- before_action :authorize_read_build!, except: [:cancel, :cancel_all, :retry, :play]
- before_action :authorize_update_build!, except: [:index, :show, :status, :raw, :trace]
+
+ before_action :authorize_read_build!,
+ only: [:index, :show, :status, :raw, :trace]
+ before_action :authorize_update_build!,
+ except: [:index, :show, :status, :raw, :trace, :cancel_all]
+
layout 'project'
def index
@@ -19,11 +23,21 @@ class Projects::BuildsController < Projects::ApplicationController
else
@builds
end
+ @builds = @builds.includes([
+ { pipeline: :project },
+ :project,
+ :tags
+ ])
@builds = @builds.page(params[:page]).per(30)
end
def cancel_all
- @project.builds.running_or_pending.each(&:cancel)
+ return access_denied! unless can?(current_user, :update_build, project)
+
+ @project.builds.running_or_pending.each do |build|
+ build.cancel if can?(current_user, :update_build, build)
+ end
+
redirect_to namespace_project_builds_path(project.namespace, project)
end
@@ -31,72 +45,84 @@ class Projects::BuildsController < Projects::ApplicationController
@builds = @project.pipelines.find_by_sha(@build.sha).builds.order('id DESC')
@builds = @builds.where("id not in (?)", @build.id)
@pipeline = @build.pipeline
-
- respond_to do |format|
- format.html
- format.json do
- render json: {
- id: @build.id,
- status: @build.status,
- trace_html: @build.trace_html
- }
- end
- end
end
def trace
- respond_to do |format|
- format.json do
- state = params[:state].presence
- render json: @build.trace_with_state(state: state).
- merge!(id: @build.id, status: @build.status)
+ build.trace.read do |stream|
+ respond_to do |format|
+ format.json do
+ result = {
+ id: @build.id, status: @build.status, complete: @build.complete?
+ }
+
+ if stream.valid?
+ stream.limit
+ state = params[:state].presence
+ trace = stream.html_with_state(state)
+ result.merge!(trace.to_h)
+ end
+
+ render json: result
+ end
end
end
end
def retry
- return render_404 unless @build.retryable?
+ return respond_422 unless @build.retryable?
build = Ci::Build.retry(@build, current_user)
redirect_to build_path(build)
end
def play
- return render_404 unless @build.playable?
+ return respond_422 unless @build.playable?
build = @build.play(current_user)
redirect_to build_path(build)
end
def cancel
+ return respond_422 unless @build.cancelable?
+
@build.cancel
redirect_to build_path(@build)
end
def status
render json: BuildSerializer
- .new(project: @project, user: @current_user)
+ .new(project: @project, current_user: @current_user)
.represent_status(@build)
end
def erase
- @build.erase(erased_by: current_user)
- redirect_to namespace_project_build_path(project.namespace, project, @build),
+ if @build.erase(erased_by: current_user)
+ redirect_to namespace_project_build_path(project.namespace, project, @build),
notice: "Build has been successfully erased!"
+ else
+ respond_422
+ end
end
def raw
- if @build.has_trace_file?
- send_file @build.trace_file_path, type: 'text/plain; charset=utf-8', disposition: 'inline'
- else
- render_404
+ build.trace.read do |stream|
+ if stream.file?
+ send_file stream.path, type: 'text/plain; charset=utf-8', disposition: 'inline'
+ else
+ render_404
+ end
end
end
private
+ def authorize_update_build!
+ return access_denied! unless can?(current_user, :update_build, build)
+ end
+
def build
- @build ||= project.builds.find_by!(id: params[:id]).present(current_user: current_user)
+ @build ||= project.builds.find(params[:id])
+ .present(current_user: current_user)
end
def build_path(build)
diff --git a/app/controllers/projects/commit_controller.rb b/app/controllers/projects/commit_controller.rb
index cc67f688d51..7c3cce1c241 100644
--- a/app/controllers/projects/commit_controller.rb
+++ b/app/controllers/projects/commit_controller.rb
@@ -2,6 +2,7 @@
#
# Not to be confused with CommitsController, plural.
class Projects::CommitController < Projects::ApplicationController
+ include RendersNotes
include CreatesCommit
include DiffForPath
include DiffHelper
@@ -35,8 +36,10 @@ class Projects::CommitController < Projects::ApplicationController
respond_to do |format|
format.html
format.json do
+ Gitlab::PollingInterval.set_header(response, interval: 10_000)
+
render json: PipelineSerializer
- .new(project: @project, user: @current_user)
+ .new(project: @project, current_user: @current_user)
.represent(@pipelines)
end
end
@@ -53,9 +56,7 @@ class Projects::CommitController < Projects::ApplicationController
return render_404 if @start_branch.blank?
- @target_branch = create_new_branch? ? @commit.revert_branch_name : @start_branch
-
- @mr_target_branch = @start_branch
+ @branch_name = create_new_branch? ? @commit.revert_branch_name : @start_branch
create_commit(Commits::RevertService, success_notice: "The #{@commit.change_type_title(current_user)} has been successfully reverted.",
success_path: -> { successful_change_path }, failure_path: failed_change_path)
@@ -66,9 +67,7 @@ class Projects::CommitController < Projects::ApplicationController
return render_404 if @start_branch.blank?
- @target_branch = create_new_branch? ? @commit.cherry_pick_branch_name : @start_branch
-
- @mr_target_branch = @start_branch
+ @branch_name = create_new_branch? ? @commit.cherry_pick_branch_name : @start_branch
create_commit(Commits::CherryPickService, success_notice: "The #{@commit.change_type_title(current_user)} has been successfully cherry-picked.",
success_path: -> { successful_change_path }, failure_path: failed_change_path)
@@ -81,7 +80,7 @@ class Projects::CommitController < Projects::ApplicationController
end
def successful_change_path
- referenced_merge_request_url || namespace_project_commits_url(@project.namespace, @project, @target_branch)
+ referenced_merge_request_url || namespace_project_commits_url(@project.namespace, @project, @branch_name)
end
def failed_change_path
@@ -111,22 +110,19 @@ class Projects::CommitController < Projects::ApplicationController
end
def define_note_vars
- @grouped_diff_discussions = commit.notes.grouped_diff_discussions
- @notes = commit.notes.non_diff_notes.fresh
-
- Banzai::NoteRenderer.render(
- @grouped_diff_discussions.values.flat_map(&:notes) + @notes,
- @project,
- current_user,
- )
-
+ @noteable = @commit
@note = @project.build_commit_note(commit)
- @noteable = @commit
- @comments_target = {
+ @new_diff_note_attrs = {
noteable_type: 'Commit',
commit_id: @commit.id
}
+
+ @grouped_diff_discussions = commit.grouped_diff_discussions
+ @discussions = commit.discussions
+
+ @notes = (@grouped_diff_discussions.values.flatten + @discussions).flat_map(&:notes)
+ @notes = prepare_notes_for_rendering(@notes)
end
def assign_change_commit_vars
diff --git a/app/controllers/projects/compare_controller.rb b/app/controllers/projects/compare_controller.rb
index c6651254d70..008d2f5815f 100644
--- a/app/controllers/projects/compare_controller.rb
+++ b/app/controllers/projects/compare_controller.rb
@@ -61,7 +61,6 @@ class Projects::CompareController < Projects::ApplicationController
@environment = EnvironmentsFinder.new(@project, current_user, environment_params).execute.last
@diff_notes_disabled = true
- @grouped_diff_discussions = {}
end
end
diff --git a/app/controllers/projects/container_registry_controller.rb b/app/controllers/projects/container_registry_controller.rb
deleted file mode 100644
index d1f46497207..00000000000
--- a/app/controllers/projects/container_registry_controller.rb
+++ /dev/null
@@ -1,34 +0,0 @@
-class Projects::ContainerRegistryController < Projects::ApplicationController
- before_action :verify_registry_enabled
- before_action :authorize_read_container_image!
- before_action :authorize_update_container_image!, only: [:destroy]
- layout 'project'
-
- def index
- @tags = container_registry_repository.tags
- end
-
- def destroy
- url = namespace_project_container_registry_index_path(project.namespace, project)
-
- if tag.delete
- redirect_to url
- else
- redirect_to url, alert: 'Failed to remove tag'
- end
- end
-
- private
-
- def verify_registry_enabled
- render_404 unless Gitlab.config.registry.enabled
- end
-
- def container_registry_repository
- @container_registry_repository ||= project.container_registry_repository
- end
-
- def tag
- @tag ||= container_registry_repository.tag(params[:id])
- end
-end
diff --git a/app/controllers/projects/deploy_keys_controller.rb b/app/controllers/projects/deploy_keys_controller.rb
index d0c44e297e3..f27089b8590 100644
--- a/app/controllers/projects/deploy_keys_controller.rb
+++ b/app/controllers/projects/deploy_keys_controller.rb
@@ -8,7 +8,12 @@ class Projects::DeployKeysController < Projects::ApplicationController
layout "project_settings"
def index
- redirect_to_repository_settings(@project)
+ respond_to do |format|
+ format.html { redirect_to_repository_settings(@project) }
+ format.json do
+ render json: Projects::Settings::DeployKeysPresenter.new(@project, current_user: current_user).as_json
+ end
+ end
end
def new
@@ -19,7 +24,7 @@ class Projects::DeployKeysController < Projects::ApplicationController
@key = DeployKey.new(deploy_key_params.merge(user: current_user))
unless @key.valid? && @project.deploy_keys << @key
- flash[:alert] = @key.errors.full_messages.join(', ').html_safe
+ flash[:alert] = @key.errors.full_messages.join(', ').html_safe
end
redirect_to_repository_settings(@project)
end
@@ -27,7 +32,10 @@ class Projects::DeployKeysController < Projects::ApplicationController
def enable
Projects::EnableDeployKeyService.new(@project, current_user, params).execute
- redirect_to_repository_settings(@project)
+ respond_to do |format|
+ format.html { redirect_to_repository_settings(@project) }
+ format.json { head :ok }
+ end
end
def disable
@@ -35,7 +43,11 @@ class Projects::DeployKeysController < Projects::ApplicationController
return render_404 unless deploy_key_project
deploy_key_project.destroy!
- redirect_to_repository_settings(@project)
+
+ respond_to do |format|
+ format.html { redirect_to_repository_settings(@project) }
+ format.json { head :ok }
+ end
end
protected
diff --git a/app/controllers/projects/deployments_controller.rb b/app/controllers/projects/deployments_controller.rb
new file mode 100644
index 00000000000..6644deb49c9
--- /dev/null
+++ b/app/controllers/projects/deployments_controller.rb
@@ -0,0 +1,34 @@
+class Projects::DeploymentsController < Projects::ApplicationController
+ before_action :authorize_read_environment!
+ before_action :authorize_read_deployment!
+
+ def index
+ deployments = environment.deployments.reorder(created_at: :desc)
+ deployments = deployments.where('created_at > ?', params[:after].to_time) if params[:after]&.to_time
+
+ render json: { deployments: DeploymentSerializer.new(project: project)
+ .represent_concise(deployments) }
+ end
+
+ def metrics
+ return render_404 unless deployment.has_metrics?
+ @metrics = deployment.metrics
+ if @metrics&.any?
+ render json: @metrics, status: :ok
+ else
+ head :no_content
+ end
+ rescue NotImplementedError
+ render_404
+ end
+
+ private
+
+ def deployment
+ @deployment ||= environment.deployments.find_by(iid: params[:id])
+ end
+
+ def environment
+ @environment ||= project.environments.find(params[:environment_id])
+ end
+end
diff --git a/app/controllers/projects/discussions_controller.rb b/app/controllers/projects/discussions_controller.rb
index 1349b015a63..f4a18a5e8f7 100644
--- a/app/controllers/projects/discussions_controller.rb
+++ b/app/controllers/projects/discussions_controller.rb
@@ -28,7 +28,7 @@ class Projects::DiscussionsController < Projects::ApplicationController
end
def discussion
- @discussion ||= @merge_request.find_diff_discussion(params[:id]) || render_404
+ @discussion ||= @merge_request.find_discussion(params[:id]) || render_404
end
def authorize_resolve_discussion!
diff --git a/app/controllers/projects/environments_controller.rb b/app/controllers/projects/environments_controller.rb
index fa37963dfd4..fd57afbd05f 100644
--- a/app/controllers/projects/environments_controller.rb
+++ b/app/controllers/projects/environments_controller.rb
@@ -17,7 +17,7 @@ class Projects::EnvironmentsController < Projects::ApplicationController
format.json do
render json: {
environments: EnvironmentSerializer
- .new(project: @project, user: @current_user)
+ .new(project: @project, current_user: @current_user)
.with_pagination(request, response)
.within_folders
.represent(@environments),
@@ -37,7 +37,7 @@ class Projects::EnvironmentsController < Projects::ApplicationController
format.json do
render json: {
environments: EnvironmentSerializer
- .new(project: @project, user: @current_user)
+ .new(project: @project, current_user: @current_user)
.with_pagination(request, response)
.represent(@environments),
available_count: folder_environments.available.count,
@@ -81,10 +81,16 @@ class Projects::EnvironmentsController < Projects::ApplicationController
stop_action = @environment.stop_with_action!(current_user)
- if stop_action
- redirect_to polymorphic_path([project.namespace.becomes(Namespace), project, stop_action])
- else
- redirect_to namespace_project_environment_path(project.namespace, project, @environment)
+ action_or_env_url =
+ if stop_action
+ polymorphic_url([project.namespace.becomes(Namespace), project, stop_action])
+ else
+ namespace_project_environment_url(project.namespace, project, @environment)
+ end
+
+ respond_to do |format|
+ format.html { redirect_to action_or_env_url }
+ format.json { render json: { redirect_url: action_or_env_url } }
end
end
diff --git a/app/controllers/projects/forks_controller.rb b/app/controllers/projects/forks_controller.rb
index ba46e2528e6..1eb3800e49d 100644
--- a/app/controllers/projects/forks_controller.rb
+++ b/app/controllers/projects/forks_controller.rb
@@ -9,7 +9,7 @@ class Projects::ForksController < Projects::ApplicationController
def index
base_query = project.forks.includes(:creator)
- @forks = base_query.merge(ProjectsFinder.new.execute(current_user))
+ @forks = base_query.merge(ProjectsFinder.new(current_user: current_user).execute)
@total_forks_count = base_query.size
@private_forks_count = @total_forks_count - @forks.size
@public_forks_count = @total_forks_count - @private_forks_count
diff --git a/app/controllers/projects/git_http_controller.rb b/app/controllers/projects/git_http_controller.rb
index 278098fcc58..9e4edcae101 100644
--- a/app/controllers/projects/git_http_controller.rb
+++ b/app/controllers/projects/git_http_controller.rb
@@ -5,6 +5,8 @@ class Projects::GitHttpController < Projects::GitHttpClientController
# GET /foo/bar.git/info/refs?service=git-receive-pack (git push)
def info_refs
if upload_pack? && upload_pack_allowed?
+ log_user_activity
+
render_ok
elsif receive_pack? && receive_pack_allowed?
render_ok
@@ -57,7 +59,7 @@ class Projects::GitHttpController < Projects::GitHttpClientController
def render_ok
set_workhorse_internal_api_content_type
- render json: Gitlab::Workhorse.git_http_ok(repository, user)
+ render json: Gitlab::Workhorse.git_http_ok(repository, wiki?, user, action_name)
end
def render_http_not_allowed
@@ -106,4 +108,8 @@ class Projects::GitHttpController < Projects::GitHttpClientController
def access_klass
@access_klass ||= wiki? ? Gitlab::GitAccessWiki : Gitlab::GitAccess
end
+
+ def log_user_activity
+ Users::ActivityService.new(user, 'pull').execute
+ end
end
diff --git a/app/controllers/projects/hooks_controller.rb b/app/controllers/projects/hooks_controller.rb
index b668a9331e7..86d13a0d222 100644
--- a/app/controllers/projects/hooks_controller.rb
+++ b/app/controllers/projects/hooks_controller.rb
@@ -1,6 +1,7 @@
class Projects::HooksController < Projects::ApplicationController
# Authorize
before_action :authorize_admin_project!
+ before_action :hook, only: :edit
respond_to :html
@@ -10,13 +11,25 @@ class Projects::HooksController < Projects::ApplicationController
@hook = @project.hooks.new(hook_params)
@hook.save
- unless @hook.valid?
+ unless @hook.valid?
@hooks = @project.hooks.select(&:persisted?)
flash[:alert] = @hook.errors.full_messages.join.html_safe
end
redirect_to namespace_project_settings_integrations_path(@project.namespace, @project)
end
+ def edit
+ end
+
+ def update
+ if hook.update_attributes(hook_params)
+ flash[:notice] = 'Hook was successfully updated.'
+ redirect_to namespace_project_settings_integrations_path(@project.namespace, @project)
+ else
+ render 'edit'
+ end
+ end
+
def test
if !@project.empty_repo?
status, message = TestHookService.new.execute(hook, current_user)
@@ -49,7 +62,7 @@ class Projects::HooksController < Projects::ApplicationController
def hook_params
params.require(:hook).permit(
- :build_events,
+ :job_events,
:pipeline_events,
:enable_ssl_verification,
:issues_events,
diff --git a/app/controllers/projects/issues_controller.rb b/app/controllers/projects/issues_controller.rb
index d984e6d3918..cbef8fa94d4 100644
--- a/app/controllers/projects/issues_controller.rb
+++ b/app/controllers/projects/issues_controller.rb
@@ -1,5 +1,5 @@
class Projects::IssuesController < Projects::ApplicationController
- include NotesHelper
+ include RendersNotes
include ToggleSubscriptionAction
include IssuableActions
include ToggleAwardEmoji
@@ -11,10 +11,10 @@ class Projects::IssuesController < Projects::ApplicationController
before_action :redirect_to_external_issue_tracker, only: [:index, :new]
before_action :module_enabled
before_action :issue, only: [:edit, :update, :show, :referenced_merge_requests,
- :related_branches, :can_create_branch]
+ :related_branches, :can_create_branch, :realtime_changes, :create_merge_request]
# Allow read any issue
- before_action :authorize_read_issue!, only: [:show]
+ before_action :authorize_read_issue!, only: [:show, :realtime_changes]
# Allow write(create) issue
before_action :authorize_create_issue!, only: [:new, :create]
@@ -22,6 +22,9 @@ class Projects::IssuesController < Projects::ApplicationController
# Allow modify issue
before_action :authorize_update_issue!, only: [:edit, :update]
+ # Allow create a new branch and empty WIP merge request from current issue
+ before_action :authorize_create_merge_request!, only: [:create_merge_request]
+
respond_to :html
def index
@@ -31,7 +34,7 @@ class Projects::IssuesController < Projects::ApplicationController
@issuable_meta_data = issuable_meta_data(@issues, @collection_type)
if @issues.out_of_range? && @issues.total_pages != 0
- return redirect_to url_for(params.merge(page: @issues.total_pages))
+ return redirect_to url_for(params.merge(page: @issues.total_pages, only_path: true))
end
if params[:label_name].present?
@@ -64,7 +67,7 @@ class Projects::IssuesController < Projects::ApplicationController
def new
params[:issue] ||= ActionController::Parameters.new(
- assignee_id: ""
+ assignee_ids: ""
)
build_params = issue_params.merge(
merge_request_to_resolve_discussions_of: params[:merge_request_to_resolve_discussions_of],
@@ -84,15 +87,11 @@ class Projects::IssuesController < Projects::ApplicationController
end
def show
- raw_notes = @issue.notes.inc_relations_for_view.fresh
-
- @notes = Banzai::NoteRenderer.
- render(raw_notes, @project, current_user, @path, @project_wiki, @ref)
-
- @note = @project.notes.new(noteable: @issue)
@noteable = @issue
+ @note = @project.notes.new(noteable: @issue)
- preload_max_access_for_authors(@notes, @project)
+ @discussions = @issue.discussions
+ @notes = prepare_notes_for_rendering(@discussions.flat_map(&:notes))
respond_to do |format|
format.html
@@ -151,7 +150,7 @@ class Projects::IssuesController < Projects::ApplicationController
if @issue.valid?
render json: @issue.to_json(methods: [:task_status, :task_status_short],
include: { milestone: {},
- assignee: { only: [:name, :username], methods: [:avatar_url] },
+ assignees: { only: [:id, :name, :username], methods: [:avatar_url] },
labels: { methods: :text_color } })
else
render json: { errors: @issue.errors.full_messages }, status: :unprocessable_entity
@@ -195,16 +194,39 @@ class Projects::IssuesController < Projects::ApplicationController
respond_to do |format|
format.json do
- render json: { can_create_branch: can_create }
+ render json: { can_create_branch: can_create, has_related_branch: @issue.has_related_branch? }
end
end
end
+ def realtime_changes
+ Gitlab::PollingInterval.set_header(response, interval: 3_000)
+
+ render json: {
+ title: view_context.markdown_field(@issue, :title),
+ title_text: @issue.title,
+ description: view_context.markdown_field(@issue, :description),
+ description_text: @issue.description,
+ task_status: @issue.task_status,
+ updated_at: @issue.updated_at
+ }
+ end
+
+ def create_merge_request
+ result = MergeRequests::CreateFromIssueService.new(project, current_user, issue_iid: issue.iid).execute
+
+ if result[:status] == :success
+ render json: MergeRequestCreateSerializer.new.represent(result[:merge_request])
+ else
+ render json: result[:messsage], status: :unprocessable_entity
+ end
+ end
+
protected
def issue
# The Sortable default scope causes performance issues when used with find_by
- @noteable = @issue ||= @project.issues.where(iid: params[:id]).reorder(nil).take || redirect_old
+ @noteable = @issue ||= @project.issues.where(iid: params[:id]).reorder(nil).take!
end
alias_method :subscribable_resource, :issue
alias_method :issuable, :issue
@@ -223,6 +245,10 @@ class Projects::IssuesController < Projects::ApplicationController
return render_404 unless can?(current_user, :admin_issue, @project)
end
+ def authorize_create_merge_request!
+ return render_404 unless can?(current_user, :push_code, @project) && @issue.can_be_worked_on?(current_user)
+ end
+
def module_enabled
return render_404 unless @project.feature_available?(:issues, current_user) && @project.default_issues_tracker?
end
@@ -239,25 +265,10 @@ class Projects::IssuesController < Projects::ApplicationController
end
end
- # Since iids are implemented only in 6.1
- # user may navigate to issue page using old global ids.
- #
- # To prevent 404 errors we provide a redirect to correct iids until 7.0 release
- #
- def redirect_old
- issue = @project.issues.find_by(id: params[:id])
-
- if issue
- redirect_to issue_path(issue)
- else
- raise ActiveRecord::RecordNotFound.new
- end
- end
-
def issue_params
params.require(:issue).permit(
:title, :assignee_id, :position, :description, :confidential,
- :milestone_id, :due_date, :state_event, :task_num, :lock_version, label_ids: []
+ :milestone_id, :due_date, :state_event, :task_num, :lock_version, label_ids: [], assignee_ids: []
)
end
@@ -266,7 +277,10 @@ class Projects::IssuesController < Projects::ApplicationController
notice = "Please sign in to create the new issue."
- store_location_for :user, request.fullpath
+ if request.get? && !request.xhr?
+ store_location_for :user, request.fullpath
+ end
+
redirect_to new_user_session_path, notice: notice
end
end
diff --git a/app/controllers/projects/labels_controller.rb b/app/controllers/projects/labels_controller.rb
index 2f55ba4e700..71bfb7163da 100644
--- a/app/controllers/projects/labels_controller.rb
+++ b/app/controllers/projects/labels_controller.rb
@@ -19,7 +19,7 @@ class Projects::LabelsController < Projects::ApplicationController
respond_to do |format|
format.html
format.json do
- render json: @available_labels.as_json(only: [:id, :title, :color])
+ render json: LabelSerializer.new.represent_appearance(@available_labels)
end
end
end
diff --git a/app/controllers/projects/lfs_api_controller.rb b/app/controllers/projects/lfs_api_controller.rb
index 8a5a645ed0e..1b0d3aab3fa 100644
--- a/app/controllers/projects/lfs_api_controller.rb
+++ b/app/controllers/projects/lfs_api_controller.rb
@@ -22,7 +22,7 @@ class Projects::LfsApiController < Projects::GitHttpClientController
render(
json: {
message: 'Server supports batch API only, please update your Git LFS client to version 1.0.1 and up.',
- documentation_url: "#{Gitlab.config.gitlab.url}/help",
+ documentation_url: "#{Gitlab.config.gitlab.url}/help"
},
status: 501
)
@@ -55,7 +55,7 @@ class Projects::LfsApiController < Projects::GitHttpClientController
else
object[:error] = {
code: 404,
- message: "Object does not exist on the server or you don't have permissions to access it",
+ message: "Object does not exist on the server or you don't have permissions to access it"
}
end
end
diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb
index 9621b30b251..0352065998b 100755..100644
--- a/app/controllers/projects/merge_requests_controller.rb
+++ b/app/controllers/projects/merge_requests_controller.rb
@@ -3,22 +3,21 @@ class Projects::MergeRequestsController < Projects::ApplicationController
include DiffForPath
include DiffHelper
include IssuableActions
- include NotesHelper
+ include RendersNotes
include ToggleAwardEmoji
include IssuableCollections
before_action :module_enabled
before_action :merge_request, only: [
- :edit, :update, :show, :diffs, :commits, :conflicts, :conflict_for_path, :pipelines, :merge, :merge_check,
- :ci_status, :pipeline_status, :ci_environments_status, :toggle_subscription, :cancel_merge_when_pipeline_succeeds, :remove_wip, :resolve_conflicts, :assign_related_issues
+ :edit, :update, :show, :diffs, :commits, :conflicts, :conflict_for_path, :pipelines, :merge,
+ :pipeline_status, :ci_environments_status, :toggle_subscription, :cancel_merge_when_pipeline_succeeds, :remove_wip, :resolve_conflicts, :assign_related_issues, :commit_change_content
]
before_action :validates_merge_request, only: [:show, :diffs, :commits, :pipelines]
- before_action :define_show_vars, only: [:show, :diffs, :commits, :conflicts, :conflict_for_path, :builds, :pipelines]
- before_action :define_widget_vars, only: [:merge, :cancel_merge_when_pipeline_succeeds, :merge_check]
+ before_action :define_show_vars, only: [:diffs, :commits, :conflicts, :conflict_for_path, :builds, :pipelines]
before_action :define_commit_vars, only: [:diffs]
- before_action :define_diff_comment_vars, only: [:diffs]
before_action :ensure_ref_fetched, only: [:show, :diffs, :commits, :builds, :conflicts, :conflict_for_path, :pipelines]
before_action :close_merge_request_without_source_project, only: [:show, :diffs, :commits, :builds, :pipelines]
+ before_action :check_if_can_be_merged, only: :show
before_action :apply_diff_view_cookie!, only: [:new_diffs]
before_action :build_merge_request, only: [:new, :new_diffs]
@@ -39,10 +38,11 @@ class Projects::MergeRequestsController < Projects::ApplicationController
@collection_type = "MergeRequest"
@merge_requests = merge_requests_collection
@merge_requests = @merge_requests.page(params[:page])
+ @merge_requests = @merge_requests.preload(merge_request_diff: :merge_request)
@issuable_meta_data = issuable_meta_data(@merge_requests, @collection_type)
if @merge_requests.out_of_range? && @merge_requests.total_pages != 0
- return redirect_to url_for(params.merge(page: @merge_requests.total_pages))
+ return redirect_to url_for(params.merge(page: @merge_requests.total_pages, only_path: true))
end
if params[:label_name].present?
@@ -74,10 +74,15 @@ class Projects::MergeRequestsController < Projects::ApplicationController
def show
respond_to do |format|
- format.html { define_discussion_vars }
+ format.html do
+ define_discussion_vars
+ define_show_vars
+ end
format.json do
- render json: MergeRequestSerializer.new.represent(@merge_request)
+ Gitlab::PollingInterval.set_header(response, interval: 10_000)
+
+ render json: serializer.represent(@merge_request, basic: params[:basic])
end
format.patch do
@@ -100,34 +105,11 @@ class Projects::MergeRequestsController < Projects::ApplicationController
respond_to do |format|
format.html { define_discussion_vars }
format.json do
- @merge_request_diff =
- if params[:diff_id]
- @merge_request.merge_request_diffs.viewable.find(params[:diff_id])
- else
- @merge_request.merge_request_diff
- end
-
- @merge_request_diffs = @merge_request.merge_request_diffs.viewable.select_without_diff
- @comparable_diffs = @merge_request_diffs.select { |diff| diff.id < @merge_request_diff.id }
-
- if params[:start_sha].present?
- @start_sha = params[:start_sha]
- @start_version = @comparable_diffs.find { |diff| diff.head_commit_sha == @start_sha }
-
- unless @start_version
- @start_sha = @merge_request_diff.head_commit_sha
- @start_version = @merge_request_diff
- end
- end
+ define_diff_vars
+ define_diff_comment_vars
@environment = @merge_request.environments_for(current_user).last
- if @start_sha
- compared_diff_version
- else
- original_diff_version
- end
-
render json: { html: view_to_html_string("projects/merge_requests/show/_diffs") }
end
end
@@ -139,16 +121,18 @@ class Projects::MergeRequestsController < Projects::ApplicationController
def diff_for_path
if params[:id]
merge_request
+ define_diff_vars
define_diff_comment_vars
else
build_merge_request
+ @compare = @merge_request
+ @diffs = @compare.diffs(diff_options)
@diff_notes_disabled = true
- @grouped_diff_discussions = {}
end
define_commit_vars
- render_diff_for_path(@merge_request.diffs(diff_options))
+ render_diff_for_path(@diffs)
end
def commits
@@ -175,8 +159,8 @@ class Projects::MergeRequestsController < Projects::ApplicationController
format.html { define_discussion_vars }
format.json do
- if @merge_request.conflicts_can_be_resolved_in_ui?
- render json: @merge_request.conflicts
+ if @conflicts_list.can_be_resolved_in_ui?
+ render json: @conflicts_list
elsif @merge_request.can_be_merged?
render json: {
message: 'The merge conflicts for this merge request have already been resolved. Please return to the merge request.',
@@ -193,9 +177,9 @@ class Projects::MergeRequestsController < Projects::ApplicationController
end
def conflict_for_path
- return render_404 unless @merge_request.conflicts_can_be_resolved_in_ui?
+ return render_404 unless @conflicts_list.can_be_resolved_in_ui?
- file = @merge_request.conflicts.file_for_path(params[:old_path], params[:new_path])
+ file = @conflicts_list.file_for_path(params[:old_path], params[:new_path])
return render_404 unless file
@@ -203,7 +187,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController
end
def resolve_conflicts
- return render_404 unless @merge_request.conflicts_can_be_resolved_in_ui?
+ return render_404 unless @conflicts_list.can_be_resolved_in_ui?
if @merge_request.can_be_merged?
render status: :bad_request, json: { message: 'The merge conflicts for this merge request have already been resolved.' }
@@ -211,7 +195,9 @@ class Projects::MergeRequestsController < Projects::ApplicationController
end
begin
- MergeRequests::ResolveService.new(@merge_request.source_project, current_user, params).execute(@merge_request)
+ MergeRequests::Conflicts::ResolveService.
+ new(merge_request).
+ execute(current_user, params)
flash[:notice] = 'All merge conflicts were resolved. The merge request can now be merged.'
@@ -232,8 +218,10 @@ class Projects::MergeRequestsController < Projects::ApplicationController
end
format.json do
+ Gitlab::PollingInterval.set_header(response, interval: 10_000)
+
render json: PipelineSerializer
- .new(project: @project, user: @current_user)
+ .new(project: @project, current_user: @current_user)
.represent(@pipelines)
end
end
@@ -245,9 +233,11 @@ class Projects::MergeRequestsController < Projects::ApplicationController
format.json do
define_pipelines_vars
+ Gitlab::PollingInterval.set_header(response, interval: 10_000)
+
render json: {
pipelines: PipelineSerializer
- .new(project: @project, user: @current_user)
+ .new(project: @project, current_user: @current_user)
.represent(@pipelines)
}
end
@@ -316,17 +306,15 @@ class Projects::MergeRequestsController < Projects::ApplicationController
end
def remove_wip
- MergeRequests::UpdateService.new(project, current_user, wip_event: 'unwip').execute(@merge_request)
+ @merge_request = MergeRequests::UpdateService
+ .new(project, current_user, wip_event: 'unwip')
+ .execute(@merge_request)
- redirect_to namespace_project_merge_request_path(@project.namespace, @project, @merge_request),
- notice: "The merge request can now be merged."
+ render json: serializer.represent(@merge_request)
end
- def merge_check
- @merge_request.check_if_can_be_merged
- @pipelines = @merge_request.all_pipelines
-
- render partial: "projects/merge_requests/widget/show.html.haml", layout: false
+ def commit_change_content
+ render partial: 'projects/merge_requests/widget/commit_change_content', layout: false
end
def cancel_merge_when_pipeline_succeeds
@@ -337,65 +325,22 @@ class Projects::MergeRequestsController < Projects::ApplicationController
MergeRequests::MergeWhenPipelineSucceedsService
.new(@project, current_user)
.cancel(@merge_request)
+
+ render json: serializer.represent(@merge_request)
end
def merge
return access_denied! unless @merge_request.can_be_merged_by?(current_user)
- # Disable the CI check if merge_when_pipeline_succeeds is enabled since we have
- # to wait until CI completes to know
- unless @merge_request.mergeable?(skip_ci_check: merge_when_pipeline_succeeds_active?)
- @status = :failed
- return
- end
-
- if params[:sha] != @merge_request.diff_head_sha
- @status = :sha_mismatch
- return
- end
-
- @merge_request.update(merge_error: nil)
-
- if params[:merge_when_pipeline_succeeds].present?
- unless @merge_request.head_pipeline
- @status = :failed
- return
- end
-
- if @merge_request.head_pipeline.active?
- MergeRequests::MergeWhenPipelineSucceedsService
- .new(@project, current_user, merge_params)
- .execute(@merge_request)
+ status = merge!
- @status = :merge_when_pipeline_succeeds
- elsif @merge_request.head_pipeline.success?
- # This can be triggered when a user clicks the auto merge button while
- # the tests finish at about the same time
- MergeWorker.perform_async(@merge_request.id, current_user.id, params)
- @status = :success
- else
- @status = :failed
- end
+ if @merge_request.merge_error
+ render json: { status: status, merge_error: @merge_request.merge_error }
else
- MergeWorker.perform_async(@merge_request.id, current_user.id, params)
- @status = :success
+ render json: { status: status }
end
end
- def merge_widget_refresh
- @status =
- if merge_request.merge_when_pipeline_succeeds
- :merge_when_pipeline_succeeds
- else
- # Only MRs that can be merged end in this action
- # MR can be already picked up for merge / merged already or can be waiting for worker to be picked up
- # in last case it does not have any special status. Possible error is handled inside widget js function
- :success
- end
-
- render 'merge'
- end
-
def branch_from
# This is always source
@source_project = @merge_request.nil? ? @project : @merge_request.source_project
@@ -445,37 +390,9 @@ class Projects::MergeRequestsController < Projects::ApplicationController
end
end
- def ci_status
- pipeline = @merge_request.head_pipeline
- @pipelines = @merge_request.all_pipelines
-
- if pipeline
- status = pipeline.status
- coverage = pipeline.try(:coverage)
-
- status = "success_with_warnings" if pipeline.success? && pipeline.has_warnings?
-
- status ||= "preparing"
- else
- ci_service = @merge_request.source_project.try(:ci_service)
- status = ci_service.commit_status(merge_request.diff_head_sha, merge_request.source_branch) if ci_service
- end
-
- response = {
- title: merge_request.title,
- sha: (merge_request.diff_head_commit.short_id if merge_request.diff_head_sha),
- status: status,
- coverage: coverage,
- pipeline: pipeline.try(:id),
- has_ci: @merge_request.has_ci?
- }
-
- render json: response
- end
-
def pipeline_status
render json: PipelineSerializer
- .new(project: @project, user: @current_user)
+ .new(project: @project, current_user: @current_user)
.represent_status(@merge_request.head_pipeline)
end
@@ -491,10 +408,19 @@ class Projects::MergeRequestsController < Projects::ApplicationController
stop_namespace_project_environment_path(project.namespace, project, environment)
end
+ metrics_url =
+ if can?(current_user, :read_environment, environment) && environment.has_metrics?
+ metrics_namespace_project_environment_deployment_path(environment.project.namespace,
+ environment.project,
+ environment,
+ deployment)
+ end
+
{
id: environment.id,
name: environment.name,
url: namespace_project_environment_path(project.namespace, project, environment),
+ metrics_url: metrics_url,
stop_url: stop_url,
external_url: environment.external_url,
external_url_formatted: environment.formatted_external_url,
@@ -533,7 +459,9 @@ class Projects::MergeRequestsController < Projects::ApplicationController
end
def authorize_can_resolve_conflicts!
- return render_404 unless @merge_request.conflicts_can_be_resolved_by?(current_user)
+ @conflicts_list = MergeRequests::Conflicts::ListService.new(@merge_request)
+
+ return render_404 unless @conflicts_list.can_be_resolved_by?(current_user)
end
def module_enabled
@@ -569,24 +497,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController
@note = @project.notes.new(noteable: @merge_request)
@discussions = @merge_request.discussions
-
- preload_noteable_for_regular_notes(@discussions.flat_map(&:notes))
-
- # This is not executed lazily
- @notes = Banzai::NoteRenderer.render(
- @discussions.flat_map(&:notes),
- @project,
- current_user,
- @path,
- @project_wiki,
- @ref
- )
-
- preload_max_access_for_authors(@notes, @project)
- end
-
- def define_widget_vars
- @pipeline = @merge_request.head_pipeline
+ @notes = prepare_notes_for_rendering(@discussions.flat_map(&:notes))
end
def define_commit_vars
@@ -594,23 +505,49 @@ class Projects::MergeRequestsController < Projects::ApplicationController
@base_commit = @merge_request.diff_base_commit || @merge_request.likely_diff_base_commit
end
+ def define_diff_vars
+ @merge_request_diff =
+ if params[:diff_id]
+ @merge_request.merge_request_diffs.viewable.find(params[:diff_id])
+ else
+ @merge_request.merge_request_diff
+ end
+
+ @merge_request_diffs = @merge_request.merge_request_diffs.viewable.select_without_diff
+ @comparable_diffs = @merge_request_diffs.select { |diff| diff.id < @merge_request_diff.id }
+
+ if params[:start_sha].present?
+ @start_sha = params[:start_sha]
+ @start_version = @comparable_diffs.find { |diff| diff.head_commit_sha == @start_sha }
+
+ unless @start_version
+ @start_sha = @merge_request_diff.head_commit_sha
+ @start_version = @merge_request_diff
+ end
+ end
+
+ @compare =
+ if @start_sha
+ @merge_request_diff.compare_with(@start_sha)
+ else
+ @merge_request_diff
+ end
+
+ @diffs = @compare.diffs(diff_options)
+ end
+
def define_diff_comment_vars
- @comments_target = {
+ @new_diff_note_attrs = {
noteable_type: 'MergeRequest',
noteable_id: @merge_request.id
}
+ @diff_notes_disabled = false
+
@use_legacy_diff_notes = !@merge_request.has_complete_diff_refs?
- @grouped_diff_discussions = @merge_request.notes.inc_relations_for_view.grouped_diff_discussions
- Banzai::NoteRenderer.render(
- @grouped_diff_discussions.values.flat_map(&:notes),
- @project,
- current_user,
- @path,
- @project_wiki,
- @ref
- )
+ @grouped_diff_discussions = @merge_request.grouped_diff_discussions(@compare.diff_refs)
+ @notes = prepare_notes_for_rendering(@grouped_diff_discussions.values.flatten.flat_map(&:notes))
end
def define_pipelines_vars
@@ -693,19 +630,55 @@ class Projects::MergeRequestsController < Projects::ApplicationController
@merge_request = MergeRequests::BuildService.new(project, current_user, merge_request_params.merge(diff_options: diff_options)).execute
end
- def compared_diff_version
- @diff_notes_disabled = true
- @diffs = @merge_request_diff.compare_with(@start_sha).diffs(diff_options)
+ def close_merge_request_without_source_project
+ if !@merge_request.source_project && @merge_request.open?
+ @merge_request.close
+ end
end
- def original_diff_version
- @diff_notes_disabled = !@merge_request_diff.latest?
- @diffs = @merge_request_diff.diffs(diff_options)
+ private
+
+ def check_if_can_be_merged
+ @merge_request.check_if_can_be_merged
end
- def close_merge_request_without_source_project
- if !@merge_request.source_project && @merge_request.open?
- @merge_request.close
+ def merge!
+ # Disable the CI check if merge_when_pipeline_succeeds is enabled since we have
+ # to wait until CI completes to know
+ unless @merge_request.mergeable?(skip_ci_check: merge_when_pipeline_succeeds_active?)
+ return :failed
end
+
+ return :sha_mismatch if params[:sha] != @merge_request.diff_head_sha
+
+ @merge_request.update(merge_error: nil)
+
+ if params[:merge_when_pipeline_succeeds].present?
+ return :failed unless @merge_request.head_pipeline
+
+ if @merge_request.head_pipeline.active?
+ MergeRequests::MergeWhenPipelineSucceedsService
+ .new(@project, current_user, merge_params)
+ .execute(@merge_request)
+
+ :merge_when_pipeline_succeeds
+ elsif @merge_request.head_pipeline.success?
+ # This can be triggered when a user clicks the auto merge button while
+ # the tests finish at about the same time
+ MergeWorker.perform_async(@merge_request.id, current_user.id, params)
+
+ :success
+ else
+ :failed
+ end
+ else
+ MergeWorker.perform_async(@merge_request.id, current_user.id, params)
+
+ :success
+ end
+ end
+
+ def serializer
+ MergeRequestSerializer.new(current_user: current_user, project: merge_request.project)
end
end
diff --git a/app/controllers/projects/milestones_controller.rb b/app/controllers/projects/milestones_controller.rb
index 5922e686cd0..c56bce19eee 100644
--- a/app/controllers/projects/milestones_controller.rb
+++ b/app/controllers/projects/milestones_controller.rb
@@ -1,12 +1,14 @@
class Projects::MilestonesController < Projects::ApplicationController
+ include MilestoneActions
+
before_action :module_enabled
- before_action :milestone, only: [:edit, :update, :destroy, :show, :sort_issues, :sort_merge_requests]
+ before_action :milestone, only: [:edit, :update, :destroy, :show, :sort_issues, :sort_merge_requests, :merge_requests, :participants, :labels]
# Allow read any milestone
before_action :authorize_read_milestone!
# Allow admin milestone
- before_action :authorize_admin_milestone!, except: [:index, :show]
+ before_action :authorize_admin_milestone!, except: [:index, :show, :merge_requests, :participants, :labels]
respond_to :html
@@ -21,9 +23,10 @@ class Projects::MilestonesController < Projects::ApplicationController
@sort = params[:sort] || 'due_date_asc'
@milestones = @milestones.sort(@sort)
- @milestones = @milestones.includes(:project)
respond_to do |format|
format.html do
+ @project_namespace = @project.namespace.becomes(Namespace)
+ @milestones = @milestones.includes(:project)
@milestones = @milestones.page(params[:page])
end
format.json do
diff --git a/app/controllers/projects/notes_controller.rb b/app/controllers/projects/notes_controller.rb
index d00177e7612..41a13f6f577 100644
--- a/app/controllers/projects/notes_controller.rb
+++ b/app/controllers/projects/notes_controller.rb
@@ -1,62 +1,22 @@
class Projects::NotesController < Projects::ApplicationController
+ include NotesActions
include ToggleAwardEmoji
- # Authorize
before_action :authorize_read_note!
before_action :authorize_create_note!, only: [:create]
- before_action :authorize_admin_note!, only: [:update, :destroy]
before_action :authorize_resolve_note!, only: [:resolve, :unresolve]
- before_action :find_current_user_notes, only: [:index]
-
- def index
- current_fetched_at = Time.now.to_i
-
- notes_json = { notes: [], last_fetched_at: current_fetched_at }
-
- @notes.each do |note|
- next if note.cross_reference_not_visible_for?(current_user)
-
- notes_json[:notes] << note_json(note)
- end
-
- render json: notes_json
- end
+ #
+ # This is a fix to make spinach feature tests passing:
+ # Controller actions are returned from AbstractController::Base and methods of parent classes are
+ # excluded in order to return only specific controller related methods.
+ # That is ok for the app (no :create method in ancestors)
+ # but fails for tests because there is a :create method on FactoryGirl (one of the ancestors)
+ #
+ # see https://github.com/rails/rails/blob/v4.2.7/actionpack/lib/abstract_controller/base.rb#L78
+ #
def create
- create_params = note_params.merge(merge_request_diff_head_sha: params[:merge_request_diff_head_sha])
- @note = Notes::CreateService.new(project, current_user, create_params).execute
-
- if @note.is_a?(Note)
- Banzai::NoteRenderer.render([@note], @project, current_user)
- end
-
- respond_to do |format|
- format.json { render json: note_json(@note) }
- format.html { redirect_back_or_default }
- end
- end
-
- def update
- @note = Notes::UpdateService.new(project, current_user, note_params).execute(note)
-
- if @note.is_a?(Note)
- Banzai::NoteRenderer.render([@note], @project, current_user)
- end
-
- respond_to do |format|
- format.json { render json: note_json(@note) }
- format.html { redirect_back_or_default }
- end
- end
-
- def destroy
- if note.editable?
- Notes::DestroyService.new(project, current_user).execute(note)
- end
-
- respond_to do |format|
- format.js { head :ok }
- end
+ super
end
def delete_attachment
@@ -102,120 +62,11 @@ class Projects::NotesController < Projects::ApplicationController
end
alias_method :awardable, :note
- def note_html(note)
- render_to_string(
- "projects/notes/_note",
- layout: false,
- formats: [:html],
- locals: { note: note }
- )
- end
-
- def diff_discussion_html(discussion)
- return unless discussion.diff_discussion?
-
- if params[:view] == 'parallel'
- template = "discussions/_parallel_diff_discussion"
- locals =
- if params[:line_type] == 'old'
- { discussion_left: discussion, discussion_right: nil }
- else
- { discussion_left: nil, discussion_right: discussion }
- end
- else
- template = "discussions/_diff_discussion"
- locals = { discussion: discussion }
- end
-
- render_to_string(
- template,
- layout: false,
- formats: [:html],
- locals: locals
- )
- end
-
- def discussion_html(discussion)
- return unless discussion.diff_discussion?
-
- render_to_string(
- "discussions/_discussion",
- layout: false,
- formats: [:html],
- locals: { discussion: discussion }
- )
- end
-
- def note_json(note)
- attrs = {
- id: note.id
- }
-
- if note.persisted?
- Banzai::NoteRenderer.render([note], @project, current_user)
-
- attrs.merge!(
- valid: true,
- discussion_id: note.discussion_id,
- html: note_html(note),
- note: note.note
- )
-
- if note.diff_note?
- discussion = note.to_discussion
-
- attrs.merge!(
- diff_discussion_html: diff_discussion_html(discussion),
- discussion_html: discussion_html(discussion)
- )
-
- # The discussion_id is used to add the comment to the correct discussion
- # element on the merge request page. Among other things, the discussion_id
- # contains the sha of head commit of the merge request.
- # When new commits are pushed into the merge request after the initial
- # load of the merge request page, the discussion elements will still have
- # the old discussion_ids, with the old head commit sha. The new comment,
- # however, will have the new discussion_id with the new commit sha.
- # To ensure that these new comments will still end up in the correct
- # discussion element, we also send the original discussion_id, with the
- # old commit sha, along, and fall back on this value when no discussion
- # element with the new discussion_id could be found.
- if note.new_diff_note? && note.position != note.original_position
- attrs[:original_discussion_id] = note.original_discussion_id
- end
- end
- else
- attrs.merge!(
- valid: false,
- errors: note.errors
- )
- end
-
- attrs[:commands_changes] = note.commands_changes
- attrs
- end
-
- def authorize_admin_note!
- return access_denied! unless can?(current_user, :admin_note, note)
+ def finder_params
+ params.merge(last_fetched_at: last_fetched_at)
end
def authorize_resolve_note!
return access_denied! unless can?(current_user, :resolve_note, note)
end
-
- def note_params
- params.require(:note).permit(
- :note, :noteable, :noteable_id, :noteable_type, :project_id,
- :attachment, :line_code, :commit_id, :type, :position
- )
- end
-
- def find_current_user_notes
- @notes = NotesFinder.new(project, current_user, params.merge(last_fetched_at: last_fetched_at))
- .execute.inc_author
- end
-
- def last_fetched_at
- request.headers['X-Last-Fetched-At']
- end
end
diff --git a/app/controllers/projects/pages_controller.rb b/app/controllers/projects/pages_controller.rb
index fbd18b68141..93b2c180810 100644
--- a/app/controllers/projects/pages_controller.rb
+++ b/app/controllers/projects/pages_controller.rb
@@ -1,6 +1,7 @@
class Projects::PagesController < Projects::ApplicationController
layout 'project_settings'
+ before_action :require_pages_enabled!
before_action :authorize_read_pages!, only: [:show]
before_action :authorize_update_pages!, except: [:show]
diff --git a/app/controllers/projects/pages_domains_controller.rb b/app/controllers/projects/pages_domains_controller.rb
index b8c253f6ae3..3a93977fd27 100644
--- a/app/controllers/projects/pages_domains_controller.rb
+++ b/app/controllers/projects/pages_domains_controller.rb
@@ -1,6 +1,7 @@
class Projects::PagesDomainsController < Projects::ApplicationController
layout 'project_settings'
+ before_action :require_pages_enabled!
before_action :authorize_update_pages!, except: [:show]
before_action :domain, only: [:show, :destroy]
diff --git a/app/controllers/projects/pipeline_schedules_controller.rb b/app/controllers/projects/pipeline_schedules_controller.rb
new file mode 100644
index 00000000000..1616b2cb6b8
--- /dev/null
+++ b/app/controllers/projects/pipeline_schedules_controller.rb
@@ -0,0 +1,68 @@
+class Projects::PipelineSchedulesController < Projects::ApplicationController
+ before_action :authorize_read_pipeline_schedule!
+ before_action :authorize_create_pipeline_schedule!, only: [:new, :create, :edit, :take_ownership, :update]
+ before_action :authorize_admin_pipeline_schedule!, only: [:destroy]
+
+ before_action :schedule, only: [:edit, :update, :destroy, :take_ownership]
+
+ def index
+ @scope = params[:scope]
+ @all_schedules = PipelineSchedulesFinder.new(@project).execute
+ @schedules = PipelineSchedulesFinder.new(@project).execute(scope: params[:scope])
+ .includes(:last_pipeline)
+ end
+
+ def new
+ @schedule = project.pipeline_schedules.new
+ end
+
+ def create
+ @schedule = Ci::CreatePipelineScheduleService
+ .new(@project, current_user, schedule_params)
+ .execute
+
+ if @schedule.persisted?
+ redirect_to pipeline_schedules_path(@project)
+ else
+ render :new
+ end
+ end
+
+ def edit
+ end
+
+ def update
+ if schedule.update(schedule_params)
+ redirect_to namespace_project_pipeline_schedules_path(@project.namespace.becomes(Namespace), @project)
+ else
+ render :edit
+ end
+ end
+
+ def take_ownership
+ if schedule.update(owner: current_user)
+ redirect_to pipeline_schedules_path(@project)
+ else
+ redirect_to pipeline_schedules_path(@project), alert: "Failed to change the owner"
+ end
+ end
+
+ def destroy
+ if schedule.destroy
+ redirect_to pipeline_schedules_path(@project)
+ else
+ redirect_to pipeline_schedules_path(@project), alert: "Failed to remove the pipeline schedule"
+ end
+ end
+
+ private
+
+ def schedule
+ @schedule ||= project.pipeline_schedules.find(params[:id])
+ end
+
+ def schedule_params
+ params.require(:schedule)
+ .permit(:description, :cron, :cron_timezone, :ref, :active)
+ end
+end
diff --git a/app/controllers/projects/pipelines_controller.rb b/app/controllers/projects/pipelines_controller.rb
index 43a1abaa662..602d3dd8c1c 100644
--- a/app/controllers/projects/pipelines_controller.rb
+++ b/app/controllers/projects/pipelines_controller.rb
@@ -1,27 +1,31 @@
class Projects::PipelinesController < Projects::ApplicationController
before_action :pipeline, except: [:index, :new, :create, :charts]
- before_action :commit, only: [:show, :builds]
+ before_action :commit, only: [:show, :builds, :failures]
before_action :authorize_read_pipeline!
before_action :authorize_create_pipeline!, only: [:new, :create]
before_action :authorize_update_pipeline!, only: [:retry, :cancel]
before_action :builds_enabled, only: :charts
+ wrap_parameters Ci::Pipeline
+
+ POLLING_INTERVAL = 10_000
+
def index
@scope = params[:scope]
@pipelines = PipelinesFinder
- .new(project)
- .execute(scope: @scope)
+ .new(project, scope: @scope)
+ .execute
.page(params[:page])
.per(30)
@running_count = PipelinesFinder
- .new(project).execute(scope: 'running').count
+ .new(project, scope: 'running').execute.count
@pending_count = PipelinesFinder
- .new(project).execute(scope: 'pending').count
+ .new(project, scope: 'pending').execute.count
@finished_count = PipelinesFinder
- .new(project).execute(scope: 'finished').count
+ .new(project, scope: 'finished').execute.count
@pipelines_count = PipelinesFinder
.new(project).execute.count
@@ -29,16 +33,18 @@ class Projects::PipelinesController < Projects::ApplicationController
respond_to do |format|
format.html
format.json do
+ Gitlab::PollingInterval.set_header(response, interval: POLLING_INTERVAL)
+
render json: {
pipelines: PipelineSerializer
- .new(project: @project, user: @current_user)
+ .new(project: @project, current_user: @current_user)
.with_pagination(request, response)
.represent(@pipelines),
count: {
all: @pipelines_count,
running: @running_count,
pending: @pending_count,
- finished: @finished_count,
+ finished: @finished_count
}
}
end
@@ -53,28 +59,42 @@ class Projects::PipelinesController < Projects::ApplicationController
@pipeline = Ci::CreatePipelineService
.new(project, current_user, create_params)
.execute(ignore_skip_ci: true, save_on_errors: false)
- unless @pipeline.persisted?
+
+ if @pipeline.persisted?
+ redirect_to namespace_project_pipeline_path(project.namespace, project, @pipeline)
+ else
render 'new'
- return
end
-
- redirect_to namespace_project_pipeline_path(project.namespace, project, @pipeline)
end
def show
+ respond_to do |format|
+ format.html
+ format.json do
+ Gitlab::PollingInterval.set_header(response, interval: POLLING_INTERVAL)
+
+ render json: PipelineSerializer
+ .new(project: @project, current_user: @current_user)
+ .represent(@pipeline, grouped: true)
+ end
+ end
end
def builds
- respond_to do |format|
- format.html do
- render 'show'
- end
+ render_show
+ end
+
+ def failures
+ if @pipeline.statuses.latest.failed.present?
+ render_show
+ else
+ redirect_to pipeline_path(@pipeline)
end
end
def status
render json: PipelineSerializer
- .new(project: @project, user: @current_user)
+ .new(project: @project, current_user: @current_user)
.represent_status(@pipeline)
end
@@ -90,13 +110,25 @@ class Projects::PipelinesController < Projects::ApplicationController
def retry
pipeline.retry_failed(current_user)
- redirect_back_or_default default: namespace_project_pipelines_path(project.namespace, project)
+ respond_to do |format|
+ format.html do
+ redirect_back_or_default default: namespace_project_pipelines_path(project.namespace, project)
+ end
+
+ format.json { head :no_content }
+ end
end
def cancel
pipeline.cancel_running
- redirect_back_or_default default: namespace_project_pipelines_path(project.namespace, project)
+ respond_to do |format|
+ format.html do
+ redirect_back_or_default default: namespace_project_pipelines_path(project.namespace, project)
+ end
+
+ format.json { head :no_content }
+ end
end
def charts
@@ -109,12 +141,20 @@ class Projects::PipelinesController < Projects::ApplicationController
private
+ def render_show
+ respond_to do |format|
+ format.html do
+ render 'show'
+ end
+ end
+ end
+
def create_params
params.require(:pipeline).permit(:ref)
end
def pipeline
- @pipeline ||= project.pipelines.find_by!(id: params[:id])
+ @pipeline ||= project.pipelines.find_by!(id: params[:id]).present(current_user: current_user)
end
def commit
diff --git a/app/controllers/projects/pipelines_settings_controller.rb b/app/controllers/projects/pipelines_settings_controller.rb
index c8c80551ac9..38a47651000 100644
--- a/app/controllers/projects/pipelines_settings_controller.rb
+++ b/app/controllers/projects/pipelines_settings_controller.rb
@@ -7,7 +7,7 @@ class Projects::PipelinesSettingsController < Projects::ApplicationController
def update
if @project.update_attributes(update_params)
- flash[:notice] = "CI/CD Pipelines settings for '#{@project.name}' were successfully updated."
+ flash[:notice] = "Pipelines settings for '#{@project.name}' were successfully updated."
redirect_to namespace_project_settings_ci_cd_path(@project.namespace, @project)
else
render 'show'
@@ -23,7 +23,7 @@ class Projects::PipelinesSettingsController < Projects::ApplicationController
def update_params
params.require(:project).permit(
:runners_token, :builds_enabled, :build_allow_git_fetch, :build_timeout_in_minutes, :build_coverage_regex,
- :public_builds
+ :public_builds, :auto_cancel_pending_pipelines
)
end
end
diff --git a/app/controllers/projects/project_members_controller.rb b/app/controllers/projects/project_members_controller.rb
index 6e158e685e9..d2d26738582 100644
--- a/app/controllers/projects/project_members_controller.rb
+++ b/app/controllers/projects/project_members_controller.rb
@@ -10,18 +10,6 @@ class Projects::ProjectMembersController < Projects::ApplicationController
redirect_to namespace_project_settings_members_path(@project.namespace, @project, sort: sort)
end
- def create
- status = Members::CreateService.new(@project, current_user, params).execute
-
- redirect_url = namespace_project_settings_members_path(@project.namespace, @project)
-
- if status
- redirect_to redirect_url, notice: 'Users were successfully added.'
- else
- redirect_to redirect_url, alert: 'No users or groups specified.'
- end
- end
-
def update
@project_member = @project.project_members.find(params[:id])
@@ -30,18 +18,6 @@ class Projects::ProjectMembersController < Projects::ApplicationController
@project_member.update_attributes(member_params)
end
- def destroy
- Members::DestroyService.new(@project, current_user, params).
- execute(:all)
-
- respond_to do |format|
- format.html do
- redirect_to namespace_project_settings_members_path(@project.namespace, @project)
- end
- format.js { head :ok }
- end
- end
-
def resend_invite
redirect_path = namespace_project_settings_members_path(@project.namespace, @project)
diff --git a/app/controllers/projects/protected_branches_controller.rb b/app/controllers/projects/protected_branches_controller.rb
index a8cb07eb67a..ba24fa9acfe 100644
--- a/app/controllers/projects/protected_branches_controller.rb
+++ b/app/controllers/projects/protected_branches_controller.rb
@@ -1,58 +1,23 @@
-class Projects::ProtectedBranchesController < Projects::ApplicationController
- include RepositorySettingsRedirect
- # Authorize
- before_action :require_non_empty_project
- before_action :authorize_admin_project!
- before_action :load_protected_branch, only: [:show, :update, :destroy]
+class Projects::ProtectedBranchesController < Projects::ProtectedRefsController
+ protected
- layout "project_settings"
-
- def index
- redirect_to_repository_settings(@project)
- end
-
- def create
- @protected_branch = ::ProtectedBranches::CreateService.new(@project, current_user, protected_branch_params).execute
- unless @protected_branch.persisted?
- flash[:alert] = @protected_branches.errors.full_messages.join(', ').html_safe
- end
- redirect_to_repository_settings(@project)
- end
-
- def show
- @matching_branches = @protected_branch.matching(@project.repository.branches)
+ def project_refs
+ @project.repository.branches
end
- def update
- @protected_branch = ::ProtectedBranches::UpdateService.new(@project, current_user, protected_branch_params).execute(@protected_branch)
-
- if @protected_branch.valid?
- respond_to do |format|
- format.json { render json: @protected_branch, status: :ok }
- end
- else
- respond_to do |format|
- format.json { render json: @protected_branch.errors, status: :unprocessable_entity }
- end
- end
+ def create_service_class
+ ::ProtectedBranches::CreateService
end
- def destroy
- @protected_branch.destroy
-
- respond_to do |format|
- format.html { redirect_to_repository_settings(@project) }
- format.js { head :ok }
- end
+ def update_service_class
+ ::ProtectedBranches::UpdateService
end
- private
-
- def load_protected_branch
- @protected_branch = @project.protected_branches.find(params[:id])
+ def load_protected_ref
+ @protected_ref = @project.protected_branches.find(params[:id])
end
- def protected_branch_params
+ def protected_ref_params
params.require(:protected_branch).permit(:name,
merge_access_levels_attributes: [:access_level, :id],
push_access_levels_attributes: [:access_level, :id])
diff --git a/app/controllers/projects/protected_refs_controller.rb b/app/controllers/projects/protected_refs_controller.rb
new file mode 100644
index 00000000000..083a70968e5
--- /dev/null
+++ b/app/controllers/projects/protected_refs_controller.rb
@@ -0,0 +1,47 @@
+class Projects::ProtectedRefsController < Projects::ApplicationController
+ include RepositorySettingsRedirect
+
+ # Authorize
+ before_action :require_non_empty_project
+ before_action :authorize_admin_project!
+ before_action :load_protected_ref, only: [:show, :update, :destroy]
+
+ layout "project_settings"
+
+ def index
+ redirect_to_repository_settings(@project)
+ end
+
+ def create
+ protected_ref = create_service_class.new(@project, current_user, protected_ref_params).execute
+
+ unless protected_ref.persisted?
+ flash[:alert] = protected_ref.errors.full_messages.join(', ').html_safe
+ end
+
+ redirect_to_repository_settings(@project)
+ end
+
+ def show
+ @matching_refs = @protected_ref.matching(project_refs)
+ end
+
+ def update
+ @protected_ref = update_service_class.new(@project, current_user, protected_ref_params).execute(@protected_ref)
+
+ if @protected_ref.valid?
+ render json: @protected_ref, status: :ok
+ else
+ render json: @protected_ref.errors, status: :unprocessable_entity
+ end
+ end
+
+ def destroy
+ @protected_ref.destroy
+
+ respond_to do |format|
+ format.html { redirect_to_repository_settings(@project) }
+ format.js { head :ok }
+ end
+ end
+end
diff --git a/app/controllers/projects/protected_tags_controller.rb b/app/controllers/projects/protected_tags_controller.rb
new file mode 100644
index 00000000000..c61ddf145e6
--- /dev/null
+++ b/app/controllers/projects/protected_tags_controller.rb
@@ -0,0 +1,23 @@
+class Projects::ProtectedTagsController < Projects::ProtectedRefsController
+ protected
+
+ def project_refs
+ @project.repository.tags
+ end
+
+ def create_service_class
+ ::ProtectedTags::CreateService
+ end
+
+ def update_service_class
+ ::ProtectedTags::UpdateService
+ end
+
+ def load_protected_ref
+ @protected_ref = @project.protected_tags.find(params[:id])
+ end
+
+ def protected_ref_params
+ params.require(:protected_tag).permit(:name, create_access_levels_attributes: [:access_level, :id])
+ end
+end
diff --git a/app/controllers/projects/raw_controller.rb b/app/controllers/projects/raw_controller.rb
index c55b37ae0dd..a02cc477e08 100644
--- a/app/controllers/projects/raw_controller.rb
+++ b/app/controllers/projects/raw_controller.rb
@@ -15,7 +15,7 @@ class Projects::RawController < Projects::ApplicationController
return if cached_blob?
- if @blob.lfs_pointer? && project.lfs_enabled?
+ if @blob.stored_externally?
send_lfs_object
else
send_git_blob @repository, @blob
diff --git a/app/controllers/projects/registry/application_controller.rb b/app/controllers/projects/registry/application_controller.rb
new file mode 100644
index 00000000000..a56f9c58726
--- /dev/null
+++ b/app/controllers/projects/registry/application_controller.rb
@@ -0,0 +1,16 @@
+module Projects
+ module Registry
+ class ApplicationController < Projects::ApplicationController
+ layout 'project'
+
+ before_action :verify_registry_enabled!
+ before_action :authorize_read_container_image!
+
+ private
+
+ def verify_registry_enabled!
+ render_404 unless Gitlab.config.registry.enabled
+ end
+ end
+ end
+end
diff --git a/app/controllers/projects/registry/repositories_controller.rb b/app/controllers/projects/registry/repositories_controller.rb
new file mode 100644
index 00000000000..17f391ba07f
--- /dev/null
+++ b/app/controllers/projects/registry/repositories_controller.rb
@@ -0,0 +1,43 @@
+module Projects
+ module Registry
+ class RepositoriesController < ::Projects::Registry::ApplicationController
+ before_action :authorize_update_container_image!, only: [:destroy]
+ before_action :ensure_root_container_repository!, only: [:index]
+
+ def index
+ @images = project.container_repositories
+ end
+
+ def destroy
+ if image.destroy
+ redirect_to project_container_registry_path(@project),
+ notice: 'Image repository has been removed successfully!'
+ else
+ redirect_to project_container_registry_path(@project),
+ alert: 'Failed to remove image repository!'
+ end
+ end
+
+ private
+
+ def image
+ @image ||= project.container_repositories.find(params[:id])
+ end
+
+ ##
+ # Container repository object for root project path.
+ #
+ # Needed to maintain a backwards compatibility.
+ #
+ def ensure_root_container_repository!
+ ContainerRegistry::Path.new(@project.full_path).tap do |path|
+ break if path.has_repository?
+
+ ContainerRepository.build_from_path(path).tap do |repository|
+ repository.save! if repository.has_tags?
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/app/controllers/projects/registry/tags_controller.rb b/app/controllers/projects/registry/tags_controller.rb
new file mode 100644
index 00000000000..d689cade3ab
--- /dev/null
+++ b/app/controllers/projects/registry/tags_controller.rb
@@ -0,0 +1,28 @@
+module Projects
+ module Registry
+ class TagsController < ::Projects::Registry::ApplicationController
+ before_action :authorize_update_container_image!, only: [:destroy]
+
+ def destroy
+ if tag.delete
+ redirect_to project_container_registry_path(@project),
+ notice: 'Registry tag has been removed successfully!'
+ else
+ redirect_to project_container_registry_path(@project),
+ alert: 'Failed to remove registry tag!'
+ end
+ end
+
+ private
+
+ def image
+ @image ||= project.container_repositories
+ .find(params[:repository_id])
+ end
+
+ def tag
+ @tag ||= image.tag(params[:id])
+ end
+ end
+ end
+end
diff --git a/app/controllers/projects/settings/integrations_controller.rb b/app/controllers/projects/settings/integrations_controller.rb
index fb2a4837735..1ff08cce8cb 100644
--- a/app/controllers/projects/settings/integrations_controller.rb
+++ b/app/controllers/projects/settings/integrations_controller.rb
@@ -5,7 +5,7 @@ module Projects
before_action :authorize_admin_project!
layout "project_settings"
-
+
def show
@hooks = @project.hooks
@hook = ProjectHook.new
diff --git a/app/controllers/projects/settings/repository_controller.rb b/app/controllers/projects/settings/repository_controller.rb
index b6ce4abca45..44de8a49593 100644
--- a/app/controllers/projects/settings/repository_controller.rb
+++ b/app/controllers/projects/settings/repository_controller.rb
@@ -4,46 +4,48 @@ module Projects
before_action :authorize_admin_project!
def show
- @deploy_keys = DeployKeysPresenter
- .new(@project, current_user: current_user)
+ @deploy_keys = DeployKeysPresenter.new(@project, current_user: current_user)
- define_protected_branches
+ define_protected_refs
end
private
- def define_protected_branches
- load_protected_branches
+ def define_protected_refs
+ @protected_branches = @project.protected_branches.order(:name).page(params[:page])
+ @protected_tags = @project.protected_tags.order(:name).page(params[:page])
@protected_branch = @project.protected_branches.new
+ @protected_tag = @project.protected_tags.new
load_gon_index
end
- def load_protected_branches
- @protected_branches = @project.protected_branches.order(:name).page(params[:page])
- end
-
def access_levels_options
{
- push_access_levels: {
- roles: ProtectedBranch::PushAccessLevel.human_access_levels.map do |id, text|
- { id: id, text: text, before_divider: true }
- end
- },
- merge_access_levels: {
- roles: ProtectedBranch::MergeAccessLevel.human_access_levels.map do |id, text|
- { id: id, text: text, before_divider: true }
- end
- }
+ create_access_levels: levels_for_dropdown(ProtectedTag::CreateAccessLevel),
+ push_access_levels: levels_for_dropdown(ProtectedBranch::PushAccessLevel),
+ merge_access_levels: levels_for_dropdown(ProtectedBranch::MergeAccessLevel)
}
end
- def open_branches
- branches = @project.open_branches.map { |br| { text: br.name, id: br.name, title: br.name } }
- { open_branches: branches }
+ def levels_for_dropdown(access_level_type)
+ roles = access_level_type.human_access_levels.map do |id, text|
+ { id: id, text: text, before_divider: true }
+ end
+ { roles: roles }
+ end
+
+ def protectable_tags_for_dropdown
+ { open_tags: ProtectableDropdown.new(@project, :tags).hash }
+ end
+
+ def protectable_branches_for_dropdown
+ { open_branches: ProtectableDropdown.new(@project, :branches).hash }
end
def load_gon_index
- gon.push(open_branches.merge(access_levels_options))
+ gon.push(protectable_tags_for_dropdown)
+ gon.push(protectable_branches_for_dropdown)
+ gon.push(access_levels_options)
end
end
end
diff --git a/app/controllers/projects/snippets_controller.rb b/app/controllers/projects/snippets_controller.rb
index ea1a97b7cf0..3b2b0d9e502 100644
--- a/app/controllers/projects/snippets_controller.rb
+++ b/app/controllers/projects/snippets_controller.rb
@@ -1,7 +1,9 @@
class Projects::SnippetsController < Projects::ApplicationController
+ include RendersNotes
include ToggleAwardEmoji
include SpammableActions
include SnippetsActions
+ include RendersBlob
before_action :module_enabled
before_action :snippet, only: [:show, :edit, :destroy, :update, :raw, :toggle_award_emoji, :mark_as_spam]
@@ -21,12 +23,11 @@ class Projects::SnippetsController < Projects::ApplicationController
respond_to :html
def index
- @snippets = SnippetsFinder.new.execute(
+ @snippets = SnippetsFinder.new(
current_user,
- filter: :by_project,
project: @project,
scope: params[:scope]
- )
+ ).execute
@snippets = @snippets.page(params[:page])
if @snippets.out_of_range? && @snippets.total_pages != 0
redirect_to namespace_project_snippets_path(page: @snippets.total_pages)
@@ -54,9 +55,23 @@ class Projects::SnippetsController < Projects::ApplicationController
end
def show
- @note = @project.notes.new(noteable: @snippet)
- @notes = Banzai::NoteRenderer.render(@snippet.notes.fresh, @project, current_user)
- @noteable = @snippet
+ blob = @snippet.blob
+ override_max_blob_size(blob)
+
+ respond_to do |format|
+ format.html do
+ @note = @project.notes.new(noteable: @snippet)
+ @noteable = @snippet
+
+ @discussions = @snippet.discussions
+ @notes = prepare_notes_for_rendering(@discussions.flat_map(&:notes))
+ render 'show'
+ end
+
+ format.json do
+ render_blob_json(blob)
+ end
+ end
end
def destroy
diff --git a/app/controllers/projects/tags_controller.rb b/app/controllers/projects/tags_controller.rb
index e13f0bde315..afbea3e2b40 100644
--- a/app/controllers/projects/tags_controller.rb
+++ b/app/controllers/projects/tags_controller.rb
@@ -38,6 +38,8 @@ class Projects::TagsController < Projects::ApplicationController
redirect_to namespace_project_tag_path(@project.namespace, @project, @tag.name)
else
@error = result[:message]
+ @message = params[:message]
+ @release_description = params[:release_description]
render action: 'new'
end
end
@@ -48,7 +50,7 @@ class Projects::TagsController < Projects::ApplicationController
respond_to do |format|
if result[:status] == :success
format.html do
- redirect_to namespace_project_tags_path(@project.namespace, @project)
+ redirect_to namespace_project_tags_path(@project.namespace, @project), status: 303
end
format.js
@@ -57,7 +59,7 @@ class Projects::TagsController < Projects::ApplicationController
format.html do
redirect_to namespace_project_tags_path(@project.namespace, @project),
- alert: @error
+ alert: @error, status: 303
end
format.js do
diff --git a/app/controllers/projects/tree_controller.rb b/app/controllers/projects/tree_controller.rb
index 637b61504d8..f8eb8e00a5d 100644
--- a/app/controllers/projects/tree_controller.rb
+++ b/app/controllers/projects/tree_controller.rb
@@ -24,6 +24,8 @@ class Projects::TreeController < Projects::ApplicationController
end
end
+ @last_commit = @repository.last_commit_for_path(@commit.id, @tree.path) || @commit
+
respond_to do |format|
format.html
# Disable cache so browser history works
@@ -34,21 +36,21 @@ class Projects::TreeController < Projects::ApplicationController
def create_dir
return render_404 unless @commit_params.values.all?
- update_ref
+ set_start_branch_to_branch_name
create_commit(Files::CreateDirService, success_notice: "The directory has been successfully created.",
- success_path: namespace_project_tree_path(@project.namespace, @project, File.join(@target_branch, @dir_name)),
+ success_path: namespace_project_tree_path(@project.namespace, @project, File.join(@branch_name, @dir_name)),
failure_path: namespace_project_tree_path(@project.namespace, @project, @ref))
end
private
def assign_dir_vars
- @target_branch = params[:target_branch]
+ @branch_name = params[:branch_name]
@dir_name = File.join(@path, params[:dir_name])
@commit_params = {
file_path: @dir_name,
- commit_message: params[:commit_message],
+ commit_message: params[:commit_message]
}
end
end
diff --git a/app/controllers/projects/triggers_controller.rb b/app/controllers/projects/triggers_controller.rb
index c47198c5eb6..afa56de920b 100644
--- a/app/controllers/projects/triggers_controller.rb
+++ b/app/controllers/projects/triggers_controller.rb
@@ -11,7 +11,7 @@ class Projects::TriggersController < Projects::ApplicationController
end
def create
- @trigger = project.triggers.create(create_params.merge(owner: current_user))
+ @trigger = project.triggers.create(trigger_params.merge(owner: current_user))
if @trigger.valid?
flash[:notice] = 'Trigger was created successfully.'
@@ -36,7 +36,7 @@ class Projects::TriggersController < Projects::ApplicationController
end
def update
- if trigger.update(update_params)
+ if trigger.update(trigger_params)
redirect_to namespace_project_settings_ci_cd_path(@project.namespace, @project), notice: 'Trigger was successfully updated.'
else
render action: "edit"
@@ -67,11 +67,10 @@ class Projects::TriggersController < Projects::ApplicationController
@trigger ||= project.triggers.find(params[:id]) || render_404
end
- def create_params
- params.require(:trigger).permit(:description)
- end
-
- def update_params
- params.require(:trigger).permit(:description)
+ def trigger_params
+ params.require(:trigger).permit(
+ :description,
+ trigger_schedule_attributes: [:id, :active, :cron, :cron_timezone, :ref]
+ )
end
end
diff --git a/app/controllers/projects/uploads_controller.rb b/app/controllers/projects/uploads_controller.rb
index 61686499bd3..6966a7c5fee 100644
--- a/app/controllers/projects/uploads_controller.rb
+++ b/app/controllers/projects/uploads_controller.rb
@@ -1,33 +1,11 @@
class Projects::UploadsController < Projects::ApplicationController
+ include UploadsActions
+
skip_before_action :project, :repository,
if: -> { action_name == 'show' && image_or_video? }
before_action :authorize_upload_file!, only: [:create]
- def create
- link_to_file = ::Projects::UploadService.new(project, params[:file]).
- execute
-
- respond_to do |format|
- if link_to_file
- format.json do
- render json: { link: link_to_file }
- end
- else
- format.json do
- render json: 'Invalid file.', status: :unprocessable_entity
- end
- end
- end
- end
-
- def show
- return render_404 if uploader.nil? || !uploader.file.exists?
-
- disposition = uploader.image_or_video? ? 'inline' : 'attachment'
- send_file uploader.file.path, disposition: disposition
- end
-
private
def uploader
@@ -52,4 +30,10 @@ class Projects::UploadsController < Projects::ApplicationController
def image_or_video?
uploader && uploader.file.exists? && uploader.image_or_video?
end
+
+ def uploader_class
+ FileUploader
+ end
+
+ alias_method :model, :project
end
diff --git a/app/controllers/projects/wikis_controller.rb b/app/controllers/projects/wikis_controller.rb
index c5e24b9e365..887d18dbec3 100644
--- a/app/controllers/projects/wikis_controller.rb
+++ b/app/controllers/projects/wikis_controller.rb
@@ -91,23 +91,20 @@ class Projects::WikisController < Projects::ApplicationController
)
end
- def preview_markdown
- text = params[:text]
+ def git_access
+ end
- ext = Gitlab::ReferenceExtractor.new(@project, current_user)
- ext.analyze(text, author: current_user)
+ def preview_markdown
+ result = PreviewMarkdownService.new(@project, current_user, params).execute
render json: {
- body: view_context.markdown(text, pipeline: :wiki, project_wiki: @project_wiki, page_slug: params[:id]),
+ body: view_context.markdown(result[:text], pipeline: :wiki, project_wiki: @project_wiki, page_slug: params[:id]),
references: {
- users: ext.users.map(&:username)
+ users: result[:users]
}
}
end
- def git_access
- end
-
private
def load_project_wiki
@@ -115,7 +112,6 @@ class Projects::WikisController < Projects::ApplicationController
# Call #wiki to make sure the Wiki Repo is initialized
@project_wiki.wiki
-
@sidebar_wiki_entries = WikiPage.group_by_directory(@project_wiki.pages.first(15))
rescue ProjectWiki::CouldNotCreateWikiError
flash[:notice] = "Could not create Wiki Repository at this time. Please try again later."
diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb
index 47f7e0b1b28..544715d62ea 100644
--- a/app/controllers/projects_controller.rb
+++ b/app/controllers/projects_controller.rb
@@ -216,25 +216,11 @@ class ProjectsController < Projects::ApplicationController
}
end
- def preview_markdown
- text = params[:text]
-
- ext = Gitlab::ReferenceExtractor.new(@project, current_user)
- ext.analyze(text, author: current_user)
-
- render json: {
- body: view_context.markdown(text),
- references: {
- users: ext.users.map(&:username)
- }
- }
- end
-
def refs
branches = BranchesFinder.new(@repository, params).execute.map(&:name)
options = {
- 'Branches' => branches.take(100),
+ 'Branches' => branches.take(100)
}
unless @repository.tag_count.zero?
@@ -252,6 +238,18 @@ class ProjectsController < Projects::ApplicationController
render json: options.to_json
end
+ def preview_markdown
+ result = PreviewMarkdownService.new(@project, current_user, params).execute
+
+ render json: {
+ body: view_context.markdown(result[:text]),
+ references: {
+ users: result[:users],
+ commands: view_context.markdown(result[:commands])
+ }
+ }
+ end
+
private
# Render project landing depending of which features are available
@@ -345,7 +343,11 @@ class ProjectsController < Projects::ApplicationController
end
def project_view_files?
- current_user && current_user.project_view == 'files'
+ if current_user
+ current_user.project_view == 'files'
+ else
+ project_view_files_allowed?
+ end
end
# Override extract_ref from ExtractsPath, which returns the branch and file path
@@ -359,4 +361,15 @@ class ProjectsController < Projects::ApplicationController
def get_id
project.repository.root_ref
end
+
+ def project_view_files_allowed?
+ !project.empty_repo? && can?(current_user, :download_code, project)
+ end
+
+ def build_canonical_path(project)
+ params[:namespace_id] = project.namespace.to_param
+ params[:id] = project.to_param
+
+ url_for(params)
+ end
end
diff --git a/app/controllers/registrations_controller.rb b/app/controllers/registrations_controller.rb
index a49a1f50a81..3ca14dee33c 100644
--- a/app/controllers/registrations_controller.rb
+++ b/app/controllers/registrations_controller.rb
@@ -25,12 +25,12 @@ class RegistrationsController < Devise::RegistrationsController
end
def destroy
- Users::DestroyService.new(current_user).execute(current_user)
+ DeleteUserWorker.perform_async(current_user.id, current_user.id)
respond_to do |format|
format.html do
session.try(:destroy)
- redirect_to new_user_session_path, notice: "Account successfully removed."
+ redirect_to new_user_session_path, notice: "Account scheduled for removal."
end
end
end
@@ -60,7 +60,7 @@ class RegistrationsController < Devise::RegistrationsController
end
def resource
- @resource ||= Users::CreateService.new(current_user, sign_up_params).build
+ @resource ||= Users::BuildService.new(current_user, sign_up_params).execute
end
def devise_mapping
diff --git a/app/controllers/search_controller.rb b/app/controllers/search_controller.rb
index 612d69cf557..4a579601785 100644
--- a/app/controllers/search_controller.rb
+++ b/app/controllers/search_controller.rb
@@ -6,45 +6,19 @@ class SearchController < ApplicationController
layout 'search'
def show
- if params[:project_id].present?
- @project = Project.find_by(id: params[:project_id])
- @project = nil unless can?(current_user, :download_code, @project)
- end
+ search_service = SearchService.new(current_user, params)
- if params[:group_id].present?
- @group = Group.find_by(id: params[:group_id])
- @group = nil unless can?(current_user, :read_group, @group)
- end
+ @project = search_service.project
+ @group = search_service.group
return if params[:search].blank?
@search_term = params[:search]
- @scope = params[:scope]
- @show_snippets = params[:snippets].eql? 'true'
-
- @search_results =
- if @project
- unless %w(blobs notes issues merge_requests milestones wiki_blobs
- commits).include?(@scope)
- @scope = 'blobs'
- end
-
- Search::ProjectService.new(@project, current_user, params).execute
- elsif @show_snippets
- unless %w(snippet_blobs snippet_titles).include?(@scope)
- @scope = 'snippet_blobs'
- end
-
- Search::SnippetService.new(current_user, params).execute
- else
- unless %w(projects issues merge_requests milestones).include?(@scope)
- @scope = 'projects'
- end
- Search::GlobalService.new(current_user, params).execute
- end
-
- @search_objects = @search_results.objects(@scope, params[:page])
+ @scope = search_service.scope
+ @show_snippets = search_service.show_snippets?
+ @search_results = search_service.search_results
+ @search_objects = search_service.search_objects
check_single_commit_result
end
diff --git a/app/controllers/sessions_controller.rb b/app/controllers/sessions_controller.rb
index 7d81c96262f..8c6ba4915cd 100644
--- a/app/controllers/sessions_controller.rb
+++ b/app/controllers/sessions_controller.rb
@@ -3,7 +3,7 @@ class SessionsController < Devise::SessionsController
include Devise::Controllers::Rememberable
include Recaptcha::ClientHelper
- skip_before_action :check_2fa_requirement, only: [:destroy]
+ skip_before_action :check_two_factor_requirement, only: [:destroy]
prepend_before_action :check_initial_setup, only: [:new]
prepend_before_action :authenticate_with_two_factor,
@@ -35,6 +35,7 @@ class SessionsController < Devise::SessionsController
# hide the signed-in notification
flash[:notice] = nil
log_audit_event(current_user, with: authentication_method)
+ log_user_activity(current_user)
end
end
@@ -79,7 +80,7 @@ class SessionsController < Devise::SessionsController
if request.referer.present? && (params['redirect_to_referer'] == 'yes')
referer_uri = URI(request.referer)
if referer_uri.host == Gitlab.config.gitlab.host
- referer_uri.path
+ referer_uri.request_uri
else
request.fullpath
end
@@ -123,6 +124,10 @@ class SessionsController < Devise::SessionsController
for_authentication.security_event
end
+ def log_user_activity(user)
+ Users::ActivityService.new(user, 'login').execute
+ end
+
def load_recaptcha
Gitlab::Recaptcha.load_configurations!
end
diff --git a/app/controllers/snippets/notes_controller.rb b/app/controllers/snippets/notes_controller.rb
new file mode 100644
index 00000000000..f9496787b15
--- /dev/null
+++ b/app/controllers/snippets/notes_controller.rb
@@ -0,0 +1,35 @@
+class Snippets::NotesController < ApplicationController
+ include NotesActions
+ include ToggleAwardEmoji
+
+ skip_before_action :authenticate_user!, only: [:index]
+ before_action :snippet
+ before_action :authorize_read_snippet!, only: [:show, :index, :create]
+
+ private
+
+ def note
+ @note ||= snippet.notes.find(params[:id])
+ end
+ alias_method :awardable, :note
+
+ def project
+ nil
+ end
+
+ def snippet
+ PersonalSnippet.find_by(id: params[:snippet_id])
+ end
+
+ def note_params
+ super.merge(noteable_id: params[:snippet_id])
+ end
+
+ def finder_params
+ params.merge(last_fetched_at: last_fetched_at, target_id: snippet.id, target_type: 'personal_snippet')
+ end
+
+ def authorize_read_snippet!
+ return render_404 unless can?(current_user, :read_personal_snippet, snippet)
+ end
+end
diff --git a/app/controllers/snippets_controller.rb b/app/controllers/snippets_controller.rb
index f3fd3da8b20..7445f61195d 100644
--- a/app/controllers/snippets_controller.rb
+++ b/app/controllers/snippets_controller.rb
@@ -1,12 +1,14 @@
class SnippetsController < ApplicationController
+ include RendersNotes
include ToggleAwardEmoji
include SpammableActions
include SnippetsActions
+ include RendersBlob
- before_action :snippet, only: [:show, :edit, :destroy, :update, :raw, :download]
+ before_action :snippet, only: [:show, :edit, :destroy, :update, :raw]
# Allow read snippet
- before_action :authorize_read_snippet!, only: [:show, :raw, :download]
+ before_action :authorize_read_snippet!, only: [:show, :raw]
# Allow modify snippet
before_action :authorize_update_snippet!, only: [:edit, :update]
@@ -14,7 +16,7 @@ class SnippetsController < ApplicationController
# Allow destroy snippet
before_action :authorize_admin_snippet!, only: [:destroy]
- skip_before_action :authenticate_user!, only: [:index, :show, :raw, :download]
+ skip_before_action :authenticate_user!, only: [:index, :show, :raw]
layout 'snippets'
respond_to :html
@@ -25,12 +27,8 @@ class SnippetsController < ApplicationController
return render_404 unless @user
- @snippets = SnippetsFinder.new.execute(current_user, {
- filter: :by_user,
- user: @user,
- scope: params[:scope]
- })
- .page(params[:page])
+ @snippets = SnippetsFinder.new(current_user, author: @user, scope: params[:scope])
+ .execute.page(params[:page])
render 'index'
else
@@ -59,6 +57,24 @@ class SnippetsController < ApplicationController
end
def show
+ blob = @snippet.blob
+ override_max_blob_size(blob)
+
+ @note = Note.new(noteable: @snippet)
+ @noteable = @snippet
+
+ @discussions = @snippet.discussions
+ @notes = prepare_notes_for_rendering(@discussions.flat_map(&:notes))
+
+ respond_to do |format|
+ format.html do
+ render 'show'
+ end
+
+ format.json do
+ render_blob_json(blob)
+ end
+ end
end
def destroy
@@ -69,31 +85,34 @@ class SnippetsController < ApplicationController
redirect_to snippets_path
end
- def download
- send_data(
- convert_line_endings(@snippet.content),
- type: 'text/plain; charset=utf-8',
- filename: @snippet.sanitized_file_name
- )
+ def preview_markdown
+ result = PreviewMarkdownService.new(@project, current_user, params).execute
+
+ render json: {
+ body: view_context.markdown(result[:text], skip_project_check: true),
+ references: {
+ users: result[:users]
+ }
+ }
end
protected
def snippet
- @snippet ||= if current_user
- PersonalSnippet.where("author_id = ? OR visibility_level IN (?)",
- current_user.id,
- [Snippet::PUBLIC, Snippet::INTERNAL]).
- find(params[:id])
- else
- PersonalSnippet.find(params[:id])
- end
+ @snippet ||= PersonalSnippet.find_by(id: params[:id])
end
+
alias_method :awardable, :snippet
alias_method :spammable, :snippet
def authorize_read_snippet!
- authenticate_user! unless can?(current_user, :read_personal_snippet, @snippet)
+ return if can?(current_user, :read_personal_snippet, @snippet)
+
+ if current_user
+ render_404
+ else
+ authenticate_user!
+ end
end
def authorize_update_snippet!
diff --git a/app/controllers/unicorn_test_controller.rb b/app/controllers/unicorn_test_controller.rb
new file mode 100644
index 00000000000..b7a1a046be0
--- /dev/null
+++ b/app/controllers/unicorn_test_controller.rb
@@ -0,0 +1,12 @@
+if Rails.env.test?
+ class UnicornTestController < ActionController::Base
+ def pid
+ render plain: Process.pid.to_s
+ end
+
+ def kill
+ Process.kill(params[:signal], Process.pid)
+ render plain: 'Bye!'
+ end
+ end
+end
diff --git a/app/controllers/uploads_controller.rb b/app/controllers/uploads_controller.rb
index f1bfd574f04..eef53730291 100644
--- a/app/controllers/uploads_controller.rb
+++ b/app/controllers/uploads_controller.rb
@@ -1,50 +1,45 @@
class UploadsController < ApplicationController
- skip_before_action :authenticate_user!
- before_action :find_model, :authorize_access!
-
- def show
- uploader = @model.send(upload_mount)
-
- unless uploader.file_storage?
- return redirect_to uploader.url
- end
+ include UploadsActions
- unless uploader.file && uploader.file.exists?
- return render_404
- end
-
- disposition = uploader.image? ? 'inline' : 'attachment'
-
- expires_in 0.seconds, must_revalidate: true, private: true
- send_file uploader.file.path, disposition: disposition
- end
+ skip_before_action :authenticate_user!
+ before_action :find_model
+ before_action :authorize_access!, only: [:show]
+ before_action :authorize_create_access!, only: [:create]
private
def find_model
- unless upload_model && upload_mount
- return render_404
- end
+ return render_404 unless upload_model && upload_mount
@model = upload_model.find(params[:id])
end
def authorize_access!
authorized =
- case @model
- when Project
- can?(current_user, :read_project, @model)
- when Group
- can?(current_user, :read_group, @model)
+ case model
when Note
- can?(current_user, :read_project, @model.project)
- else
- # No authentication required for user avatars.
+ can?(current_user, :read_project, model.project)
+ when User
+ true
+ when Appearance
true
+ else
+ permission = "read_#{model.class.to_s.underscore}".to_sym
+
+ can?(current_user, permission, model)
end
- return if authorized
+ render_unauthorized unless authorized
+ end
+
+ def authorize_create_access!
+ # for now we support only personal snippets comments
+ authorized = can?(current_user, :comment_personal_snippet, model)
+ render_unauthorized unless authorized
+ end
+
+ def render_unauthorized
if current_user
render_404
else
@@ -58,17 +53,44 @@ class UploadsController < ApplicationController
"project" => Project,
"note" => Note,
"group" => Group,
- "appearance" => Appearance
+ "appearance" => Appearance,
+ "personal_snippet" => PersonalSnippet
}
upload_models[params[:model]]
end
def upload_mount
+ return true unless params[:mounted_as]
+
upload_mounts = %w(avatar attachment file logo header_logo)
if upload_mounts.include?(params[:mounted_as])
params[:mounted_as]
end
end
+
+ def uploader
+ return @uploader if defined?(@uploader)
+
+ if model.is_a?(PersonalSnippet)
+ @uploader = PersonalFileUploader.new(model, params[:secret])
+
+ @uploader.retrieve_from_store!(params[:filename])
+ else
+ @uploader = @model.send(upload_mount)
+
+ redirect_to @uploader.url unless @uploader.file_storage?
+ end
+
+ @uploader
+ end
+
+ def uploader_class
+ PersonalFileUploader
+ end
+
+ def model
+ @model ||= find_model
+ end
end
diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb
index 2683614d2e8..19fc1e5de49 100644
--- a/app/controllers/users_controller.rb
+++ b/app/controllers/users_controller.rb
@@ -1,7 +1,8 @@
class UsersController < ApplicationController
+ include RoutableActions
+
skip_before_action :authenticate_user!
before_action :user, except: [:exists]
- before_action :authorize_read_user!, only: [:show]
def show
respond_to do |format|
@@ -91,12 +92,8 @@ class UsersController < ApplicationController
private
- def authorize_read_user!
- render_404 unless can?(current_user, :read_user, user)
- end
-
def user
- @user ||= User.find_by_username!(params[:username])
+ @user ||= find_routable!(User, params[:username])
end
def contributed_projects
@@ -131,15 +128,18 @@ class UsersController < ApplicationController
end
def load_snippets
- @snippets = SnippetsFinder.new.execute(
+ @snippets = SnippetsFinder.new(
current_user,
- filter: :by_user,
- user: user,
+ author: user,
scope: params[:scope]
- ).page(params[:page])
+ ).execute.page(params[:page])
end
def projects_for_current_user
- ProjectsFinder.new.execute(current_user)
+ ProjectsFinder.new(current_user: current_user).execute
+ end
+
+ def build_canonical_path(user)
+ url_for(params.merge(username: user.to_param))
end
end