project_presenter.rb 9.24 KB
Newer Older
1 2
# frozen_string_literal: true

3 4 5 6 7 8
class ProjectPresenter < Gitlab::View::Presenter::Delegated
  include ActionView::Helpers::NumberHelper
  include ActionView::Helpers::UrlHelper
  include GitlabRoutingHelper
  include StorageHelper
  include TreeHelper
9
  include ChecksCollaboration
10
  include Gitlab::Utils::StrongMemoize
11 12 13

  presents :project

14 15 16
  AnchorData = Struct.new(:enabled, :label, :link, :class_modifier)
  MAX_TAGS_TO_SHOW = 3

Oswaldo Ferreira's avatar
Oswaldo Ferreira committed
17
  def statistics_anchors(show_auto_devops_callout:)
18
    [
19 20 21
      readme_anchor_data,
      changelog_anchor_data,
      contribution_guide_anchor_data,
22 23 24 25 26 27 28
      files_anchor_data,
      commits_anchor_data,
      branches_anchor_data,
      tags_anchor_data,
      gitlab_ci_anchor_data,
      autodevops_anchor_data(show_auto_devops_callout: show_auto_devops_callout),
      kubernetes_cluster_anchor_data
29
    ].compact.select { |item| item.enabled }
30 31
  end

Oswaldo Ferreira's avatar
Oswaldo Ferreira committed
32
  def statistics_buttons(show_auto_devops_callout:)
33
    [
34
      readme_anchor_data,
35 36 37 38
      changelog_anchor_data,
      contribution_guide_anchor_data,
      autodevops_anchor_data(show_auto_devops_callout: show_auto_devops_callout),
      kubernetes_cluster_anchor_data,
39
      gitlab_ci_anchor_data
40
    ].compact.reject { |item| item.enabled }
41 42
  end

Oswaldo Ferreira's avatar
Oswaldo Ferreira committed
43
  def empty_repo_statistics_anchors
44
    [
45 46 47 48
      files_anchor_data,
      commits_anchor_data,
      branches_anchor_data,
      tags_anchor_data,
49 50
      autodevops_anchor_data,
      kubernetes_cluster_anchor_data
51
    ].compact.select { |item| item.enabled }
52 53
  end

Oswaldo Ferreira's avatar
Oswaldo Ferreira committed
54
  def empty_repo_statistics_buttons
55 56 57 58 59
    [
      new_file_anchor_data,
      readme_anchor_data,
      autodevops_anchor_data,
      kubernetes_cluster_anchor_data
60
    ].compact.reject { |item| item.enabled }
61 62
  end

63
  def default_view
64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110
    return anonymous_project_view unless current_user

    user_view = current_user.project_view

    if can?(current_user, :download_code, project)
      user_view
    elsif user_view == "activity"
      "activity"
    elsif can?(current_user, :read_wiki, project)
      "wiki"
    elsif feature_available?(:issues, current_user)
      "projects/issues/issues"
    else
      "customize_workflow"
    end
  end

  def readme_path
    filename_path(:readme)
  end

  def changelog_path
    filename_path(:changelog)
  end

  def license_path
    filename_path(:license_blob)
  end

  def ci_configuration_path
    filename_path(:gitlab_ci_yml)
  end

  def contribution_guide_path
    if project && contribution_guide = repository.contribution_guide
      project_blob_path(
        project,
        tree_join(project.default_branch,
                  contribution_guide.name)
      )
    end
  end

  def add_license_path
    add_special_file_path(file_name: 'LICENSE')
  end

111 112 113 114 115 116 117 118
  def add_changelog_path
    add_special_file_path(file_name: 'CHANGELOG')
  end

  def add_contribution_guide_path
    add_special_file_path(file_name: 'CONTRIBUTING.md', commit_message: 'Add contribution guide')
  end

119 120 121 122 123 124 125 126 127 128 129 130 131 132
  def add_ci_yml_path
    add_special_file_path(file_name: '.gitlab-ci.yml')
  end

  def add_readme_path
    add_special_file_path(file_name: 'README.md')
  end

  def license_short_name
    license = repository.license
    license&.nickname || license&.name || 'LICENSE'
  end

  def can_current_user_push_code?
133 134 135 136
    strong_memoize(:can_current_user_push_code) do
      if empty_repo?
        can?(current_user, :push_code, project)
      else
137
        can_current_user_push_to_branch?(default_branch)
138
      end
139 140 141
    end
  end

142
  def can_current_user_push_to_branch?(branch)
143 144
    user_access(project).can_push_to_branch?(branch)
  end
145

146 147
  def can_current_user_push_to_default_branch?
    can_current_user_push_to_branch?(default_branch)
148 149
  end

150
  def files_anchor_data
151 152 153
    AnchorData.new(true,
                   _('Files (%{human_size})') % { human_size: storage_counter(statistics.total_repository_size) },
                   empty_repo? ? nil : project_tree_path(project))
154 155 156
  end

  def commits_anchor_data
157 158 159
    AnchorData.new(true,
                   n_('Commit (%{commit_count})', 'Commits (%{commit_count})', statistics.commit_count) % { commit_count: number_with_delimiter(statistics.commit_count) },
                   empty_repo? ? nil : project_commits_path(project, repository.root_ref))
160 161 162
  end

  def branches_anchor_data
163 164 165
    AnchorData.new(true,
                   n_('Branch (%{branch_count})', 'Branches (%{branch_count})', repository.branch_count) % { branch_count: number_with_delimiter(repository.branch_count) },
                   empty_repo? ? nil : project_branches_path(project))
166 167 168
  end

  def tags_anchor_data
169 170 171
    AnchorData.new(true,
                   n_('Tag (%{tag_count})', 'Tags (%{tag_count})', repository.tag_count) % { tag_count: number_with_delimiter(repository.tag_count) },
                   empty_repo? ? nil : project_tags_path(project))
172 173 174
  end

  def new_file_anchor_data
175
    if current_user && can_current_user_push_to_default_branch?
176 177 178
      AnchorData.new(false,
                     _('New file'),
                     project_new_blob_path(project, default_branch || 'master'),
179
                     'success')
180 181 182 183
    end
  end

  def readme_anchor_data
184
    if current_user && can_current_user_push_to_default_branch? && repository.readme.nil?
185 186 187
      AnchorData.new(false,
                     _('Add Readme'),
                     add_readme_path)
188
    elsif repository.readme
189 190 191
      AnchorData.new(true,
                     _('Readme'),
                     default_view != 'readme' ? readme_path : '#readme')
192 193 194 195
    end
  end

  def changelog_anchor_data
196
    if current_user && can_current_user_push_to_default_branch? && repository.changelog.blank?
197 198 199
      AnchorData.new(false,
                     _('Add Changelog'),
                     add_changelog_path)
200
    elsif repository.changelog.present?
201 202 203
      AnchorData.new(true,
                     _('Changelog'),
                     changelog_path)
204 205 206 207
    end
  end

  def license_anchor_data
208 209 210 211 212 213 214 215 216 217 218 219 220 221
    if repository.license_blob.present?
      AnchorData.new(true,
                     license_short_name,
                     license_path)
    else
      if current_user && can_current_user_push_to_default_branch?
        AnchorData.new(false,
                       _('Add license'),
                       add_license_path)
      else
        AnchorData.new(false,
                       _('No license. All rights reserved'),
                       nil)
      end
222 223 224 225
    end
  end

  def contribution_guide_anchor_data
226
    if current_user && can_current_user_push_to_default_branch? && repository.contribution_guide.blank?
227 228 229
      AnchorData.new(false,
                     _('Add Contribution guide'),
                     add_contribution_guide_path)
230
    elsif repository.contribution_guide.present?
231 232 233
      AnchorData.new(true,
                     _('Contribution guide'),
                     contribution_guide_path)
234 235 236 237 238
    end
  end

  def autodevops_anchor_data(show_auto_devops_callout: false)
    if current_user && can?(current_user, :admin_pipeline, project) && repository.gitlab_ci_yml.blank? && !show_auto_devops_callout
239 240 241
      AnchorData.new(auto_devops_enabled?,
                     auto_devops_enabled? ? _('Auto DevOps enabled') : _('Enable Auto DevOps'),
                     project_settings_ci_cd_path(project, anchor: 'autodevops-settings'))
242
    elsif auto_devops_enabled?
243 244 245
      AnchorData.new(true,
                     _('Auto DevOps enabled'),
                     nil)
246 247 248 249 250
    end
  end

  def kubernetes_cluster_anchor_data
    if current_user && can?(current_user, :create_cluster, project)
251
      cluster_link = clusters.count == 1 ? project_cluster_path(project, clusters.first) : project_clusters_path(project)
252 253 254 255 256

      if clusters.empty?
        cluster_link = new_project_cluster_path(project)
      end

257 258 259
      AnchorData.new(!clusters.empty?,
                     clusters.empty? ? _('Add Kubernetes cluster') : _('Kubernetes configured'),
                     cluster_link)
260 261 262 263 264
    end
  end

  def gitlab_ci_anchor_data
    if current_user && can_current_user_push_code? && repository.gitlab_ci_yml.blank? && !auto_devops_enabled?
265 266 267
      AnchorData.new(false,
                     _('Set up CI/CD'),
                     add_ci_yml_path)
268
    elsif repository.gitlab_ci_yml.present?
269 270 271
      AnchorData.new(true,
                     _('CI/CD configuration'),
                     ci_configuration_path)
272 273 274
    end
  end

275
  def tags_to_show
276
    project.tag_list.take(MAX_TAGS_TO_SHOW) # rubocop: disable CodeReuse/ActiveRecord
277 278 279 280 281 282 283 284 285 286 287 288 289 290
  end

  def count_of_extra_tags_not_shown
    if project.tag_list.count > MAX_TAGS_TO_SHOW
      project.tag_list.count - MAX_TAGS_TO_SHOW
    else
      0
    end
  end

  def has_extra_tags?
    count_of_extra_tags_not_shown > 0
  end

291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319
  private

  def filename_path(filename)
    if blob = repository.public_send(filename) # rubocop:disable GitlabSecurity/PublicSend
      project_blob_path(
        project,
        tree_join(default_branch, blob.name)
      )
    end
  end

  def anonymous_project_view
    if !project.empty_repo? && can?(current_user, :download_code, project)
      'files'
    else
      'activity'
    end
  end

  def add_special_file_path(file_name:, commit_message: nil, branch_name: nil)
    commit_message ||= s_("CommitMessage|Add %{file_name}") % { file_name: file_name }
    project_new_blob_path(
      project,
      project.default_branch || 'master',
      file_name:      file_name,
      commit_message: commit_message,
      branch_name:    branch_name
    )
  end
320
end