diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2020-06-18 14:18:50 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2020-06-18 14:18:50 +0300 |
commit | 8c7f4e9d5f36cff46365a7f8c4b9c21578c1e781 (patch) | |
tree | a77e7fe7a93de11213032ed4ab1f33a3db51b738 /app/controllers/projects | |
parent | 00b35af3db1abfe813a778f643dad221aad51fca (diff) |
Add latest changes from gitlab-org/gitlab@13-1-stable-ee
Diffstat (limited to 'app/controllers/projects')
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 |