diff options
Diffstat (limited to 'app/controllers/projects')
25 files changed, 420 insertions, 105 deletions
diff --git a/app/controllers/projects/alert_management_controller.rb b/app/controllers/projects/alert_management_controller.rb new file mode 100644 index 00000000000..0c0a91e136f --- /dev/null +++ b/app/controllers/projects/alert_management_controller.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +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 + + def details + @alert_id = params[:id] + end +end diff --git a/app/controllers/projects/artifacts_controller.rb b/app/controllers/projects/artifacts_controller.rb index 50399a8cfbb..b8663bc59f2 100644 --- a/app/controllers/projects/artifacts_controller.rb +++ b/app/controllers/projects/artifacts_controller.rb @@ -10,7 +10,7 @@ class Projects::ArtifactsController < Projects::ApplicationController before_action :authorize_update_build!, only: [:keep] before_action :authorize_destroy_artifacts!, only: [:destroy] before_action :extract_ref_name_and_path - before_action :validate_artifacts!, except: [:index, :download, :destroy] + before_action :validate_artifacts!, except: [:index, :download, :raw, :destroy] before_action :entry, only: [:file] MAX_PER_PAGE = 20 @@ -22,7 +22,7 @@ class Projects::ArtifactsController < Projects::ApplicationController # issues: https://gitlab.com/gitlab-org/gitlab/issues/32281 return head :no_content unless Feature.enabled?(:artifacts_management_page, @project) - finder = ArtifactsFinder.new(@project, artifacts_params) + finder = Ci::JobArtifactsFinder.new(@project, artifacts_params) all_artifacts = finder.execute @artifacts = all_artifacts.page(params[:page]).per(MAX_PER_PAGE) @@ -73,9 +73,11 @@ class Projects::ArtifactsController < Projects::ApplicationController end def raw + return render_404 unless zip_artifact? + path = Gitlab::Ci::Build::Artifacts::Path.new(params[:path]) - send_artifacts_entry(build, path) + send_artifacts_entry(artifacts_file, path) end def keep @@ -138,6 +140,13 @@ class Projects::ArtifactsController < Projects::ApplicationController @artifacts_file ||= build&.artifacts_file_for_type(params[:file_type] || :archive) end + def zip_artifact? + types = HashWithIndifferentAccess.new(Ci::JobArtifact::TYPE_AND_FORMAT_PAIRS) + file_type = params[:file_type] || :archive + + types[file_type] == :zip + end + def entry @entry = build.artifacts_metadata_entry(params[:path]) diff --git a/app/controllers/projects/branches_controller.rb b/app/controllers/projects/branches_controller.rb index 09754409104..cc595740696 100644 --- a/app/controllers/projects/branches_controller.rb +++ b/app/controllers/projects/branches_controller.rb @@ -186,7 +186,6 @@ class Projects::BranchesController < Projects::ApplicationController end def confidential_issue_project - return unless helpers.create_confidential_merge_request_enabled? return if params[:confidential_issue_project_id].blank? confidential_issue_project = Project.find(params[:confidential_issue_project_id]) 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 new file mode 100644 index 00000000000..dfda5fca310 --- /dev/null +++ b/app/controllers/projects/ci/daily_build_group_report_results_controller.rb @@ -0,0 +1,77 @@ +# frozen_string_literal: true + +class Projects::Ci::DailyBuildGroupReportResultsController < Projects::ApplicationController + include Gitlab::Utils::StrongMemoize + + MAX_ITEMS = 1000 + 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 :validate_param_type! + + def index + respond_to do |format| + format.csv { send_data(render_csv(results), type: 'text/csv; charset=utf-8') } + end + end + + private + + def validate_feature_flag! + render_404 unless Feature.enabled?(:ci_download_daily_code_coverage, project, default_enabled: true) + end + + def validate_param_type! + respond_422 unless allowed_param_types.include?(param_type) + end + + def render_csv(collection) + CsvBuilders::SingleBatch.new( + collection, + { + date: 'date', + group_name: 'group_name', + param_type => -> (record) { record.data[param_type] } + } + ).render + end + + def results + Ci::DailyBuildGroupReportResultsFinder.new(finder_params).execute + end + + def finder_params + { + current_user: current_user, + project: project, + ref_path: params.require(:ref_path), + start_date: start_date, + end_date: end_date, + limit: MAX_ITEMS + } + end + + def start_date + strong_memoize(:start_date) do + start_date = Date.parse(params.require(:start_date)) + + # The start_date cannot be older than `end_date - 90 days` + [start_date, end_date - REPORT_WINDOW].max + end + end + + def end_date + strong_memoize(:end_date) do + Date.parse(params.require(:end_date)) + end + end + + def allowed_param_types + Ci::DailyBuildGroupReportResult::PARAM_TYPES + end + + def param_type + params.require(:param_type) + end +end diff --git a/app/controllers/projects/design_management/designs/raw_images_controller.rb b/app/controllers/projects/design_management/designs/raw_images_controller.rb new file mode 100644 index 00000000000..beb7e9d294b --- /dev/null +++ b/app/controllers/projects/design_management/designs/raw_images_controller.rb @@ -0,0 +1,30 @@ +# frozen_string_literal: true + +# Returns full-size design images +module Projects + module DesignManagement + module Designs + class RawImagesController < Projects::DesignManagement::DesignsController + include SendsBlob + + skip_before_action :default_cache_headers, only: :show + + def show + blob = design_repository.blob_at(ref, design.full_path) + + send_blob(design_repository, blob, inline: false, allow_caching: project.public?) + end + + private + + def design_repository + @design_repository ||= project.design_repository + end + + def ref + sha || design_repository.root_ref + end + end + end + end +end diff --git a/app/controllers/projects/design_management/designs/resized_image_controller.rb b/app/controllers/projects/design_management/designs/resized_image_controller.rb new file mode 100644 index 00000000000..50a997f32db --- /dev/null +++ b/app/controllers/projects/design_management/designs/resized_image_controller.rb @@ -0,0 +1,46 @@ +# frozen_string_literal: true + +# Returns smaller sized design images +module Projects + module DesignManagement + module Designs + class ResizedImageController < Projects::DesignManagement::DesignsController + include SendFileUpload + + before_action :validate_size! + + skip_before_action :default_cache_headers, only: :show + + def show + relation = design.actions + relation = relation.up_to_version(sha) if sha + action = relation.most_recent.first + + return render_404 unless action + + # This controller returns a 404 if the the `size` param + # is not one of our specific sizes, so using `send` here is safe. + uploader = action.public_send(:"image_#{size}") # rubocop:disable GitlabSecurity/PublicSend + + return render_404 unless uploader.file # The image has not been processed + + if stale?(etag: action.cache_key) + workhorse_set_content_type! + + send_upload(uploader, attachment: design.filename) + end + end + + private + + def validate_size! + render_404 unless ::DesignManagement::DESIGN_IMAGE_SIZES.include?(size) + end + + def size + params[:id] + end + end + end + end +end diff --git a/app/controllers/projects/design_management/designs_controller.rb b/app/controllers/projects/design_management/designs_controller.rb new file mode 100644 index 00000000000..fec09fa9515 --- /dev/null +++ b/app/controllers/projects/design_management/designs_controller.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true + +class Projects::DesignManagement::DesignsController < Projects::ApplicationController + before_action :authorize_read_design! + + private + + def authorize_read_design! + unless can?(current_user, :read_design, design) + access_denied! + end + end + + def design + @design ||= project.designs.find(params[:design_id]) + end + + def sha + params[:sha].presence + end +end diff --git a/app/controllers/projects/environments_controller.rb b/app/controllers/projects/environments_controller.rb index 09dc4d118a1..5f4d88c57e9 100644 --- a/app/controllers/projects/environments_controller.rb +++ b/app/controllers/projects/environments_controller.rb @@ -4,6 +4,12 @@ class Projects::EnvironmentsController < Projects::ApplicationController include MetricsDashboard layout 'project' + + before_action only: [:metrics, :additional_metrics, :metrics_dashboard] do + authorize_metrics_dashboard! + + push_frontend_feature_flag(:prometheus_computed_alerts) + end before_action :authorize_read_environment! before_action :authorize_create_environment!, only: [:new, :create] before_action :authorize_stop_environment!, only: [:stop] @@ -12,10 +18,6 @@ class Projects::EnvironmentsController < Projects::ApplicationController before_action :environment, only: [:show, :edit, :update, :stop, :terminal, :terminal_websocket_authorize, :metrics, :cancel_auto_stop] before_action :verify_api_request!, only: :terminal_websocket_authorize before_action :expire_etag_cache, only: [:index], unless: -> { request.format.json? } - before_action only: [:metrics, :additional_metrics, :metrics_dashboard] do - push_frontend_feature_flag(:prometheus_computed_alerts) - push_frontend_feature_flag(:metrics_dashboard_annotations) - end after_action :expire_etag_cache, only: [:cancel_auto_stop] def index @@ -27,12 +29,13 @@ class Projects::EnvironmentsController < Projects::ApplicationController format.html format.json do Gitlab::PollingInterval.set_header(response, interval: 3_000) + environments_count_by_state = project.environments.count_by_state render json: { environments: serialize_environments(request, response, params[:nested]), review_app: serialize_review_app, - available_count: project.environments.available.count, - stopped_count: project.environments.stopped.count + available_count: environments_count_by_state[:available], + stopped_count: environments_count_by_state[:stopped] } end end diff --git a/app/controllers/projects/graphs_controller.rb b/app/controllers/projects/graphs_controller.rb index 889dcefb65a..34246f27241 100644 --- a/app/controllers/projects/graphs_controller.rb +++ b/app/controllers/projects/graphs_controller.rb @@ -28,6 +28,7 @@ class Projects::GraphsController < Projects::ApplicationController def charts get_commits get_languages + get_daily_coverage_options end def ci @@ -52,6 +53,27 @@ class Projects::GraphsController < Projects::ApplicationController end end + def get_daily_coverage_options + return unless Feature.enabled?(:ci_download_daily_code_coverage, default_enabled: true) + + date_today = Date.current + report_window = Projects::Ci::DailyBuildGroupReportResultsController::REPORT_WINDOW + + @daily_coverage_options = { + base_params: { + start_date: date_today - report_window, + end_date: date_today, + ref_path: @project.repository.expand_ref(@ref), + param_type: 'coverage' + }, + download_path: namespace_project_ci_daily_build_group_report_results_path( + namespace_id: @project.namespace, + project_id: @project, + format: :csv + ) + } + end + def fetch_graph @commits = @project.repository.commits(@ref, limit: 6000, skip_merges: true) @log = [] diff --git a/app/controllers/projects/import/jira_controller.rb b/app/controllers/projects/import/jira_controller.rb index 4a70ed45404..711e23dc3ce 100644 --- a/app/controllers/projects/import/jira_controller.rb +++ b/app/controllers/projects/import/jira_controller.rb @@ -36,7 +36,7 @@ module Projects 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.' + flash[:alert] = 'No Jira project key has been provided.' end redirect_to project_import_jira_path(@project) diff --git a/app/controllers/projects/issues_controller.rb b/app/controllers/projects/issues_controller.rb index 3aae8990f07..3e9d956f7b1 100644 --- a/app/controllers/projects/issues_controller.rb +++ b/app/controllers/projects/issues_controller.rb @@ -21,7 +21,6 @@ class Projects::IssuesController < Projects::ApplicationController prepend_before_action(only: [:index]) { authenticate_sessionless_user!(:rss) } prepend_before_action(only: [:calendar]) { authenticate_sessionless_user!(:ics) } prepend_before_action :authenticate_user!, only: [:new, :export_csv] - # designs is only applicable to EE, but defining a prepend_before_action in EE code would overwrite this prepend_before_action :store_uri, only: [:new, :show, :designs] before_action :whitelist_query_limiting, only: [:create, :create_merge_request, :move, :bulk_update] @@ -50,6 +49,10 @@ class Projects::IssuesController < Projects::ApplicationController push_frontend_feature_flag(:save_issuable_health_status, project.group, default_enabled: true) end + before_action only: :show do + push_frontend_feature_flag(:real_time_issue_sidebar, @project) + end + around_action :allow_gitaly_ref_name_caching, only: [:discussions] respond_to :html @@ -81,11 +84,13 @@ class Projects::IssuesController < Projects::ApplicationController ) build_params = issue_params.merge( merge_request_to_resolve_discussions_of: params[:merge_request_to_resolve_discussions_of], - discussion_to_resolve: params[:discussion_to_resolve] + discussion_to_resolve: params[:discussion_to_resolve], + confidential: !!Gitlab::Utils.to_boolean(params[:issue][:confidential]) ) service = Issues::BuildService.new(project, current_user, build_params) @issue = @noteable = service.execute + @merge_request_to_resolve_discussions_of = service.merge_request_to_resolve_discussions_of @discussion_to_resolve = service.discussions_to_resolve.first if params[:discussion_to_resolve] @@ -154,7 +159,10 @@ class Projects::IssuesController < Projects::ApplicationController end def related_branches - @related_branches = Issues::RelatedBranchesService.new(project, current_user).execute(issue) + @related_branches = Issues::RelatedBranchesService + .new(project, current_user) + .execute(issue) + .map { |branch| branch.merge(link: branch_link(branch)) } respond_to do |format| format.json do @@ -179,7 +187,7 @@ class Projects::IssuesController < Projects::ApplicationController def create_merge_request create_params = params.slice(:branch_name, :ref).merge(issue_iid: issue.iid) - create_params[:target_project_id] = params[:target_project_id] if helpers.create_confidential_merge_request_enabled? + create_params[:target_project_id] = params[:target_project_id] result = ::MergeRequests::CreateFromIssueService.new(project, current_user, create_params).execute if result[:status] == :success @@ -193,7 +201,8 @@ class Projects::IssuesController < Projects::ApplicationController ExportCsvWorker.perform_async(current_user.id, project.id, finder_options.to_h) # rubocop:disable CodeReuse/Worker index_path = project_issues_path(project) - redirect_to(index_path, notice: "Your CSV export has started. It will be emailed to #{current_user.notification_email} when complete.") + message = _('Your CSV export has started. It will be emailed to %{email} when complete.') % { email: current_user.notification_email } + redirect_to(index_path, notice: message) end def import_csv @@ -305,6 +314,10 @@ class Projects::IssuesController < Projects::ApplicationController private + def branch_link(branch) + project_compare_path(project, from: project.default_branch, to: branch[:name]) + end + def create_rate_limit key = :issues_create diff --git a/app/controllers/projects/mattermosts_controller.rb b/app/controllers/projects/mattermosts_controller.rb index 085b1bc1498..cfaeddf711a 100644 --- a/app/controllers/projects/mattermosts_controller.rb +++ b/app/controllers/projects/mattermosts_controller.rb @@ -30,7 +30,7 @@ class Projects::MattermostsController < Projects::ApplicationController def configure_params params.require(:mattermost).permit(:trigger, :team_id).merge( url: service_trigger_url(@service), - icon_url: asset_url('slash-command-logo.png')) + icon_url: asset_url('slash-command-logo.png', skip_pipeline: true)) end def teams diff --git a/app/controllers/projects/merge_requests/creations_controller.rb b/app/controllers/projects/merge_requests/creations_controller.rb index 23222cbd37c..28aa1b300aa 100644 --- a/app/controllers/projects/merge_requests/creations_controller.rb +++ b/app/controllers/projects/merge_requests/creations_controller.rb @@ -16,7 +16,6 @@ class Projects::MergeRequests::CreationsController < Projects::MergeRequests::Ap end def create - @target_branches ||= [] @merge_request = ::MergeRequests::CreateService.new(project, current_user, merge_request_params).execute if @merge_request.valid? @@ -97,13 +96,6 @@ class Projects::MergeRequests::CreationsController < Projects::MergeRequests::Ap def define_new_vars @noteable = @merge_request - - @target_branches = if @merge_request.target_project - @merge_request.target_project.repository.branch_names - else - [] - end - @target_project = @merge_request.target_project @source_project = @merge_request.source_project diff --git a/app/controllers/projects/merge_requests/diffs_controller.rb b/app/controllers/projects/merge_requests/diffs_controller.rb index 79598c0aaff..2331674f42c 100644 --- a/app/controllers/projects/merge_requests/diffs_controller.rb +++ b/app/controllers/projects/merge_requests/diffs_controller.rb @@ -9,6 +9,8 @@ class Projects::MergeRequests::DiffsController < Projects::MergeRequests::Applic before_action :define_diff_vars before_action :define_diff_comment_vars, except: [:diffs_batch, :diffs_metadata] + around_action :allow_gitaly_ref_name_caching + def show render_diffs end diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb index 8c37d70d4c9..5613b5b9589 100644 --- a/app/controllers/projects/merge_requests_controller.rb +++ b/app/controllers/projects/merge_requests_controller.rb @@ -14,7 +14,13 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo skip_before_action :merge_request, only: [:index, :bulk_update] before_action :whitelist_query_limiting, only: [:assign_related_issues, :update] before_action :authorize_update_issuable!, only: [:close, :edit, :update, :remove_wip, :sort] - before_action :authorize_read_actual_head_pipeline!, only: [:test_reports, :exposed_artifacts, :coverage_reports] + before_action :authorize_read_actual_head_pipeline!, only: [ + :test_reports, + :exposed_artifacts, + :coverage_reports, + :terraform_reports, + :accessibility_reports + ] before_action :set_issuables_index, only: [:index] before_action :authenticate_user!, only: [:assign_related_issues] before_action :check_user_can_push_to_source_branch!, only: [:rebase] @@ -26,7 +32,7 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo push_frontend_feature_flag(:code_navigation, @project) push_frontend_feature_flag(:widget_visibility_polling, @project, default_enabled: true) push_frontend_feature_flag(:merge_ref_head_comments, @project) - push_frontend_feature_flag(:diff_compare_with_head, @project) + push_frontend_feature_flag(:mr_commit_neighbor_nav, @project, default_enabled: true) end before_action do @@ -136,6 +142,14 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo reports_response(@merge_request.compare_test_reports) end + def accessibility_reports + if @merge_request.has_accessibility_reports? + reports_response(@merge_request.compare_accessibility_reports) + else + head :no_content + end + end + def coverage_reports if @merge_request.has_coverage_reports? reports_response(@merge_request.find_coverage_reports) @@ -144,6 +158,10 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo end end + def terraform_reports + reports_response(@merge_request.find_terraform_reports) + end + def exposed_artifacts if @merge_request.has_exposed_artifacts? reports_response(@merge_request.find_exposed_artifacts) @@ -353,7 +371,6 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo def define_edit_vars @source_project = @merge_request.source_project @target_project = @merge_request.target_project - @target_branches = @merge_request.target_project.repository.branch_names @noteable = @merge_request # FIXME: We have to assign a presenter to another instance variable diff --git a/app/controllers/projects/pipelines_controller.rb b/app/controllers/projects/pipelines_controller.rb index 726ce8974c7..678d0862f48 100644 --- a/app/controllers/projects/pipelines_controller.rb +++ b/app/controllers/projects/pipelines_controller.rb @@ -11,7 +11,9 @@ class Projects::PipelinesController < Projects::ApplicationController before_action :authorize_create_pipeline!, only: [:new, :create] before_action :authorize_update_pipeline!, only: [:retry, :cancel] before_action do - push_frontend_feature_flag(:junit_pipeline_view) + 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) end before_action :ensure_pipeline, only: [:show] @@ -22,9 +24,8 @@ class Projects::PipelinesController < Projects::ApplicationController POLLING_INTERVAL = 10_000 def index - @scope = params[:scope] @pipelines = Ci::PipelinesFinder - .new(project, current_user, scope: @scope) + .new(project, current_user, index_params) .execute .page(params[:page]) .per(30) @@ -69,6 +70,8 @@ class Projects::PipelinesController < Projects::ApplicationController end def show + Gitlab::QueryLimiting.whitelist('https://gitlab.com/gitlab-org/gitlab/-/issues/26657') + respond_to do |format| format.html format.json do @@ -91,6 +94,10 @@ class Projects::PipelinesController < Projects::ApplicationController render_show end + def dag + render_show + end + def failures if @pipeline.failed_builds.present? render_show @@ -169,19 +176,9 @@ class Projects::PipelinesController < Projects::ApplicationController end format.json do - if pipeline_test_report == :error - render json: { status: :error_parsing_report } - else - test_reports = if params[:scope] == "with_attachment" - pipeline_test_report.with_attachment! - else - pipeline_test_report - end - - render json: TestReportSerializer - .new(current_user: @current_user) - .represent(test_reports, project: project) - end + render json: TestReportSerializer + .new(current_user: @current_user) + .represent(pipeline_test_report, project: project) end end end @@ -189,11 +186,7 @@ class Projects::PipelinesController < Projects::ApplicationController def test_reports_count return unless Feature.enabled?(:junit_pipeline_view, project) - begin - render json: { total_count: pipeline.test_reports_count }.to_json - rescue Gitlab::Ci::Parsers::ParserError - render json: { total_count: 0 }.to_json - end + render json: { total_count: pipeline.test_reports_count }.to_json end private @@ -262,18 +255,22 @@ class Projects::PipelinesController < Projects::ApplicationController end def limited_pipelines_count(project, scope = nil) - finder = Ci::PipelinesFinder.new(project, current_user, scope: scope) + finder = Ci::PipelinesFinder.new(project, current_user, index_params.merge(scope: scope)) view_context.limited_counter_with_delimiter(finder.execute) end def pipeline_test_report strong_memoize(:pipeline_test_report) do - @pipeline.test_reports - rescue Gitlab::Ci::Parsers::ParserError - :error + @pipeline.test_reports.tap do |reports| + reports.with_attachment! if params[:scope] == 'with_attachment' + end end end + + def index_params + params.permit(:scope, :username, :ref) + end end Projects::PipelinesController.prepend_if_ee('EE::Projects::PipelinesController') diff --git a/app/controllers/projects/project_members_controller.rb b/app/controllers/projects/project_members_controller.rb index 109c8b7005f..3e52248f292 100644 --- a/app/controllers/projects/project_members_controller.rb +++ b/app/controllers/projects/project_members_controller.rb @@ -17,8 +17,9 @@ class Projects::ProjectMembersController < Projects::ApplicationController @group_links = @project.project_group_links @group_links = @group_links.search(params[:search]) if params[:search].present? - @project_members = MembersFinder.new(@project, current_user) - .execute(include_relations: requested_relations, params: params.merge(sort: @sort)) + @project_members = MembersFinder + .new(@project, current_user, params: filter_params) + .execute(include_relations: requested_relations) @project_members = present_members(@project_members.page(params[:page])) @@ -43,12 +44,17 @@ class Projects::ProjectMembersController < Projects::ApplicationController return render_404 end - redirect_to(project_project_members_path(project), - notice: notice) + redirect_to(project_project_members_path(project), notice: notice) end # MembershipActions concern alias_method :membershipable, :project + + private + + def filter_params + params.permit(:search).merge(sort: @sort) + end end Projects::ProjectMembersController.prepend_if_ee('EE::Projects::ProjectMembersController') diff --git a/app/controllers/projects/refs_controller.rb b/app/controllers/projects/refs_controller.rb index 7c606bd8c45..fcbeb5c840c 100644 --- a/app/controllers/projects/refs_controller.rb +++ b/app/controllers/projects/refs_controller.rb @@ -12,7 +12,7 @@ class Projects::RefsController < Projects::ApplicationController before_action :authorize_download_code! before_action only: [:logs_tree] do - push_frontend_feature_flag(:vue_file_list_lfs_badge) + push_frontend_feature_flag(:vue_file_list_lfs_badge, default_enabled: true) end def switch @@ -44,30 +44,25 @@ class Projects::RefsController < Projects::ApplicationController end def logs_tree - summary = ::Gitlab::TreeSummary.new( - @commit, - @project, - path: @path, - offset: params[:offset], - limit: 25 - ) - - @logs, commits = summary.summarize - @more_log_url = more_url(summary.next_offset) if summary.more? + tree_summary = ::Gitlab::TreeSummary.new( + @commit, @project, current_user, + path: @path, offset: params[:offset], limit: 25) respond_to do |format| format.html { render_404 } format.json do - response.headers["More-Logs-Url"] = @more_log_url if summary.more? - response.headers["More-Logs-Offset"] = summary.next_offset if summary.more? - render json: @logs + logs, next_offset = tree_summary.fetch_logs + + response.headers["More-Logs-Offset"] = next_offset if next_offset + + render json: logs end - # The commit titles must be rendered and redacted before being shown. - # Doing it here allows us to apply performance optimizations that avoid - # N+1 problems + # Deprecated due to https://gitlab.com/gitlab-org/gitlab/-/issues/36863 + # Will be removed soon https://gitlab.com/gitlab-org/gitlab/-/merge_requests/29895 format.js do - prerender_commit_full_titles!(commits) + @logs, _ = tree_summary.summarize + @more_log_url = more_url(tree_summary.next_offset) if tree_summary.more? end end end @@ -78,14 +73,6 @@ class Projects::RefsController < Projects::ApplicationController logs_file_project_ref_path(@project, @ref, @path, offset: offset) end - def prerender_commit_full_titles!(commits) - # Preload commit authors as they are used in rendering - commits.each(&:lazy_author) - - renderer = Banzai::ObjectRenderer.new(user: current_user, default_project: @project) - renderer.render(commits, :full_title) - end - def validate_ref_id return not_found! if params[:id].present? && params[:id] !~ Gitlab::PathRegex.git_reference_regex end diff --git a/app/controllers/projects/registry/repositories_controller.rb b/app/controllers/projects/registry/repositories_controller.rb index 2418ea97409..19d0cb9acdc 100644 --- a/app/controllers/projects/registry/repositories_controller.rb +++ b/app/controllers/projects/registry/repositories_controller.rb @@ -10,7 +10,8 @@ module Projects respond_to do |format| format.html format.json do - @images = project.container_repositories + @images = ContainerRepositoriesFinder.new(user: current_user, subject: project, params: params.slice(:name)) + .execute track_event(:list_repositories) diff --git a/app/controllers/projects/settings/access_tokens_controller.rb b/app/controllers/projects/settings/access_tokens_controller.rb new file mode 100644 index 00000000000..d6b4c4dd5dc --- /dev/null +++ b/app/controllers/projects/settings/access_tokens_controller.rb @@ -0,0 +1,71 @@ +# frozen_string_literal: true + +module Projects + module Settings + class AccessTokensController < Projects::ApplicationController + include ProjectsHelper + + before_action :check_feature_availability + + def index + @project_access_token = PersonalAccessToken.new + set_index_vars + end + + def create + token_response = ResourceAccessTokens::CreateService.new(current_user, @project, create_params).execute + + if token_response.success? + @project_access_token = token_response.payload[:access_token] + PersonalAccessToken.redis_store!(key_identity, @project_access_token.token) + + redirect_to namespace_project_settings_access_tokens_path, notice: _("Your new project access token has been created.") + else + render :index + end + end + + def revoke + @project_access_token = finder.find(params[:id]) + revoked_response = ResourceAccessTokens::RevokeService.new(current_user, @project, @project_access_token).execute + + if revoked_response.success? + flash[:notice] = _("Revoked project access token %{project_access_token_name}!") % { project_access_token_name: @project_access_token.name } + else + flash[:alert] = _("Could not revoke project access token %{project_access_token_name}.") % { project_access_token_name: @project_access_token.name } + end + + redirect_to namespace_project_settings_access_tokens_path + end + + private + + def check_feature_availability + render_404 unless project_access_token_available?(@project) + end + + def create_params + params.require(:project_access_token).permit(:name, :expires_at, scopes: []) + end + + def set_index_vars + @scopes = Gitlab::Auth.resource_bot_scopes + @active_project_access_tokens = finder(state: 'active').execute + @inactive_project_access_tokens = finder(state: 'inactive', sort: 'expires_at_asc').execute + @new_project_access_token = PersonalAccessToken.redis_getdel(key_identity) + end + + def finder(options = {}) + PersonalAccessTokensFinder.new({ user: bot_users, impersonation: false }.merge(options)) + end + + def bot_users + @project.bots + end + + def key_identity + "#{current_user.id}:#{@project.id}" + end + end + end +end diff --git a/app/controllers/projects/settings/repository_controller.rb b/app/controllers/projects/settings/repository_controller.rb index 0aa55dcc5b9..35ca9336613 100644 --- a/app/controllers/projects/settings/repository_controller.rb +++ b/app/controllers/projects/settings/repository_controller.rb @@ -89,7 +89,7 @@ module Projects end def deploy_token_params - params.require(:deploy_token).permit(:name, :expires_at, :read_repository, :read_registry, :write_registry, :username) + params.require(:deploy_token).permit(:name, :expires_at, :read_repository, :read_registry, :write_registry, :read_package_registry, :write_package_registry, :username) end def access_levels_options diff --git a/app/controllers/projects/snippets_controller.rb b/app/controllers/projects/snippets_controller.rb index da0e3a44f05..9233f063f55 100644 --- a/app/controllers/projects/snippets_controller.rb +++ b/app/controllers/projects/snippets_controller.rb @@ -52,15 +52,8 @@ class Projects::SnippetsController < Projects::ApplicationController create_params = snippet_params.merge(spammable_params) service_response = Snippets::CreateService.new(project, current_user, create_params).execute @snippet = service_response.payload[:snippet] - repository_operation_error = service_response.error? && !@snippet.persisted? && @snippet.valid? - if repository_operation_error - flash.now[:alert] = service_response.message - - render :new - else - recaptcha_check_with_fallback { render :new } - end + handle_repository_error(:new) end def update @@ -69,7 +62,7 @@ class Projects::SnippetsController < Projects::ApplicationController service_response = Snippets::UpdateService.new(project, current_user, update_params).execute(@snippet) @snippet = service_response.payload[:snippet] - check_repository_error + handle_repository_error(:edit) end def show diff --git a/app/controllers/projects/tree_controller.rb b/app/controllers/projects/tree_controller.rb index b8fe2a47b30..9cb345724cc 100644 --- a/app/controllers/projects/tree_controller.rb +++ b/app/controllers/projects/tree_controller.rb @@ -16,7 +16,7 @@ class Projects::TreeController < Projects::ApplicationController before_action :authorize_edit_tree!, only: [:create_dir] before_action only: [:show] do - push_frontend_feature_flag(:vue_file_list_lfs_badge) + push_frontend_feature_flag(:vue_file_list_lfs_badge, default_enabled: true) end def show diff --git a/app/controllers/projects/usage_ping_controller.rb b/app/controllers/projects/usage_ping_controller.rb index ebdf28bd59c..0e2c8f879b1 100644 --- a/app/controllers/projects/usage_ping_controller.rb +++ b/app/controllers/projects/usage_ping_controller.rb @@ -10,4 +10,10 @@ class Projects::UsagePingController < Projects::ApplicationController head(200) end + + def web_ide_pipelines_count + Gitlab::UsageDataCounters::WebIdeCounter.increment_pipelines_count + + head(200) + end end diff --git a/app/controllers/projects/wikis_controller.rb b/app/controllers/projects/wikis_controller.rb index 90ff798077a..508b1f5bd0a 100644 --- a/app/controllers/projects/wikis_controller.rb +++ b/app/controllers/projects/wikis_controller.rb @@ -10,8 +10,9 @@ class Projects::WikisController < Projects::ApplicationController before_action :authorize_admin_wiki!, only: :destroy before_action :load_project_wiki before_action :load_page, only: [:show, :edit, :update, :history, :destroy] - before_action :valid_encoding?, - if: -> { %w[show edit update].include?(action_name) && load_page } + 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 @@ -64,7 +65,7 @@ class Projects::WikisController < Projects::ApplicationController def update return render('empty') unless can?(current_user, :create_wiki, @project) - @page = WikiPages::UpdateService.new(@project, current_user, wiki_params).execute(@page) + @page = WikiPages::UpdateService.new(container: @project, current_user: current_user, params: wiki_params).execute(@page) if @page.valid? redirect_to( @@ -80,7 +81,7 @@ class Projects::WikisController < Projects::ApplicationController end def create - @page = WikiPages::CreateService.new(@project, current_user, wiki_params).execute + @page = WikiPages::CreateService.new(container: @project, current_user: current_user, params: wiki_params).execute if @page.persisted? redirect_to( @@ -111,7 +112,7 @@ class Projects::WikisController < Projects::ApplicationController end def destroy - WikiPages::DestroyService.new(@project, current_user).execute(@page) + WikiPages::DestroyService.new(container: @project, current_user: current_user).execute(@page) redirect_to project_wiki_path(@project, :home), status: :found, @@ -144,7 +145,7 @@ class Projects::WikisController < Projects::ApplicationController @sidebar_page = @project_wiki.find_sidebar(params[:version_id]) unless @sidebar_page # Fallback to default sidebar - @sidebar_wiki_entries = WikiPage.group_by_directory(@project_wiki.list_pages(limit: 15)) + @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.") @@ -167,7 +168,11 @@ class Projects::WikisController < Projects::ApplicationController end def load_page - @page ||= @project_wiki.find_page(*page_params) + @page ||= find_page + end + + def find_page + @project_wiki.find_page(*page_params) end def page_params @@ -178,9 +183,11 @@ class Projects::WikisController < Projects::ApplicationController end def valid_encoding? - strong_memoize(:valid_encoding) do - @page.content.encoding == Encoding::UTF_8 - end + page_encoding == Encoding::UTF_8 + end + + def page_encoding + strong_memoize(:page_encoding) { @page&.content&.encoding } end def set_encoding_error |