Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2020-06-18 14:18:50 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2020-06-18 14:18:50 +0300
commit8c7f4e9d5f36cff46365a7f8c4b9c21578c1e781 (patch)
treea77e7fe7a93de11213032ed4ab1f33a3db51b738 /app/controllers/projects
parent00b35af3db1abfe813a778f643dad221aad51fca (diff)
Add latest changes from gitlab-org/gitlab@13-1-stable-ee
Diffstat (limited to 'app/controllers/projects')
-rw-r--r--app/controllers/projects/alert_management_controller.rb4
-rw-r--r--app/controllers/projects/alerting/notifications_controller.rb16
-rw-r--r--app/controllers/projects/badges_controller.rb11
-rw-r--r--app/controllers/projects/blame_controller.rb3
-rw-r--r--app/controllers/projects/blob_controller.rb6
-rw-r--r--app/controllers/projects/branches_controller.rb14
-rw-r--r--app/controllers/projects/ci/daily_build_group_report_results_controller.rb11
-rw-r--r--app/controllers/projects/discussions_controller.rb2
-rw-r--r--app/controllers/projects/environments_controller.rb2
-rw-r--r--app/controllers/projects/graphs_controller.rb10
-rw-r--r--app/controllers/projects/group_links_controller.rb7
-rw-r--r--app/controllers/projects/import/jira_controller.rb54
-rw-r--r--app/controllers/projects/issues_controller.rb1
-rw-r--r--app/controllers/projects/jobs_controller.rb40
-rw-r--r--app/controllers/projects/merge_requests/diffs_controller.rb11
-rw-r--r--app/controllers/projects/merge_requests/drafts_controller.rb129
-rw-r--r--app/controllers/projects/merge_requests_controller.rb3
-rw-r--r--app/controllers/projects/milestones_controller.rb4
-rw-r--r--app/controllers/projects/pipelines_controller.rb16
-rw-r--r--app/controllers/projects/refs_controller.rb2
-rw-r--r--app/controllers/projects/releases_controller.rb1
-rw-r--r--app/controllers/projects/services_controller.rb15
-rw-r--r--app/controllers/projects/settings/operations_controller.rb2
-rw-r--r--app/controllers/projects/snippets/application_controller.rb19
-rw-r--r--app/controllers/projects/snippets_controller.rb86
-rw-r--r--app/controllers/projects/tags_controller.rb18
-rw-r--r--app/controllers/projects/web_ide_terminals_controller.rb98
-rw-r--r--app/controllers/projects/wikis_controller.rb199
28 files changed, 415 insertions, 369 deletions
diff --git a/app/controllers/projects/alert_management_controller.rb b/app/controllers/projects/alert_management_controller.rb
index 0c0a91e136f..054dc8e6a35 100644
--- a/app/controllers/projects/alert_management_controller.rb
+++ b/app/controllers/projects/alert_management_controller.rb
@@ -2,10 +2,6 @@
class Projects::AlertManagementController < Projects::ApplicationController
before_action :authorize_read_alert_management_alert!
- before_action do
- push_frontend_feature_flag(:alert_list_status_filtering_enabled)
- push_frontend_feature_flag(:create_issue_from_alert_enabled)
- end
def index
end
diff --git a/app/controllers/projects/alerting/notifications_controller.rb b/app/controllers/projects/alerting/notifications_controller.rb
index 358e7629958..fef8235628d 100644
--- a/app/controllers/projects/alerting/notifications_controller.rb
+++ b/app/controllers/projects/alerting/notifications_controller.rb
@@ -29,12 +29,22 @@ module Projects
end
def notify_service
- Projects::Alerting::NotifyService
- .new(project, current_user, notification_payload)
+ notify_service_class.new(project, current_user, notification_payload)
+ end
+
+ def notify_service_class
+ # We are tracking the consolidation of these services in
+ # https://gitlab.com/groups/gitlab-org/-/epics/3360
+ # to get rid of this workaround.
+ if Projects::Prometheus::Alerts::NotifyService.processable?(notification_payload)
+ Projects::Prometheus::Alerts::NotifyService
+ else
+ Projects::Alerting::NotifyService
+ end
end
def notification_payload
- params.permit![:notification]
+ @notification_payload ||= params.permit![:notification]
end
end
end
diff --git a/app/controllers/projects/badges_controller.rb b/app/controllers/projects/badges_controller.rb
index 66b51b17790..59a7dff680c 100644
--- a/app/controllers/projects/badges_controller.rb
+++ b/app/controllers/projects/badges_controller.rb
@@ -8,14 +8,21 @@ class Projects::BadgesController < Projects::ApplicationController
def pipeline
pipeline_status = Gitlab::Badge::Pipeline::Status
- .new(project, params[:ref])
+ .new(project, params[:ref], opts: {
+ key_text: params[:key_text],
+ key_width: params[:key_width]
+ })
render_badge pipeline_status
end
def coverage
coverage_report = Gitlab::Badge::Coverage::Report
- .new(project, params[:ref], params[:job])
+ .new(project, params[:ref], opts: {
+ job: params[:job],
+ key_text: params[:key_text],
+ key_width: params[:key_width]
+ })
render_badge coverage_report
end
diff --git a/app/controllers/projects/blame_controller.rb b/app/controllers/projects/blame_controller.rb
index b62ce940e9c..374b4921dbc 100644
--- a/app/controllers/projects/blame_controller.rb
+++ b/app/controllers/projects/blame_controller.rb
@@ -20,6 +20,7 @@ class Projects::BlameController < Projects::ApplicationController
environment_params[:find_latest] = true
@environment = EnvironmentsFinder.new(@project, current_user, environment_params).execute.last
- @blame_groups = Gitlab::Blame.new(@blob, @commit).groups
+ @blame = Gitlab::Blame.new(@blob, @commit)
+ @blame = Gitlab::View::Presenter::Factory.new(@blame, project: @project, path: @path).fabricate!
end
end
diff --git a/app/controllers/projects/blob_controller.rb b/app/controllers/projects/blob_controller.rb
index 584320a66de..abc1d58cbf1 100644
--- a/app/controllers/projects/blob_controller.rb
+++ b/app/controllers/projects/blob_controller.rb
@@ -71,6 +71,7 @@ class Projects::BlobController < Projects::ApplicationController
def update
@path = params[:file_path] if params[:file_path].present?
+
create_commit(Files::UpdateService, success_path: -> { after_edit_path },
failure_view: :edit,
failure_path: project_blob_path(@project, @id))
@@ -93,7 +94,6 @@ class Projects::BlobController < Projects::ApplicationController
def destroy
create_commit(Files::DeleteService, success_notice: _("The file has been successfully deleted."),
success_path: -> { after_delete_path },
- failure_view: :show,
failure_path: project_blob_path(@project, @id))
end
@@ -115,6 +115,8 @@ class Projects::BlobController < Projects::ApplicationController
private
+ attr_reader :branch_name
+
def blob
@blob ||= @repository.blob_at(@commit.id, @path)
@@ -254,3 +256,5 @@ class Projects::BlobController < Projects::ApplicationController
params.permit(:full, :since, :to, :bottom, :unfold, :offset, :indent)
end
end
+
+Projects::BlobController.prepend_if_ee('EE::Projects::BlobController')
diff --git a/app/controllers/projects/branches_controller.rb b/app/controllers/projects/branches_controller.rb
index cc595740696..7cfb4a508da 100644
--- a/app/controllers/projects/branches_controller.rb
+++ b/app/controllers/projects/branches_controller.rb
@@ -25,8 +25,9 @@ class Projects::BranchesController < Projects::ApplicationController
@refs_pipelines = @project.ci_pipelines.latest_successful_for_refs(@branches.map(&:name))
@merged_branch_names = repository.merged_branch_names(@branches.map(&:name))
+ @branch_pipeline_statuses = branch_pipeline_statuses
- # https://gitlab.com/gitlab-org/gitlab-foss/issues/48097
+ # https://gitlab.com/gitlab-org/gitlab/-/issues/22851
Gitlab::GitalyClient.allow_n_plus_1_calls do
render
end
@@ -194,4 +195,15 @@ class Projects::BranchesController < Projects::ApplicationController
confidential_issue_project
end
+
+ def branch_pipeline_statuses
+ latest_commits = @branches.map do |branch|
+ [branch.name, repository.commit(branch.dereferenced_target).sha]
+ end.to_h
+
+ latest_pipelines = project.ci_pipelines.latest_pipeline_per_commit(latest_commits.values)
+ latest_commits.transform_values do |commit_sha|
+ latest_pipelines[commit_sha]&.detailed_status(current_user)
+ end.compact
+ end
end
diff --git a/app/controllers/projects/ci/daily_build_group_report_results_controller.rb b/app/controllers/projects/ci/daily_build_group_report_results_controller.rb
index dfda5fca310..b36c5f1aea6 100644
--- a/app/controllers/projects/ci/daily_build_group_report_results_controller.rb
+++ b/app/controllers/projects/ci/daily_build_group_report_results_controller.rb
@@ -7,12 +7,13 @@ class Projects::Ci::DailyBuildGroupReportResultsController < Projects::Applicati
REPORT_WINDOW = 90.days
before_action :validate_feature_flag!
- before_action :authorize_download_code! # Share the same authorization rules as the graphs controller
+ before_action :authorize_read_build_report_results!
before_action :validate_param_type!
def index
respond_to do |format|
- format.csv { send_data(render_csv(results), type: 'text/csv; charset=utf-8') }
+ format.csv { send_data(render_csv(report_results), type: 'text/csv; charset=utf-8') }
+ format.json { render json: render_json(report_results) }
end
end
@@ -37,7 +38,11 @@ class Projects::Ci::DailyBuildGroupReportResultsController < Projects::Applicati
).render
end
- def results
+ def render_json(collection)
+ Ci::DailyBuildGroupReportResultSerializer.new.represent(collection, param_type: param_type)
+ end
+
+ def report_results
Ci::DailyBuildGroupReportResultsFinder.new(finder_params).execute
end
diff --git a/app/controllers/projects/discussions_controller.rb b/app/controllers/projects/discussions_controller.rb
index 028390c7e2a..06231607f73 100644
--- a/app/controllers/projects/discussions_controller.rb
+++ b/app/controllers/projects/discussions_controller.rb
@@ -10,7 +10,7 @@ class Projects::DiscussionsController < Projects::ApplicationController
before_action :authorize_resolve_discussion!, only: [:resolve, :unresolve]
def resolve
- Discussions::ResolveService.new(project, current_user, merge_request: merge_request).execute(discussion)
+ Discussions::ResolveService.new(project, current_user, one_or_more_discussions: discussion).execute
render_discussion
end
diff --git a/app/controllers/projects/environments_controller.rb b/app/controllers/projects/environments_controller.rb
index 5f4d88c57e9..4d774123ef1 100644
--- a/app/controllers/projects/environments_controller.rb
+++ b/app/controllers/projects/environments_controller.rb
@@ -10,7 +10,7 @@ class Projects::EnvironmentsController < Projects::ApplicationController
push_frontend_feature_flag(:prometheus_computed_alerts)
end
- before_action :authorize_read_environment!
+ before_action :authorize_read_environment!, except: [:metrics, :additional_metrics, :metrics_dashboard, :metrics_redirect]
before_action :authorize_create_environment!, only: [:new, :create]
before_action :authorize_stop_environment!, only: [:stop]
before_action :authorize_update_environment!, only: [:edit, :update, :cancel_auto_stop]
diff --git a/app/controllers/projects/graphs_controller.rb b/app/controllers/projects/graphs_controller.rb
index 34246f27241..a8b90f8685f 100644
--- a/app/controllers/projects/graphs_controller.rb
+++ b/app/controllers/projects/graphs_controller.rb
@@ -6,7 +6,7 @@ class Projects::GraphsController < Projects::ApplicationController
# Authorize
before_action :require_non_empty_project
before_action :assign_ref_vars
- before_action :authorize_download_code!
+ before_action :authorize_read_repository_graphs!
def show
respond_to do |format|
@@ -54,7 +54,8 @@ class Projects::GraphsController < Projects::ApplicationController
end
def get_daily_coverage_options
- return unless Feature.enabled?(:ci_download_daily_code_coverage, default_enabled: true)
+ return unless Feature.enabled?(:ci_download_daily_code_coverage, @project, default_enabled: true)
+ return unless can?(current_user, :read_build_report_results, project)
date_today = Date.current
report_window = Projects::Ci::DailyBuildGroupReportResultsController::REPORT_WINDOW
@@ -70,6 +71,11 @@ class Projects::GraphsController < Projects::ApplicationController
namespace_id: @project.namespace,
project_id: @project,
format: :csv
+ ),
+ graph_api_path: namespace_project_ci_daily_build_group_report_results_path(
+ namespace_id: @project.namespace,
+ project_id: @project,
+ format: :json
)
}
end
diff --git a/app/controllers/projects/group_links_controller.rb b/app/controllers/projects/group_links_controller.rb
index d06e24ef39c..a30c455a7e4 100644
--- a/app/controllers/projects/group_links_controller.rb
+++ b/app/controllers/projects/group_links_controller.rb
@@ -5,10 +5,6 @@ class Projects::GroupLinksController < Projects::ApplicationController
before_action :authorize_admin_project!
before_action :authorize_admin_project_member!, only: [:update]
- def index
- redirect_to namespace_project_settings_members_path
- end
-
def create
group = Group.find(params[:link_group_id]) if params[:link_group_id].present?
@@ -26,8 +22,7 @@ class Projects::GroupLinksController < Projects::ApplicationController
def update
@group_link = @project.project_group_links.find(params[:id])
-
- @group_link.update(group_link_params)
+ Projects::GroupLinks::UpdateService.new(@group_link).execute(group_link_params)
end
def destroy
diff --git a/app/controllers/projects/import/jira_controller.rb b/app/controllers/projects/import/jira_controller.rb
index 711e23dc3ce..976ac7df976 100644
--- a/app/controllers/projects/import/jira_controller.rb
+++ b/app/controllers/projects/import/jira_controller.rb
@@ -4,59 +4,29 @@ module Projects
module Import
class JiraController < Projects::ApplicationController
before_action :authenticate_user!
- before_action :check_issues_available!
before_action :authorize_read_project!
- before_action :jira_import_enabled?
- before_action :jira_integration_configured?
- before_action :authorize_admin_project!, only: [:import]
+ before_action :validate_jira_import_settings!
def show
- jira_service = @project.jira_service
-
- if jira_service.present? && !@project.latest_jira_import&.in_progress? && current_user&.can?(:admin_project, @project)
- jira_client = jira_service.client
- jira_projects = jira_client.Project.all
-
- if jira_projects.present?
- @jira_projects = jira_projects.map { |p| ["#{p.name} (#{p.key})", p.key] }
- else
- flash[:alert] = 'No projects have been returned from Jira. Please check your Jira configuration.'
- end
- end
-
- unless Feature.enabled?(:jira_issue_import_vue, @project, default_enabled: true)
- flash[:notice] = _("Import %{status}") % { status: @project.jira_import_status } unless @project.latest_jira_import&.initial?
- end
- end
-
- def import
- jira_project_key = jira_import_params[:jira_project_key]
-
- if jira_project_key.present?
- response = ::JiraImport::StartImportService.new(current_user, @project, jira_project_key).execute
- flash[:notice] = response.message if response.message.present?
- else
- flash[:alert] = 'No Jira project key has been provided.'
- end
-
- redirect_to project_import_jira_path(@project)
end
private
- def jira_import_enabled?
- return if @project.jira_issues_import_feature_flag_enabled?
+ def validate_jira_import_settings!
+ Gitlab::JiraImport.validate_project_settings!(@project, user: current_user, configuration_check: false)
+ true
+ rescue Projects::ImportService::Error => e
+ flash[:notice] = e.message
redirect_to project_issues_path(@project)
- end
- def jira_integration_configured?
- return if Feature.enabled?(:jira_issue_import_vue, @project, default_enabled: true)
- return if @project.jira_service
+ false
+ end
- flash[:notice] = _("Configure the Jira integration first on your project's %{strong_start} Settings > Integrations > Jira%{strong_end} page." %
- { strong_start: '<strong>'.html_safe, strong_end: '</strong>'.html_safe })
- redirect_to project_issues_path(@project)
+ def jira_service
+ strong_memoize(:jira_service) do
+ @project.jira_service
+ end
end
def jira_import_params
diff --git a/app/controllers/projects/issues_controller.rb b/app/controllers/projects/issues_controller.rb
index 3e9d956f7b1..693329848de 100644
--- a/app/controllers/projects/issues_controller.rb
+++ b/app/controllers/projects/issues_controller.rb
@@ -46,7 +46,6 @@ class Projects::IssuesController < Projects::ApplicationController
before_action do
push_frontend_feature_flag(:vue_issuable_sidebar, project.group)
- push_frontend_feature_flag(:save_issuable_health_status, project.group, default_enabled: true)
end
before_action only: :show do
diff --git a/app/controllers/projects/jobs_controller.rb b/app/controllers/projects/jobs_controller.rb
index e0457925b34..e1f6cbe3dca 100644
--- a/app/controllers/projects/jobs_controller.rb
+++ b/app/controllers/projects/jobs_controller.rb
@@ -14,6 +14,8 @@ class Projects::JobsController < Projects::ApplicationController
before_action only: [:show] do
push_frontend_feature_flag(:job_log_json, project, default_enabled: true)
end
+ before_action :authorize_create_proxy_build!, only: :proxy_websocket_authorize
+ before_action :verify_proxy_request!, only: :proxy_websocket_authorize
layout 'project'
@@ -151,6 +153,10 @@ class Projects::JobsController < Projects::ApplicationController
render json: Gitlab::Workhorse.channel_websocket(@build.terminal_specification)
end
+ def proxy_websocket_authorize
+ render json: proxy_websocket_service(build_service_specification)
+ end
+
private
def authorize_update_build!
@@ -165,10 +171,19 @@ class Projects::JobsController < Projects::ApplicationController
return access_denied! unless can?(current_user, :create_build_terminal, build)
end
+ def authorize_create_proxy_build!
+ return access_denied! unless can?(current_user, :create_build_service_proxy, build)
+ end
+
def verify_api_request!
Gitlab::Workhorse.verify_api_request!(request.headers)
end
+ def verify_proxy_request!
+ verify_api_request!
+ set_workhorse_internal_api_content_type
+ end
+
def raw_send_params
{ type: 'text/plain; charset=utf-8', disposition: 'inline' }
end
@@ -202,6 +217,27 @@ class Projects::JobsController < Projects::ApplicationController
'attachment'
end
-end
-Projects::JobsController.prepend_if_ee('EE::Projects::JobsController')
+ def build_service_specification
+ build.service_specification(service: params['service'],
+ port: params['port'],
+ path: params['path'],
+ subprotocols: proxy_subprotocol)
+ end
+
+ def proxy_subprotocol
+ # This will allow to reuse the same subprotocol set
+ # in the original websocket connection
+ request.headers['HTTP_SEC_WEBSOCKET_PROTOCOL'].presence || ::Ci::BuildRunnerSession::TERMINAL_SUBPROTOCOL
+ end
+
+ # This method provides the information to Workhorse
+ # about the service we want to proxy to.
+ # For security reasons, in case this operation is started by JS,
+ # it's important to use only sourced GitLab JS code
+ def proxy_websocket_service(service)
+ service[:url] = ::Gitlab::UrlHelpers.as_wss(service[:url])
+
+ ::Gitlab::Workhorse.channel_websocket(service)
+ end
+end
diff --git a/app/controllers/projects/merge_requests/diffs_controller.rb b/app/controllers/projects/merge_requests/diffs_controller.rb
index 2331674f42c..1bf143c9a91 100644
--- a/app/controllers/projects/merge_requests/diffs_controller.rb
+++ b/app/controllers/projects/merge_requests/diffs_controller.rb
@@ -162,8 +162,13 @@ class Projects::MergeRequests::DiffsController < Projects::MergeRequests::Applic
def renderable_notes
define_diff_comment_vars unless @notes
- @notes
+ draft_notes =
+ if current_user
+ merge_request.draft_notes.authored_by(current_user)
+ else
+ []
+ end
+
+ @notes.concat(draft_notes)
end
end
-
-Projects::MergeRequests::DiffsController.prepend_if_ee('EE::Projects::MergeRequests::DiffsController')
diff --git a/app/controllers/projects/merge_requests/drafts_controller.rb b/app/controllers/projects/merge_requests/drafts_controller.rb
new file mode 100644
index 00000000000..f4846b1aa81
--- /dev/null
+++ b/app/controllers/projects/merge_requests/drafts_controller.rb
@@ -0,0 +1,129 @@
+# frozen_string_literal: true
+
+class Projects::MergeRequests::DraftsController < Projects::MergeRequests::ApplicationController
+ include Gitlab::Utils::StrongMemoize
+
+ respond_to :json
+
+ before_action :authorize_create_note!, only: [:create, :publish]
+ before_action :authorize_admin_draft!, only: [:update, :destroy]
+ before_action :authorize_admin_draft!, if: -> { action_name == 'publish' && params[:id].present? }
+
+ def index
+ drafts = prepare_notes_for_rendering(draft_notes)
+ render json: DraftNoteSerializer.new(current_user: current_user).represent(drafts)
+ end
+
+ def create
+ create_params = draft_note_params.merge(in_reply_to_discussion_id: params[:in_reply_to_discussion_id])
+ create_service = DraftNotes::CreateService.new(merge_request, current_user, create_params)
+
+ draft_note = create_service.execute
+
+ prepare_notes_for_rendering(draft_note)
+
+ render json: DraftNoteSerializer.new(current_user: current_user).represent(draft_note)
+ end
+
+ def update
+ draft_note.update!(draft_note_params)
+
+ prepare_notes_for_rendering(draft_note)
+
+ render json: DraftNoteSerializer.new(current_user: current_user).represent(draft_note)
+ end
+
+ def destroy
+ DraftNotes::DestroyService.new(merge_request, current_user).execute(draft_note)
+
+ head :ok
+ end
+
+ def publish
+ result = DraftNotes::PublishService.new(merge_request, current_user).execute(draft_note(allow_nil: true))
+
+ if result[:status] == :success
+ head :ok
+ else
+ render json: { message: result[:message] }, status: result[:status]
+ end
+ end
+
+ def discard
+ DraftNotes::DestroyService.new(merge_request, current_user).execute
+
+ head :ok
+ end
+
+ private
+
+ def draft_note(allow_nil: false)
+ strong_memoize(:draft_note) do
+ draft_notes.find(params[:id])
+ end
+ rescue ActiveRecord::RecordNotFound => ex
+ # draft_note is allowed to be nil in #publish
+ raise ex unless allow_nil
+ end
+
+ def draft_notes
+ return unless current_user
+
+ strong_memoize(:draft_notes) do
+ merge_request.draft_notes.authored_by(current_user)
+ end
+ end
+
+ # rubocop: disable CodeReuse/ActiveRecord
+ def merge_request
+ @merge_request ||= MergeRequestsFinder.new(current_user, project_id: @project.id).find_by!(iid: params[:merge_request_id])
+ end
+ # rubocop: enable CodeReuse/ActiveRecord
+
+ def draft_note_params
+ params.require(:draft_note).permit(
+ :commit_id,
+ :note,
+ :position,
+ :resolve_discussion
+ ).tap do |h|
+ # Old FE version will still be sending `draft_note[commit_id]` as 'undefined'.
+ # That can result to having a note linked to a commit with 'undefined' ID
+ # which is non-existent.
+ h[:commit_id] = nil if h[:commit_id] == 'undefined'
+ end
+ end
+
+ def prepare_notes_for_rendering(notes)
+ return [] unless notes
+
+ notes = Array.wrap(notes)
+
+ # Preload author and access-level information
+ DraftNote.preload_author(notes)
+ user_ids = notes.map(&:author_id)
+ project.team.max_member_access_for_user_ids(user_ids)
+
+ notes.map(&method(:render_draft_note))
+ end
+
+ def render_draft_note(note)
+ params = { target_id: merge_request.id, target_type: 'MergeRequest', text: note.note }
+ result = PreviewMarkdownService.new(@project, current_user, params).execute
+ markdown_params = { markdown_engine: result[:markdown_engine], issuable_state_filter_enabled: true }
+
+ note.rendered_note = view_context.markdown(result[:text], markdown_params)
+ note.users_referenced = result[:users]
+ note.commands_changes = view_context.markdown(result[:commands])
+
+ note
+ end
+
+ def authorize_admin_draft!
+ access_denied! unless can?(current_user, :admin_note, draft_note)
+ end
+
+ def authorize_create_note!
+ access_denied! unless can?(current_user, :create_note, merge_request)
+ end
+end
diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb
index 5613b5b9589..55556ea7d31 100644
--- a/app/controllers/projects/merge_requests_controller.rb
+++ b/app/controllers/projects/merge_requests_controller.rb
@@ -33,6 +33,9 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
push_frontend_feature_flag(:widget_visibility_polling, @project, default_enabled: true)
push_frontend_feature_flag(:merge_ref_head_comments, @project)
push_frontend_feature_flag(:mr_commit_neighbor_nav, @project, default_enabled: true)
+ push_frontend_feature_flag(:multiline_comments, @project)
+ push_frontend_feature_flag(:file_identifier_hash)
+ push_frontend_feature_flag(:batch_suggestions, @project)
end
before_action do
diff --git a/app/controllers/projects/milestones_controller.rb b/app/controllers/projects/milestones_controller.rb
index 56f1f1a1019..16d63cc184f 100644
--- a/app/controllers/projects/milestones_controller.rb
+++ b/app/controllers/projects/milestones_controller.rb
@@ -7,7 +7,7 @@ class Projects::MilestonesController < Projects::ApplicationController
before_action :check_issuables_available!
before_action :milestone, only: [:edit, :update, :destroy, :show, :merge_requests, :participants, :labels, :promote]
before_action do
- push_frontend_feature_flag(:burnup_charts)
+ push_frontend_feature_flag(:burnup_charts, @project)
end
# Allow read any milestone
@@ -34,7 +34,7 @@ class Projects::MilestonesController < Projects::ApplicationController
@milestones = @milestones.page(params[:page])
end
format.json do
- render json: @milestones.to_json(methods: :name)
+ render json: @milestones.to_json(only: [:id, :title], methods: :name)
end
end
end
diff --git a/app/controllers/projects/pipelines_controller.rb b/app/controllers/projects/pipelines_controller.rb
index 678d0862f48..0b6c0db211e 100644
--- a/app/controllers/projects/pipelines_controller.rb
+++ b/app/controllers/projects/pipelines_controller.rb
@@ -12,8 +12,9 @@ class Projects::PipelinesController < Projects::ApplicationController
before_action :authorize_update_pipeline!, only: [:retry, :cancel]
before_action do
push_frontend_feature_flag(:junit_pipeline_view, project)
- push_frontend_feature_flag(:filter_pipelines_search, default_enabled: true)
- push_frontend_feature_flag(:dag_pipeline_tab)
+ push_frontend_feature_flag(:filter_pipelines_search, project, default_enabled: true)
+ push_frontend_feature_flag(:dag_pipeline_tab, project, default_enabled: false)
+ push_frontend_feature_flag(:pipelines_security_report_summary, project)
end
before_action :ensure_pipeline, only: [:show]
@@ -95,7 +96,14 @@ class Projects::PipelinesController < Projects::ApplicationController
end
def dag
- render_show
+ respond_to do |format|
+ format.html { render_show }
+ format.json do
+ render json: Ci::DagPipelineSerializer
+ .new(project: @project, current_user: @current_user)
+ .represent(@pipeline)
+ end
+ end
end
def failures
@@ -269,7 +277,7 @@ class Projects::PipelinesController < Projects::ApplicationController
end
def index_params
- params.permit(:scope, :username, :ref)
+ params.permit(:scope, :username, :ref, :status)
end
end
diff --git a/app/controllers/projects/refs_controller.rb b/app/controllers/projects/refs_controller.rb
index fcbeb5c840c..a2581e72257 100644
--- a/app/controllers/projects/refs_controller.rb
+++ b/app/controllers/projects/refs_controller.rb
@@ -53,7 +53,7 @@ class Projects::RefsController < Projects::ApplicationController
format.json do
logs, next_offset = tree_summary.fetch_logs
- response.headers["More-Logs-Offset"] = next_offset if next_offset
+ response.headers["More-Logs-Offset"] = next_offset.to_s if next_offset
render json: logs
end
diff --git a/app/controllers/projects/releases_controller.rb b/app/controllers/projects/releases_controller.rb
index 228b139d794..d3285b64dab 100644
--- a/app/controllers/projects/releases_controller.rb
+++ b/app/controllers/projects/releases_controller.rb
@@ -10,6 +10,7 @@ class Projects::ReleasesController < Projects::ApplicationController
push_frontend_feature_flag(:release_evidence_collection, project, default_enabled: true)
push_frontend_feature_flag(:release_show_page, project, default_enabled: true)
push_frontend_feature_flag(:release_asset_link_editing, project, default_enabled: true)
+ push_frontend_feature_flag(:release_asset_link_type, project, default_enabled: true)
end
before_action :authorize_update_release!, only: %i[edit update]
diff --git a/app/controllers/projects/services_controller.rb b/app/controllers/projects/services_controller.rb
index 92c6ce324f7..710ad546e64 100644
--- a/app/controllers/projects/services_controller.rb
+++ b/app/controllers/projects/services_controller.rb
@@ -2,6 +2,7 @@
class Projects::ServicesController < Projects::ApplicationController
include ServiceParams
+ include InternalRedirect
# Authorize
before_action :authorize_admin_project!
@@ -10,6 +11,9 @@ class Projects::ServicesController < Projects::ApplicationController
before_action :web_hook_logs, only: [:edit, :update]
before_action :set_deprecation_notice_for_prometheus_service, only: [:edit, :update]
before_action :redirect_deprecated_prometheus_service, only: [:update]
+ before_action only: :edit do
+ push_frontend_feature_flag(:integration_form_refactor)
+ end
respond_to :html
@@ -26,8 +30,8 @@ class Projects::ServicesController < Projects::ApplicationController
respond_to do |format|
format.html do
if saved
- redirect_to project_settings_integrations_path(@project),
- notice: success_message
+ target_url = safe_redirect_path(params[:redirect_to]).presence || project_settings_integrations_path(@project)
+ redirect_to target_url, notice: success_message
else
render 'edit'
end
@@ -56,11 +60,10 @@ class Projects::ServicesController < Projects::ApplicationController
return { error: true, message: _('Validations failed.'), service_response: @service.errors.full_messages.join(','), test_failed: false }
end
- data = @service.test_data(project, current_user)
- outcome = @service.test(data)
+ result = Integrations::Test::ProjectService.new(@service, current_user, params[:event]).execute
- unless outcome[:success]
- return { error: true, message: _('Test failed.'), service_response: outcome[:result].to_s, test_failed: true }
+ unless result[:success]
+ return { error: true, message: _('Test failed.'), service_response: result[:message].to_s, test_failed: true }
end
{}
diff --git a/app/controllers/projects/settings/operations_controller.rb b/app/controllers/projects/settings/operations_controller.rb
index a9d1dc0759d..c2292511e0f 100644
--- a/app/controllers/projects/settings/operations_controller.rb
+++ b/app/controllers/projects/settings/operations_controller.rb
@@ -104,7 +104,7 @@ module Projects
project_params = {
incident_management_setting_attributes: ::Gitlab::Tracking::IncidentManagement.tracking_keys.keys,
- metrics_setting_attributes: [:external_dashboard_url],
+ metrics_setting_attributes: [:external_dashboard_url, :dashboard_timezone],
error_tracking_setting_attributes: [
:enabled,
diff --git a/app/controllers/projects/snippets/application_controller.rb b/app/controllers/projects/snippets/application_controller.rb
new file mode 100644
index 00000000000..3f488b07e96
--- /dev/null
+++ b/app/controllers/projects/snippets/application_controller.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+class Projects::Snippets::ApplicationController < Projects::ApplicationController
+ include FindSnippet
+ include SnippetAuthorizations
+
+ private
+
+ # This overrides the default snippet create authorization
+ # because ProjectSnippets are checked against the project rather
+ # than the user
+ def authorize_create_snippet!
+ return render_404 unless can?(current_user, :create_snippet, project)
+ end
+
+ def snippet_klass
+ ProjectSnippet
+ end
+end
diff --git a/app/controllers/projects/snippets_controller.rb b/app/controllers/projects/snippets_controller.rb
index 9233f063f55..5ee6abef804 100644
--- a/app/controllers/projects/snippets_controller.rb
+++ b/app/controllers/projects/snippets_controller.rb
@@ -1,34 +1,19 @@
# frozen_string_literal: true
-class Projects::SnippetsController < Projects::ApplicationController
- include RendersNotes
+class Projects::SnippetsController < Projects::Snippets::ApplicationController
+ include SnippetsActions
include ToggleAwardEmoji
include SpammableActions
- include SnippetsActions
- include RendersBlob
- include PaginatedCollection
- include Gitlab::NoteableMetadata
-
- skip_before_action :verify_authenticity_token,
- if: -> { action_name == 'show' && js_request? }
before_action :check_snippets_available!
+
before_action :snippet, only: [:show, :edit, :destroy, :update, :raw, :toggle_award_emoji, :mark_as_spam]
- # Allow create snippet
before_action :authorize_create_snippet!, only: [:new, :create]
-
- # Allow read any snippet
before_action :authorize_read_snippet!, except: [:new, :create, :index]
-
- # Allow modify snippet
before_action :authorize_update_snippet!, only: [:edit, :update]
-
- # Allow destroy snippet
before_action :authorize_admin_snippet!, only: [:destroy]
- respond_to :html
-
def index
@snippet_counts = Snippets::CountService
.new(current_user, project: @project)
@@ -56,61 +41,8 @@ class Projects::SnippetsController < Projects::ApplicationController
handle_repository_error(:new)
end
- def update
- update_params = snippet_params.merge(spammable_params)
-
- service_response = Snippets::UpdateService.new(project, current_user, update_params).execute(@snippet)
- @snippet = service_response.payload[:snippet]
-
- handle_repository_error(:edit)
- end
-
- def show
- conditionally_expand_blob(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), @noteable)
- render 'show'
- end
-
- format.json do
- render_blob_json(blob)
- end
-
- format.js do
- if @snippet.embeddable?
- render 'shared/snippets/show'
- else
- head :not_found
- end
- end
- end
- end
-
- def destroy
- service_response = Snippets::DestroyService.new(current_user, @snippet).execute
-
- if service_response.success?
- redirect_to project_snippets_path(project), status: :found
- elsif service_response.http_status == 403
- access_denied!
- else
- redirect_to project_snippet_path(project, @snippet),
- status: :found,
- alert: service_response.message
- end
- end
-
protected
- def snippet
- @snippet ||= @project.snippets.inc_relations_for_view.find(params[:id])
- end
alias_method :awardable, :snippet
alias_method :spammable, :snippet
@@ -118,18 +50,6 @@ class Projects::SnippetsController < Projects::ApplicationController
project_snippet_path(@project, @snippet)
end
- def authorize_read_snippet!
- return render_404 unless can?(current_user, :read_snippet, @snippet)
- end
-
- def authorize_update_snippet!
- return render_404 unless can?(current_user, :update_snippet, @snippet)
- end
-
- def authorize_admin_snippet!
- return render_404 unless can?(current_user, :admin_snippet, @snippet)
- end
-
def snippet_params
params.require(:project_snippet).permit(:title, :content, :file_name, :private, :visibility_level, :description)
end
diff --git a/app/controllers/projects/tags_controller.rb b/app/controllers/projects/tags_controller.rb
index c89bfd110c4..df20daa8f7e 100644
--- a/app/controllers/projects/tags_controller.rb
+++ b/app/controllers/projects/tags_controller.rb
@@ -41,16 +41,20 @@ class Projects::TagsController < Projects::ApplicationController
# rubocop: enable CodeReuse/ActiveRecord
def create
+ # TODO: remove this with the release creation moved to it's own form https://gitlab.com/gitlab-org/gitlab/-/issues/214245
+ evidence_pipeline = find_evidence_pipeline
+
result = ::Tags::CreateService.new(@project, current_user)
.execute(params[:tag_name], params[:ref], params[:message])
if result[:status] == :success
- # Release creation with Tags was deprecated in GitLab 11.7
+ # TODO: remove this with the release creation moved to it's own form https://gitlab.com/gitlab-org/gitlab/-/issues/214245
if params[:release_description].present?
release_params = {
tag: params[:tag_name],
name: params[:tag_name],
- description: params[:release_description]
+ description: params[:release_description],
+ evidence_pipeline: evidence_pipeline
}
Releases::CreateService
@@ -93,4 +97,14 @@ class Projects::TagsController < Projects::ApplicationController
end
end
end
+
+ private
+
+ # TODO: remove this with the release creation moved to it's own form https://gitlab.com/gitlab-org/gitlab/-/issues/214245
+ def find_evidence_pipeline
+ evidence_pipeline_sha = @project.repository.commit(params[:ref])&.sha
+ return unless evidence_pipeline_sha
+
+ @project.ci_pipelines.for_sha(evidence_pipeline_sha).last
+ end
end
diff --git a/app/controllers/projects/web_ide_terminals_controller.rb b/app/controllers/projects/web_ide_terminals_controller.rb
new file mode 100644
index 00000000000..08ea5c4bca8
--- /dev/null
+++ b/app/controllers/projects/web_ide_terminals_controller.rb
@@ -0,0 +1,98 @@
+# frozen_string_literal: true
+
+class Projects::WebIdeTerminalsController < Projects::ApplicationController
+ before_action :authenticate_user!
+
+ before_action :build, except: [:check_config, :create]
+ before_action :authorize_create_web_ide_terminal!
+ before_action :authorize_read_web_ide_terminal!, except: [:check_config, :create]
+ before_action :authorize_update_web_ide_terminal!, only: [:cancel, :retry]
+
+ def check_config
+ return respond_422 unless branch_sha
+
+ result = ::Ci::WebIdeConfigService.new(project, current_user, sha: branch_sha).execute
+
+ if result[:status] == :success
+ head :ok
+ else
+ respond_422
+ end
+ end
+
+ def show
+ render_terminal(build)
+ end
+
+ def create
+ result = ::Ci::CreateWebIdeTerminalService.new(project,
+ current_user,
+ ref: params[:branch])
+ .execute
+
+ if result[:status] == :error
+ render status: :bad_request, json: result[:message]
+ else
+ pipeline = result[:pipeline]
+ current_build = pipeline.builds.last
+
+ if current_build
+ Gitlab::UsageDataCounters::WebIdeCounter.increment_terminals_count
+
+ render_terminal(current_build)
+ else
+ render status: :bad_request, json: pipeline.errors.full_messages
+ end
+ end
+ end
+
+ def cancel
+ return respond_422 unless build.cancelable?
+
+ build.cancel
+
+ head :ok
+ end
+
+ def retry
+ return respond_422 unless build.retryable?
+
+ new_build = Ci::Build.retry(build, current_user)
+
+ render_terminal(new_build)
+ end
+
+ private
+
+ def authorize_create_web_ide_terminal!
+ return access_denied! unless can?(current_user, :create_web_ide_terminal, project)
+ end
+
+ def authorize_read_web_ide_terminal!
+ authorize_build_ability!(:read_web_ide_terminal)
+ end
+
+ def authorize_update_web_ide_terminal!
+ authorize_build_ability!(:update_web_ide_terminal)
+ end
+
+ def authorize_build_ability!(ability)
+ return access_denied! unless can?(current_user, ability, build)
+ end
+
+ def build
+ @build ||= project.builds.find(params[:id])
+ end
+
+ def branch_sha
+ return unless params[:branch].present?
+
+ project.commit(params[:branch])&.id
+ end
+
+ def render_terminal(current_build)
+ render json: WebIdeTerminalSerializer
+ .new(project: project, current_user: current_user)
+ .represent(current_build)
+ end
+end
diff --git a/app/controllers/projects/wikis_controller.rb b/app/controllers/projects/wikis_controller.rb
index 508b1f5bd0a..85e643aa212 100644
--- a/app/controllers/projects/wikis_controller.rb
+++ b/app/controllers/projects/wikis_controller.rb
@@ -1,206 +1,11 @@
# frozen_string_literal: true
class Projects::WikisController < Projects::ApplicationController
+ include WikiActions
include PreviewMarkdown
- include SendsBlob
- include Gitlab::Utils::StrongMemoize
- before_action :authorize_read_wiki!
- before_action :authorize_create_wiki!, only: [:edit, :create]
- before_action :authorize_admin_wiki!, only: :destroy
- before_action :load_project_wiki
- before_action :load_page, only: [:show, :edit, :update, :history, :destroy]
- before_action only: [:show, :edit, :update] do
- @valid_encoding = valid_encoding?
- end
- before_action only: [:edit, :update], unless: :valid_encoding? do
- redirect_to(project_wiki_path(@project, @page))
- end
-
- def new
- redirect_to project_wiki_path(@project, SecureRandom.uuid, random_title: true)
- end
-
- def pages
- @wiki_pages = Kaminari.paginate_array(
- @project_wiki.list_pages(sort: params[:sort], direction: params[:direction])
- ).page(params[:page])
-
- @wiki_entries = WikiPage.group_by_directory(@wiki_pages)
- end
-
- # `#show` handles a number of scenarios:
- #
- # - If `id` matches a WikiPage, then show the wiki page.
- # - If `id` is a file in the wiki repository, then send the file.
- # - If we know the user wants to create a new page with the given `id`,
- # then display a create form.
- # - Otherwise show the empty wiki page and invite the user to create a page.
- def show
- if @page
- set_encoding_error unless valid_encoding?
-
- # Assign vars expected by MarkupHelper
- @ref = params[:version_id]
- @path = @page.path
-
- render 'show'
- elsif file_blob
- send_blob(@project_wiki.repository, file_blob, allow_caching: @project.public?)
- elsif show_create_form?
- # Assign a title to the WikiPage unless `id` is a randomly generated slug from #new
- title = params[:id] unless params[:random_title].present?
-
- @page = build_page(title: title)
-
- render 'edit'
- else
- render 'empty'
- end
- end
-
- def edit
- end
-
- def update
- return render('empty') unless can?(current_user, :create_wiki, @project)
-
- @page = WikiPages::UpdateService.new(container: @project, current_user: current_user, params: wiki_params).execute(@page)
-
- if @page.valid?
- redirect_to(
- project_wiki_path(@project, @page),
- notice: _('Wiki was successfully updated.')
- )
- else
- render 'edit'
- end
- rescue WikiPage::PageChangedError, WikiPage::PageRenameError, Gitlab::Git::Wiki::OperationError => e
- @error = e
- render 'edit'
- end
-
- def create
- @page = WikiPages::CreateService.new(container: @project, current_user: current_user, params: wiki_params).execute
-
- if @page.persisted?
- redirect_to(
- project_wiki_path(@project, @page),
- notice: _('Wiki was successfully updated.')
- )
- else
- render action: "edit"
- end
- rescue Gitlab::Git::Wiki::OperationError => e
- @page = build_page(wiki_params)
- @error = e
-
- render 'edit'
- end
-
- def history
- if @page
- @page_versions = Kaminari.paginate_array(@page.versions(page: params[:page].to_i),
- total_count: @page.count_versions)
- .page(params[:page])
- else
- redirect_to(
- project_wiki_path(@project, :home),
- notice: _("Page not found")
- )
- end
- end
-
- def destroy
- WikiPages::DestroyService.new(container: @project, current_user: current_user).execute(@page)
-
- redirect_to project_wiki_path(@project, :home),
- status: :found,
- notice: _("Page was successfully deleted")
- rescue Gitlab::Git::Wiki::OperationError => e
- @error = e
- render 'edit'
- end
+ alias_method :container, :project
def git_access
end
-
- private
-
- def show_create_form?
- can?(current_user, :create_wiki, @project) &&
- @page.nil? &&
- # Always show the create form when the wiki has had at least one page created.
- # Otherwise, we only show the form when the user has navigated from
- # the 'empty wiki' page
- (@project_wiki.exists? || params[:view] == 'create')
- end
-
- def load_project_wiki
- @project_wiki = load_wiki
-
- # Call #wiki to make sure the Wiki Repo is initialized
- @project_wiki.wiki
-
- @sidebar_page = @project_wiki.find_sidebar(params[:version_id])
-
- unless @sidebar_page # Fallback to default sidebar
- @sidebar_wiki_entries, @sidebar_limited = @project_wiki.sidebar_entries
- end
- rescue ProjectWiki::CouldNotCreateWikiError
- flash[:notice] = _("Could not create Wiki Repository at this time. Please try again later.")
- redirect_to project_path(@project)
- false
- end
-
- def load_wiki
- ProjectWiki.new(@project, current_user)
- end
-
- def wiki_params
- params.require(:wiki).permit(:title, :content, :format, :message, :last_commit_sha)
- end
-
- def build_page(args = {})
- WikiPage.new(@project_wiki).tap do |page|
- page.update_attributes(args) # rubocop:disable Rails/ActiveRecordAliases
- end
- end
-
- def load_page
- @page ||= find_page
- end
-
- def find_page
- @project_wiki.find_page(*page_params)
- end
-
- def page_params
- keys = [:id]
- keys << :version_id if params[:action] == 'show'
-
- params.values_at(*keys)
- end
-
- def valid_encoding?
- page_encoding == Encoding::UTF_8
- end
-
- def page_encoding
- strong_memoize(:page_encoding) { @page&.content&.encoding }
- end
-
- def set_encoding_error
- flash.now[:notice] = _("The content of this page is not encoded in UTF-8. Edits can only be made via the Git repository.")
- end
-
- def file_blob
- strong_memoize(:file_blob) do
- commit = @project_wiki.repository.commit(@project_wiki.default_branch)
-
- next unless commit
-
- @project_wiki.repository.blob_at(commit.id, params[:id])
- end
- end
end