diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2021-10-20 11:43:02 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2021-10-20 11:43:02 +0300 |
commit | d9ab72d6080f594d0b3cae15f14b3ef2c6c638cb (patch) | |
tree | 2341ef426af70ad1e289c38036737e04b0aa5007 /app/presenters | |
parent | d6e514dd13db8947884cd58fe2a9c2a063400a9b (diff) |
Add latest changes from gitlab-org/gitlab@14-4-stable-eev14.4.0-rc42
Diffstat (limited to 'app/presenters')
56 files changed, 221 insertions, 96 deletions
diff --git a/app/presenters/README.md b/app/presenters/README.md index 62aec4fc8a2..dfd1818f97d 100644 --- a/app/presenters/README.md +++ b/app/presenters/README.md @@ -66,14 +66,15 @@ we gain the following benefits: ### Presenter definition -Every presenter should inherit from `Gitlab::View::Presenter::Simple`, which -provides a `.presents` the method which allows you to define an accessor for the +If you need a presenter class that has only necessary interfaces for the view-related context, +inherit from `Gitlab::View::Presenter::Simple`. +It provides a `.presents` the method which allows you to define an accessor for the presented object. It also includes common helpers like `Gitlab::Routing` and `Gitlab::Allowable`. ```ruby class LabelPresenter < Gitlab::View::Presenter::Simple - presents :label + presents ::Label, as: :label def text_color label.color.to_s @@ -85,13 +86,14 @@ class LabelPresenter < Gitlab::View::Presenter::Simple end ``` -In some cases, it can be more practical to transparently delegate all missing -method calls to the presented object, in these cases, you can make your -presenter inherit from `Gitlab::View::Presenter::Delegated`: +If you need a presenter class that delegates missing method calls to the presented object, +inherit from `Gitlab::View::Presenter::Delegated`. +This is more like an "extension" in the sense that the produced object is going to have +all of interfaces of the presented object **AND** all of the interfaces in the presenter class: ```ruby class LabelPresenter < Gitlab::View::Presenter::Delegated - presents :label + presents ::Label, as: :label def text_color # color is delegated to label @@ -152,3 +154,82 @@ You can also present the model in the view: %div{ class: label.text_color } = render partial: label, label: label ``` + +### Validate accidental overrides + +We use presenters in many places, such as Controller, Haml, GraphQL/Rest API, +it's very handy to extend the core/backend logic of Active Record models, +however, there is a risk that it accidentally overrides important logic. + +For example, [this production incident](https://gitlab.com/gitlab-com/gl-infra/production/-/issues/5498) +was caused by [including `ActionView::Helpers::UrlHelper` in a presenter](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/69537/diffs#4b581cff00ef3cc9780efd23682af383de302e7d_3_3). +The `tag` accesor in `Ci::Build` was accidentally overridden by `ActionView::Helpers::TagHelper#tag`, +and as a conseuqence, a wrong `tag` value was persited into database. + +Starting from GitLab 14.4, we validate the presenters (specifically all of the subclasses of `Gitlab::View::Presenter::Delegated`) +that they do not accidentally override core/backend logic. In such case, a pipeline in merge requests fails with an error message, +here is an example: + +```plaintext +We've detected that a presetner is overriding a specific method(s) on a subject model. +There is a risk that it accidentally modifies the backend/core logic that leads to production incident. +Please follow https://gitlab.com/gitlab-org/gitlab/-/blob/master/app/presenters/README.md#validate-accidental-overrides +to resolve this error with caution. + +Here are the conflict details. + +- Ci::PipelinePresenter#tag is overriding Ci::Pipeline#tag. delegator_location: /devkitkat/services/rails/cache/ruby/2.7.0/gems/actionview-6.1.3.2/lib/action_view/helpers/tag_helper.rb:271 original_location: /devkitkat/services/rails/cache/ruby/2.7.0/gems/activemodel-6.1.3.2/lib/active_model/attribute_methods.rb:254 +``` + +Here are the potential solutions: + +- If the conflict happens on an instance method in the presenter: + - If you intend to override the core/backend logic, define `delegator_override <method-name>` on top of the conflicted method. + This explicitly adds the method to an allowlist. + - If you do NOT intend to override the core/backend logic, rename the method name in the presenter. +- If the conflict happens on an included module in the presenter, remove the module from the presenter and find a workaround. + +### How to use the `Gitlab::Utils::DelegatorOverride` validator + +If a presenter class inhertis from `Gitlab::View::Presenter::Delegated`, +you should define what object class is presented: + +```ruby +class WebHookLogPresenter < Gitlab::View::Presenter::Delegated + presents ::WebHookLog, as: :web_hook_log # This defines that the presenter presents `WebHookLog` Active Record model. +``` + +These presenters are validated not to accidentaly override the methods in the presented object. +You can run the validation locally with: + +```shell +bundle exec rake lint:static_verification +``` + +To add a method to an allowlist, use `delegator_override`. For example: + +```ruby +class VulnerabilityPresenter < Gitlab::View::Presenter::Delegated + presents ::Vulnerability, as: :vulnerability + + delegator_override :description # This adds the `description` method to an allowlist that the override is intentional. + def description + vulnerability.description || finding.description + end +``` + +To add methods of a module to an allowlist, use `delegator_override_with`. For example: + +```ruby +module Ci + class PipelinePresenter < Gitlab::View::Presenter::Delegated + include Gitlab::Utils::StrongMemoize + include ActionView::Helpers::UrlHelper + + delegator_override_with Gitlab::Utils::StrongMemoize # TODO: Remove `Gitlab::Utils::StrongMemoize` inclusion as it's duplicate + delegator_override_with ActionView::Helpers::TagHelper # TODO: Remove `ActionView::Helpers::UrlHelper` inclusion as it overrides `Ci::Pipeline#tag` +``` + +Keep in mind that if you use `delegator_override_with`, +there is a high chance that you're doing **something wrong**. +Read the [Validate Accidental Overrides](#validate-accidental-overrides) for more information. diff --git a/app/presenters/alert_management/alert_presenter.rb b/app/presenters/alert_management/alert_presenter.rb index c6c6fe837a0..86fe9859271 100644 --- a/app/presenters/alert_management/alert_presenter.rb +++ b/app/presenters/alert_management/alert_presenter.rb @@ -2,10 +2,12 @@ module AlertManagement class AlertPresenter < Gitlab::View::Presenter::Delegated - include Gitlab::Utils::StrongMemoize include IncidentManagement::Settings include ActionView::Helpers::UrlHelper + presents ::AlertManagement::Alert + delegator_override_with Gitlab::Utils::StrongMemoize # TODO: Remove `Gitlab::Utils::StrongMemoize` inclusion as it's duplicate + MARKDOWN_LINE_BREAK = " \n" HORIZONTAL_LINE = "\n\n---\n\n" @@ -30,6 +32,7 @@ module AlertManagement started_at&.strftime('%d %B %Y, %-l:%M%p (%Z)') end + delegator_override :details_url def details_url details_project_alert_management_url(project, alert.iid) end @@ -65,6 +68,7 @@ module AlertManagement private attr_reader :alert, :project + delegate :alert_markdown, :full_query, to: :parsed_payload def issue_summary_markdown diff --git a/app/presenters/award_emoji_presenter.rb b/app/presenters/award_emoji_presenter.rb index 98713855d35..8a7b58e0aba 100644 --- a/app/presenters/award_emoji_presenter.rb +++ b/app/presenters/award_emoji_presenter.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true class AwardEmojiPresenter < Gitlab::View::Presenter::Delegated - presents :award_emoji + presents ::AwardEmoji, as: :award_emoji def description as_emoji['description'] diff --git a/app/presenters/blob_presenter.rb b/app/presenters/blob_presenter.rb index ecc16e2840c..c198859aa4c 100644 --- a/app/presenters/blob_presenter.rb +++ b/app/presenters/blob_presenter.rb @@ -7,7 +7,7 @@ class BlobPresenter < Gitlab::View::Presenter::Delegated include TreeHelper include ChecksCollaboration - presents :blob + presents ::Blob, as: :blob def highlight(to: nil, plain: nil) load_all_blob_data diff --git a/app/presenters/blobs/unfold_presenter.rb b/app/presenters/blobs/unfold_presenter.rb index 487c6fe0757..b921b5bf670 100644 --- a/app/presenters/blobs/unfold_presenter.rb +++ b/app/presenters/blobs/unfold_presenter.rb @@ -6,6 +6,8 @@ module Blobs include ActiveModel::AttributeAssignment include Gitlab::Utils::StrongMemoize + presents ::Blob + attribute :full, :boolean, default: false attribute :since, :integer, default: 1 attribute :to, :integer, default: 1 diff --git a/app/presenters/board_presenter.rb b/app/presenters/board_presenter.rb index d7cecd44dd7..bb3e96b8faf 100644 --- a/app/presenters/board_presenter.rb +++ b/app/presenters/board_presenter.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true class BoardPresenter < Gitlab::View::Presenter::Delegated - presents :board + presents ::Board, as: :board end diff --git a/app/presenters/ci/bridge_presenter.rb b/app/presenters/ci/bridge_presenter.rb index 724e10c26c3..a62d7cdbbd4 100644 --- a/app/presenters/ci/bridge_presenter.rb +++ b/app/presenters/ci/bridge_presenter.rb @@ -2,6 +2,9 @@ module Ci class BridgePresenter < ProcessablePresenter + presents ::Ci::Bridge + + delegator_override :detailed_status def detailed_status @detailed_status ||= subject.detailed_status(user) end diff --git a/app/presenters/ci/build_metadata_presenter.rb b/app/presenters/ci/build_metadata_presenter.rb index 4871bb3a919..2f559adf77d 100644 --- a/app/presenters/ci/build_metadata_presenter.rb +++ b/app/presenters/ci/build_metadata_presenter.rb @@ -9,8 +9,9 @@ module Ci job_timeout_source: 'job' }.freeze - presents :metadata + presents ::Ci::BuildMetadata, as: :metadata + delegator_override :timeout_source def timeout_source return unless metadata.timeout_source? diff --git a/app/presenters/ci/build_presenter.rb b/app/presenters/ci/build_presenter.rb index 06ed6791bb7..65e1c80085f 100644 --- a/app/presenters/ci/build_presenter.rb +++ b/app/presenters/ci/build_presenter.rb @@ -2,6 +2,8 @@ module Ci class BuildPresenter < ProcessablePresenter + presents ::Ci::Build + def erased_by_user? # Build can be erased through API, therefore it does not have # `erased_by` user assigned in that case. diff --git a/app/presenters/ci/group_variable_presenter.rb b/app/presenters/ci/group_variable_presenter.rb index 99011150c84..dea9a42b622 100644 --- a/app/presenters/ci/group_variable_presenter.rb +++ b/app/presenters/ci/group_variable_presenter.rb @@ -2,7 +2,7 @@ module Ci class GroupVariablePresenter < Gitlab::View::Presenter::Delegated - presents :variable + presents ::Ci::GroupVariable, as: :variable def placeholder 'GROUP_VARIABLE' diff --git a/app/presenters/ci/legacy_stage_presenter.rb b/app/presenters/ci/legacy_stage_presenter.rb index d5c21baba28..c803abfab6a 100644 --- a/app/presenters/ci/legacy_stage_presenter.rb +++ b/app/presenters/ci/legacy_stage_presenter.rb @@ -2,7 +2,7 @@ module Ci class LegacyStagePresenter < Gitlab::View::Presenter::Delegated - presents :legacy_stage + presents ::Ci::LegacyStage, as: :legacy_stage def latest_ordered_statuses preload_statuses(legacy_stage.statuses.latest_ordered) diff --git a/app/presenters/ci/pipeline_presenter.rb b/app/presenters/ci/pipeline_presenter.rb index 82f00f74692..e0cb899c9d3 100644 --- a/app/presenters/ci/pipeline_presenter.rb +++ b/app/presenters/ci/pipeline_presenter.rb @@ -5,6 +5,9 @@ module Ci include Gitlab::Utils::StrongMemoize include ActionView::Helpers::UrlHelper + delegator_override_with Gitlab::Utils::StrongMemoize # TODO: Remove `Gitlab::Utils::StrongMemoize` inclusion as it's duplicate + delegator_override_with ActionView::Helpers::TagHelper # TODO: Remove `ActionView::Helpers::UrlHelper` inclusion as it overrides `Ci::Pipeline#tag` + # We use a class method here instead of a constant, allowing EE to redefine # the returned `Hash` more easily. def self.failure_reasons @@ -20,8 +23,9 @@ module Ci user_blocked: 'The user who created this pipeline is blocked.' } end - presents :pipeline + presents ::Ci::Pipeline, as: :pipeline + delegator_override :failed_builds def failed_builds return [] unless can?(current_user, :read_build, pipeline) @@ -30,6 +34,7 @@ module Ci end end + delegator_override :failure_reason def failure_reason return unless pipeline.failure_reason? diff --git a/app/presenters/ci/processable_presenter.rb b/app/presenters/ci/processable_presenter.rb index 5a8a6649071..9f3a83a00f3 100644 --- a/app/presenters/ci/processable_presenter.rb +++ b/app/presenters/ci/processable_presenter.rb @@ -2,5 +2,6 @@ module Ci class ProcessablePresenter < CommitStatusPresenter + presents ::Ci::Processable end end diff --git a/app/presenters/ci/runner_presenter.rb b/app/presenters/ci/runner_presenter.rb index 273328afc53..ad889d444f8 100644 --- a/app/presenters/ci/runner_presenter.rb +++ b/app/presenters/ci/runner_presenter.rb @@ -2,11 +2,14 @@ module Ci class RunnerPresenter < Gitlab::View::Presenter::Delegated - presents :runner + presents ::Ci::Runner, as: :runner + delegator_override :locked? def locked? read_attribute(:locked) && project_type? end + + delegator_override :locked alias_method :locked, :locked? end end diff --git a/app/presenters/ci/stage_presenter.rb b/app/presenters/ci/stage_presenter.rb index 21bda86cded..bd5bf08abbc 100644 --- a/app/presenters/ci/stage_presenter.rb +++ b/app/presenters/ci/stage_presenter.rb @@ -2,7 +2,7 @@ module Ci class StagePresenter < Gitlab::View::Presenter::Delegated - presents :stage + presents ::Ci::Stage, as: :stage PRELOADED_RELATIONS = [:pipeline, :metadata, :tags, :job_artifacts_archive, :downstream_pipeline].freeze diff --git a/app/presenters/ci/trigger_presenter.rb b/app/presenters/ci/trigger_presenter.rb index 605c8f328a4..5f0bd4b3a8b 100644 --- a/app/presenters/ci/trigger_presenter.rb +++ b/app/presenters/ci/trigger_presenter.rb @@ -2,12 +2,13 @@ module Ci class TriggerPresenter < Gitlab::View::Presenter::Delegated - presents :trigger + presents ::Ci::Trigger, as: :trigger def has_token_exposed? can?(current_user, :admin_trigger, trigger) end + delegator_override :token def token if has_token_exposed? trigger.token diff --git a/app/presenters/ci/variable_presenter.rb b/app/presenters/ci/variable_presenter.rb index f027f3aa560..ec04dd5e9ff 100644 --- a/app/presenters/ci/variable_presenter.rb +++ b/app/presenters/ci/variable_presenter.rb @@ -2,7 +2,7 @@ module Ci class VariablePresenter < Gitlab::View::Presenter::Delegated - presents :variable + presents ::Ci::Variable, as: :variable def placeholder 'PROJECT_VARIABLE' diff --git a/app/presenters/clusterable_presenter.rb b/app/presenters/clusterable_presenter.rb index 03e26b92922..4b645510b51 100644 --- a/app/presenters/clusterable_presenter.rb +++ b/app/presenters/clusterable_presenter.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true class ClusterablePresenter < Gitlab::View::Presenter::Delegated - presents :clusterable + presents ::Project, ::Group, ::Clusters::Instance, as: :clusterable def self.fabricate(clusterable, **attributes) presenter_class = "#{clusterable.class.name}ClusterablePresenter".constantize diff --git a/app/presenters/clusters/cluster_presenter.rb b/app/presenters/clusters/cluster_presenter.rb index eb4bd8532af..ce060476cfd 100644 --- a/app/presenters/clusters/cluster_presenter.rb +++ b/app/presenters/clusters/cluster_presenter.rb @@ -3,21 +3,10 @@ module Clusters class ClusterPresenter < Gitlab::View::Presenter::Delegated include ::Gitlab::Utils::StrongMemoize - include ActionView::Helpers::SanitizeHelper - include ActionView::Helpers::UrlHelper - include IconsHelper - presents :cluster + delegator_override_with ::Gitlab::Utils::StrongMemoize # TODO: Remove `::Gitlab::Utils::StrongMemoize` inclusion as it's duplicate - # We do not want to show the group path for clusters belonging to the - # clusterable, only for the ancestor clusters. - def item_link(clusterable_presenter, *html_options) - if cluster.group_type? && clusterable != clusterable_presenter.subject - contracted_group_name(cluster.group) + ' / ' + link_to_cluster - else - link_to_cluster(*html_options) - end - end + presents ::Clusters::Cluster, as: :cluster def provider_label if aws? @@ -39,16 +28,6 @@ module Clusters can?(current_user, :read_cluster, cluster) end - def cluster_type_description - if cluster.project_type? - s_("ClusterIntegration|Project cluster") - elsif cluster.group_type? - s_("ClusterIntegration|Group cluster") - elsif cluster.instance_type? - s_("ClusterIntegration|Instance cluster") - end - end - def show_path(params: {}) if cluster.project_type? project_cluster_path(project, cluster, params) @@ -107,7 +86,7 @@ module Clusters private def image_path(path) - ActionController::Base.helpers.image_path(path) + ApplicationController.helpers.image_path(path) end # currently log explorer is only available in the scope of the project @@ -127,20 +106,6 @@ module Clusters cluster.project end end - - def contracted_group_name(group) - sanitize(group.full_name) - .sub(%r{\/.*\/}, "/ #{contracted_icon} /") - .html_safe - end - - def contracted_icon - sprite_icon('ellipsis_h', size: 12, css_class: 'vertical-align-middle') - end - - def link_to_cluster(html_options: {}) - link_to_if(can_read_cluster?, cluster.name, show_path, html_options) - end end end diff --git a/app/presenters/clusters/integration_presenter.rb b/app/presenters/clusters/integration_presenter.rb index 57608be29b1..f7be59f00f3 100644 --- a/app/presenters/clusters/integration_presenter.rb +++ b/app/presenters/clusters/integration_presenter.rb @@ -2,7 +2,7 @@ module Clusters class IntegrationPresenter < Gitlab::View::Presenter::Delegated - presents :integration + presents ::Clusters::Integrations::Prometheus, ::Clusters::Integrations::ElasticStack, as: :integration def application_type integration.class.name.demodulize.underscore diff --git a/app/presenters/commit_presenter.rb b/app/presenters/commit_presenter.rb index c14dcab6000..7df45ca03bb 100644 --- a/app/presenters/commit_presenter.rb +++ b/app/presenters/commit_presenter.rb @@ -3,7 +3,7 @@ class CommitPresenter < Gitlab::View::Presenter::Delegated include GlobalID::Identification - presents :commit + presents ::Commit, as: :commit def status_for(ref) return unless can?(current_user, :read_commit_status, commit.project) diff --git a/app/presenters/commit_status_presenter.rb b/app/presenters/commit_status_presenter.rb index 3c39470b730..7919e501bf0 100644 --- a/app/presenters/commit_status_presenter.rb +++ b/app/presenters/commit_status_presenter.rb @@ -28,19 +28,36 @@ class CommitStatusPresenter < Gitlab::View::Presenter::Delegated ci_quota_exceeded: 'No more CI minutes available', no_matching_runner: 'No matching runner available', trace_size_exceeded: 'The job log size limit was reached', - builds_disabled: 'The CI/CD is disabled for this project' + builds_disabled: 'The CI/CD is disabled for this project', + environment_creation_failure: 'This job could not be executed because it would create an environment with an invalid parameter.' + }.freeze + + TROUBLESHOOTING_DOC = { + environment_creation_failure: { path: 'ci/environments/index', anchor: 'a-deployment-job-failed-with-this-job-could-not-be-executed-because-it-would-create-an-environment-with-an-invalid-parameter-error' } }.freeze private_constant :CALLOUT_FAILURE_MESSAGES - presents :build + presents ::CommitStatus, as: :build def self.callout_failure_messages CALLOUT_FAILURE_MESSAGES end def callout_failure_message - self.class.callout_failure_messages.fetch(failure_reason.to_sym) + message = self.class.callout_failure_messages.fetch(failure_reason.to_sym) + + if doc = TROUBLESHOOTING_DOC[failure_reason.to_sym] + message += " #{help_page_link(doc[:path], doc[:anchor])}" + end + + message + end + + private + + def help_page_link(path, anchor) + ActionController::Base.helpers.link_to('How do I fix it?', help_page_path(path, anchor: anchor)) end end diff --git a/app/presenters/dev_ops_report/metric_presenter.rb b/app/presenters/dev_ops_report/metric_presenter.rb index 4d7ac1cd3ec..55326f8f678 100644 --- a/app/presenters/dev_ops_report/metric_presenter.rb +++ b/app/presenters/dev_ops_report/metric_presenter.rb @@ -2,6 +2,8 @@ module DevOpsReport class MetricPresenter < Gitlab::View::Presenter::Simple + presents ::DevOpsReport::Metric + delegate :created_at, to: :subject def cards diff --git a/app/presenters/environment_presenter.rb b/app/presenters/environment_presenter.rb index 6f67bbe2a5a..6c8da86187c 100644 --- a/app/presenters/environment_presenter.rb +++ b/app/presenters/environment_presenter.rb @@ -3,7 +3,7 @@ class EnvironmentPresenter < Gitlab::View::Presenter::Delegated include ActionView::Helpers::UrlHelper - presents :environment + presents ::Environment, as: :environment def path project_environment_path(project, self) diff --git a/app/presenters/event_presenter.rb b/app/presenters/event_presenter.rb index c37721f7213..4c787b88e20 100644 --- a/app/presenters/event_presenter.rb +++ b/app/presenters/event_presenter.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true class EventPresenter < Gitlab::View::Presenter::Delegated - presents :event + presents ::Event, as: :event def initialize(subject, **attributes) super @@ -10,6 +10,7 @@ class EventPresenter < Gitlab::View::Presenter::Delegated end # Caching `visible_to_user?` method in the presenter beause it might be called multiple times. + delegator_override :visible_to_user? def visible_to_user?(user = nil) @visible_to_user_cache.fetch(user&.id) { super(user) } end diff --git a/app/presenters/gitlab/blame_presenter.rb b/app/presenters/gitlab/blame_presenter.rb index 1f2445b04a1..e9340a42e51 100644 --- a/app/presenters/gitlab/blame_presenter.rb +++ b/app/presenters/gitlab/blame_presenter.rb @@ -12,7 +12,7 @@ module Gitlab include TreeHelper include IconsHelper - presents :blame + presents nil, as: :blame CommitData = Struct.new( :author_avatar, diff --git a/app/presenters/group_clusterable_presenter.rb b/app/presenters/group_clusterable_presenter.rb index 34e7084ab02..c51cd415029 100644 --- a/app/presenters/group_clusterable_presenter.rb +++ b/app/presenters/group_clusterable_presenter.rb @@ -2,7 +2,8 @@ class GroupClusterablePresenter < ClusterablePresenter extend ::Gitlab::Utils::Override - include ActionView::Helpers::UrlHelper + + presents ::Group override :cluster_status_cluster_path def cluster_status_cluster_path(cluster, params = {}) @@ -31,7 +32,7 @@ class GroupClusterablePresenter < ClusterablePresenter override :learn_more_link def learn_more_link - link_to(s_('ClusterIntegration|Learn more about group Kubernetes clusters'), help_page_path('user/group/clusters/index'), target: '_blank', rel: 'noopener noreferrer') + ApplicationController.helpers.link_to(s_('ClusterIntegration|Learn more about group Kubernetes clusters'), help_page_path('user/group/clusters/index'), target: '_blank', rel: 'noopener noreferrer') end def metrics_dashboard_path(cluster) diff --git a/app/presenters/group_member_presenter.rb b/app/presenters/group_member_presenter.rb index 5ab4b51f472..88facc3608d 100644 --- a/app/presenters/group_member_presenter.rb +++ b/app/presenters/group_member_presenter.rb @@ -1,6 +1,8 @@ # frozen_string_literal: true class GroupMemberPresenter < MemberPresenter + presents ::GroupMember + private def admin_member_permission diff --git a/app/presenters/instance_clusterable_presenter.rb b/app/presenters/instance_clusterable_presenter.rb index 56d91f90b2e..f2550eb17e3 100644 --- a/app/presenters/instance_clusterable_presenter.rb +++ b/app/presenters/instance_clusterable_presenter.rb @@ -2,7 +2,8 @@ class InstanceClusterablePresenter < ClusterablePresenter extend ::Gitlab::Utils::Override - include ActionView::Helpers::UrlHelper + + presents ::Clusters::Instance def self.fabricate(clusterable, **attributes) attributes_with_presenter_class = attributes.merge(presenter_class: InstanceClusterablePresenter) @@ -69,7 +70,7 @@ class InstanceClusterablePresenter < ClusterablePresenter override :learn_more_link def learn_more_link - link_to(s_('ClusterIntegration|Learn more about instance Kubernetes clusters'), help_page_path('user/instance/clusters/index'), target: '_blank', rel: 'noopener noreferrer') + ApplicationController.helpers.link_to(s_('ClusterIntegration|Learn more about instance Kubernetes clusters'), help_page_path('user/instance/clusters/index'), target: '_blank', rel: 'noopener noreferrer') end def metrics_dashboard_path(cluster) diff --git a/app/presenters/invitation_presenter.rb b/app/presenters/invitation_presenter.rb index d8c07f327dd..ada8227a477 100644 --- a/app/presenters/invitation_presenter.rb +++ b/app/presenters/invitation_presenter.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true class InvitationPresenter < Gitlab::View::Presenter::Delegated - presents :invitation + presents nil, as: :invitation end diff --git a/app/presenters/issue_presenter.rb b/app/presenters/issue_presenter.rb index b7f4ac0555d..72fe14d224d 100644 --- a/app/presenters/issue_presenter.rb +++ b/app/presenters/issue_presenter.rb @@ -1,12 +1,13 @@ # frozen_string_literal: true class IssuePresenter < Gitlab::View::Presenter::Delegated - presents :issue + presents ::Issue, as: :issue def issue_path url_builder.build(issue, only_path: true) end + delegator_override :subscribed? def subscribed? issue.subscribed?(current_user, issue.project) end diff --git a/app/presenters/label_presenter.rb b/app/presenters/label_presenter.rb index 9e51e6fa4ba..fafade2828f 100644 --- a/app/presenters/label_presenter.rb +++ b/app/presenters/label_presenter.rb @@ -1,9 +1,11 @@ # frozen_string_literal: true class LabelPresenter < Gitlab::View::Presenter::Delegated - presents :label + presents ::Label, as: :label delegate :name, :full_name, to: :label_subject, prefix: :subject + delegator_override :subject # TODO: Fix `Gitlab::View::Presenter::Delegated#subject` not to override `Label#subject`. + def edit_path case label when GroupLabel then edit_group_label_path(label.group, label) diff --git a/app/presenters/member_presenter.rb b/app/presenters/member_presenter.rb index b37a43bf251..67d044dd01c 100644 --- a/app/presenters/member_presenter.rb +++ b/app/presenters/member_presenter.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true class MemberPresenter < Gitlab::View::Presenter::Delegated - presents :member + presents ::Member, as: :member def access_level_roles member.class.access_level_roles diff --git a/app/presenters/members_presenter.rb b/app/presenters/members_presenter.rb index 03ebea36d49..b572cf96235 100644 --- a/app/presenters/members_presenter.rb +++ b/app/presenters/members_presenter.rb @@ -3,7 +3,7 @@ class MembersPresenter < Gitlab::View::Presenter::Delegated include Enumerable - presents :members + presents nil, as: :members def to_ary to_a diff --git a/app/presenters/merge_request_presenter.rb b/app/presenters/merge_request_presenter.rb index fc8a290f5f7..d19d4964524 100644 --- a/app/presenters/merge_request_presenter.rb +++ b/app/presenters/merge_request_presenter.rb @@ -8,9 +8,11 @@ class MergeRequestPresenter < Gitlab::View::Presenter::Delegated include ChecksCollaboration include Gitlab::Utils::StrongMemoize + delegator_override_with Gitlab::Utils::StrongMemoize # TODO: Remove `Gitlab::Utils::StrongMemoize` inclusion as it's duplicate + APPROVALS_WIDGET_BASE_TYPE = 'base' - presents :merge_request + presents ::MergeRequest, as: :merge_request def ci_status if pipeline @@ -183,6 +185,7 @@ class MergeRequestPresenter < Gitlab::View::Presenter::Delegated .can_push_to_branch?(source_branch) end + delegator_override :can_remove_source_branch? def can_remove_source_branch? source_branch_exists? && merge_request.can_remove_source_branch?(current_user) end @@ -202,6 +205,7 @@ class MergeRequestPresenter < Gitlab::View::Presenter::Delegated end end + delegator_override :subscribed? def subscribed? merge_request.subscribed?(current_user, merge_request.target_project) end diff --git a/app/presenters/milestone_presenter.rb b/app/presenters/milestone_presenter.rb index 6bf8203702f..4084c8740f0 100644 --- a/app/presenters/milestone_presenter.rb +++ b/app/presenters/milestone_presenter.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true class MilestonePresenter < Gitlab::View::Presenter::Delegated - presents :milestone + presents ::Milestone, as: :milestone def milestone_path url_builder.build(milestone, only_path: true) diff --git a/app/presenters/pages_domain_presenter.rb b/app/presenters/pages_domain_presenter.rb index 6ef89760bec..0523f702416 100644 --- a/app/presenters/pages_domain_presenter.rb +++ b/app/presenters/pages_domain_presenter.rb @@ -1,7 +1,9 @@ # frozen_string_literal: true class PagesDomainPresenter < Gitlab::View::Presenter::Delegated - presents :pages_domain + presents ::PagesDomain, as: :pages_domain + + delegator_override :subject # TODO: Fix `Gitlab::View::Presenter::Delegated#subject` not to override `PagesDomain#subject`. def needs_verification? Gitlab::CurrentSettings.pages_domain_verification_enabled? && unverified? diff --git a/app/presenters/project_clusterable_presenter.rb b/app/presenters/project_clusterable_presenter.rb index 920304e743e..6c4d1143c0f 100644 --- a/app/presenters/project_clusterable_presenter.rb +++ b/app/presenters/project_clusterable_presenter.rb @@ -2,7 +2,8 @@ class ProjectClusterablePresenter < ClusterablePresenter extend ::Gitlab::Utils::Override - include ActionView::Helpers::UrlHelper + + presents ::Project override :cluster_status_cluster_path def cluster_status_cluster_path(cluster, params = {}) @@ -26,7 +27,7 @@ class ProjectClusterablePresenter < ClusterablePresenter override :learn_more_link def learn_more_link - link_to(s_('ClusterIntegration|Learn more about Kubernetes'), help_page_path('user/project/clusters/index'), target: '_blank', rel: 'noopener noreferrer') + ApplicationController.helpers.link_to(s_('ClusterIntegration|Learn more about Kubernetes'), help_page_path('user/project/clusters/index'), target: '_blank', rel: 'noopener noreferrer') end def metrics_dashboard_path(cluster) diff --git a/app/presenters/project_hook_presenter.rb b/app/presenters/project_hook_presenter.rb index a65c7221b5a..a696e9fd0ec 100644 --- a/app/presenters/project_hook_presenter.rb +++ b/app/presenters/project_hook_presenter.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true class ProjectHookPresenter < Gitlab::View::Presenter::Delegated - presents :project_hook + presents ::ProjectHook, as: :project_hook def logs_details_path(log) project_hook_hook_log_path(project, self, log) diff --git a/app/presenters/project_member_presenter.rb b/app/presenters/project_member_presenter.rb index 17947266ed7..91d3ae96877 100644 --- a/app/presenters/project_member_presenter.rb +++ b/app/presenters/project_member_presenter.rb @@ -1,6 +1,8 @@ # frozen_string_literal: true class ProjectMemberPresenter < MemberPresenter + presents ::ProjectMember + private def admin_member_permission diff --git a/app/presenters/project_presenter.rb b/app/presenters/project_presenter.rb index 066f4786cff..bbd8c715f5c 100644 --- a/app/presenters/project_presenter.rb +++ b/app/presenters/project_presenter.rb @@ -12,7 +12,10 @@ class ProjectPresenter < Gitlab::View::Presenter::Delegated include Gitlab::Utils::StrongMemoize include Gitlab::Experiment::Dsl - presents :project + delegator_override_with GitlabRoutingHelper # TODO: Remove `GitlabRoutingHelper` inclusion as it's duplicate + delegator_override_with Gitlab::Utils::StrongMemoize # TODO: Remove `Gitlab::Utils::StrongMemoize` inclusion as it's duplicate + + presents ::Project, as: :project AnchorData = Struct.new(:is_link, :label, :link, :class_modifier, :icon, :itemprop, :data) MAX_TOPICS_TO_SHOW = 3 diff --git a/app/presenters/projects/import_export/project_export_presenter.rb b/app/presenters/projects/import_export/project_export_presenter.rb index f56760b55df..7b2ffb6d755 100644 --- a/app/presenters/projects/import_export/project_export_presenter.rb +++ b/app/presenters/projects/import_export/project_export_presenter.rb @@ -5,16 +5,24 @@ module Projects class ProjectExportPresenter < Gitlab::View::Presenter::Delegated include ActiveModel::Serializers::JSON - presents :project + presents ::Project, as: :project + # TODO: Remove `ActiveModel::Serializers::JSON` inclusion as it's duplicate + delegator_override_with ActiveModel::Serializers::JSON + delegator_override_with ActiveModel::Naming + delegator_override :include_root_in_json, :include_root_in_json? + + delegator_override :project_members def project_members super + converted_group_members end + delegator_override :description def description self.respond_to?(:override_description) ? override_description : super end + delegator_override :protected_branches def protected_branches project.exported_protected_branches end diff --git a/app/presenters/projects/settings/deploy_keys_presenter.rb b/app/presenters/projects/settings/deploy_keys_presenter.rb index 13290a8e632..e3323b75188 100644 --- a/app/presenters/projects/settings/deploy_keys_presenter.rb +++ b/app/presenters/projects/settings/deploy_keys_presenter.rb @@ -5,7 +5,7 @@ module Projects class DeployKeysPresenter < Gitlab::View::Presenter::Simple include Gitlab::Utils::StrongMemoize - presents :project + presents ::Project, as: :project delegate :size, to: :enabled_keys, prefix: true delegate :size, to: :available_project_keys, prefix: true delegate :size, to: :available_public_keys, prefix: true diff --git a/app/presenters/prometheus_alert_presenter.rb b/app/presenters/prometheus_alert_presenter.rb index 99e24bdcdb9..714329ede71 100644 --- a/app/presenters/prometheus_alert_presenter.rb +++ b/app/presenters/prometheus_alert_presenter.rb @@ -3,7 +3,7 @@ class PrometheusAlertPresenter < Gitlab::View::Presenter::Delegated include ActionView::Helpers::UrlHelper - presents :prometheus_alert + presents ::PrometheusAlert, as: :prometheus_alert def humanized_text operator_text = diff --git a/app/presenters/release_presenter.rb b/app/presenters/release_presenter.rb index ac27e997b41..c919c7f4c60 100644 --- a/app/presenters/release_presenter.rb +++ b/app/presenters/release_presenter.rb @@ -3,8 +3,10 @@ class ReleasePresenter < Gitlab::View::Presenter::Delegated include ActionView::Helpers::UrlHelper - presents :release + presents ::Release, as: :release + # TODO: Remove `delegate` as it's redundant due to SimpleDelegator. + delegator_override :tag, :project delegate :project, :tag, to: :release def commit_path @@ -51,6 +53,7 @@ class ReleasePresenter < Gitlab::View::Presenter::Delegated edit_project_release_url(project, release) end + delegator_override :assets_count def assets_count if can_download_code? release.assets_count @@ -59,6 +62,7 @@ class ReleasePresenter < Gitlab::View::Presenter::Delegated end end + delegator_override :name def name can_download_code? ? release.name : "Release-#{release.id}" end diff --git a/app/presenters/releases/evidence_presenter.rb b/app/presenters/releases/evidence_presenter.rb index a00cbacb7d8..bdc053a303b 100644 --- a/app/presenters/releases/evidence_presenter.rb +++ b/app/presenters/releases/evidence_presenter.rb @@ -4,7 +4,7 @@ module Releases class EvidencePresenter < Gitlab::View::Presenter::Delegated include ActionView::Helpers::UrlHelper - presents :evidence + presents ::Releases::Evidence, as: :evidence def filepath release = evidence.release diff --git a/app/presenters/search_service_presenter.rb b/app/presenters/search_service_presenter.rb index ab43800b9f2..72f967b8beb 100644 --- a/app/presenters/search_service_presenter.rb +++ b/app/presenters/search_service_presenter.rb @@ -3,7 +3,7 @@ class SearchServicePresenter < Gitlab::View::Presenter::Delegated include RendersCommits - presents :search_service + presents ::SearchService, as: :search_service SCOPE_PRELOAD_METHOD = { projects: :with_web_entity_associations, @@ -18,6 +18,7 @@ class SearchServicePresenter < Gitlab::View::Presenter::Delegated SORT_ENABLED_SCOPES = %w(issues merge_requests epics).freeze + delegator_override :search_objects def search_objects @search_objects ||= begin objects = search_service.search_objects(SCOPE_PRELOAD_METHOD[scope.to_sym]) diff --git a/app/presenters/sentry_error_presenter.rb b/app/presenters/sentry_error_presenter.rb index 669bcb68b7c..5862e54dfc7 100644 --- a/app/presenters/sentry_error_presenter.rb +++ b/app/presenters/sentry_error_presenter.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true class SentryErrorPresenter < Gitlab::View::Presenter::Delegated - presents :error + presents nil, as: :error FrequencyStruct = Struct.new(:time, :count, keyword_init: true) diff --git a/app/presenters/service_hook_presenter.rb b/app/presenters/service_hook_presenter.rb index 8f2ba1a905f..91911eb3dff 100644 --- a/app/presenters/service_hook_presenter.rb +++ b/app/presenters/service_hook_presenter.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true class ServiceHookPresenter < Gitlab::View::Presenter::Delegated - presents :service_hook + presents ::ServiceHook, as: :service_hook def logs_details_path(log) project_service_hook_log_path(integration.project, integration, log) diff --git a/app/presenters/snippet_blob_presenter.rb b/app/presenters/snippet_blob_presenter.rb index ab8fc0f905b..4072696eb89 100644 --- a/app/presenters/snippet_blob_presenter.rb +++ b/app/presenters/snippet_blob_presenter.rb @@ -3,6 +3,8 @@ class SnippetBlobPresenter < BlobPresenter include GitlabRoutingHelper + presents ::SnippetBlob + def rich_data return unless blob.rich_viewer diff --git a/app/presenters/snippet_presenter.rb b/app/presenters/snippet_presenter.rb index 695aa266e2c..8badbe7f54a 100644 --- a/app/presenters/snippet_presenter.rb +++ b/app/presenters/snippet_presenter.rb @@ -1,16 +1,18 @@ # frozen_string_literal: true class SnippetPresenter < Gitlab::View::Presenter::Delegated - presents :snippet + presents ::Snippet, as: :snippet def raw_url url_builder.build(snippet, raw: true) end + delegator_override :ssh_url_to_repo def ssh_url_to_repo snippet.ssh_url_to_repo if snippet.repository_exists? end + delegator_override :http_url_to_repo def http_url_to_repo snippet.http_url_to_repo if snippet.repository_exists? end @@ -31,6 +33,7 @@ class SnippetPresenter < Gitlab::View::Presenter::Delegated snippet.submittable_as_spam_by?(current_user) end + delegator_override :blob def blob return snippet.blob if snippet.empty_repo? diff --git a/app/presenters/terraform/modules_presenter.rb b/app/presenters/terraform/modules_presenter.rb index 608f69e2019..9e9c6a5cd2b 100644 --- a/app/presenters/terraform/modules_presenter.rb +++ b/app/presenters/terraform/modules_presenter.rb @@ -4,7 +4,7 @@ module Terraform class ModulesPresenter < Gitlab::View::Presenter::Simple attr_accessor :packages, :system - presents :modules + presents nil, as: :modules def initialize(packages, system) @packages = packages diff --git a/app/presenters/todo_presenter.rb b/app/presenters/todo_presenter.rb index 291be7848e2..cb8d37be22d 100644 --- a/app/presenters/todo_presenter.rb +++ b/app/presenters/todo_presenter.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true class TodoPresenter < Gitlab::View::Presenter::Delegated - presents :todo + presents ::Todo, as: :todo end diff --git a/app/presenters/tree_entry_presenter.rb b/app/presenters/tree_entry_presenter.rb index 216b3b0d4c9..0b313d81360 100644 --- a/app/presenters/tree_entry_presenter.rb +++ b/app/presenters/tree_entry_presenter.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true class TreeEntryPresenter < Gitlab::View::Presenter::Delegated - presents :tree + presents nil, as: :tree def web_url Gitlab::Routing.url_helpers.project_tree_url(tree.repository.project, File.join(tree.commit_id, tree.path)) diff --git a/app/presenters/user_presenter.rb b/app/presenters/user_presenter.rb index 7cd94082bac..5a99f10b6e7 100644 --- a/app/presenters/user_presenter.rb +++ b/app/presenters/user_presenter.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true class UserPresenter < Gitlab::View::Presenter::Delegated - presents :user + presents ::User, as: :user def group_memberships should_be_private? ? GroupMember.none : user.group_members diff --git a/app/presenters/web_hook_log_presenter.rb b/app/presenters/web_hook_log_presenter.rb index fca03ddb5d7..a5166589073 100644 --- a/app/presenters/web_hook_log_presenter.rb +++ b/app/presenters/web_hook_log_presenter.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true class WebHookLogPresenter < Gitlab::View::Presenter::Delegated - presents :web_hook_log + presents ::WebHookLog, as: :web_hook_log def details_path web_hook.present.logs_details_path(self) |