Commit e0e3f1c2 authored by Oswaldo Ferreira's avatar Oswaldo Ferreira

Move button list logic to project presenter

parent ccc858a5
......@@ -34,7 +34,7 @@ module ApplicationHelper
def project_icon(project_id, options = {})
project =
if project_id.is_a?(Project)
if project_id.is_a?(Project) || project_id.is_a?(ProjectPresenter)
project_id
else
Project.find_by_full_path(project_id)
......
......@@ -10,12 +10,6 @@ module BranchesHelper
project_branches_path(@project, @id, options)
end
def can_push_branch?(project, branch_name)
return false unless project.repository.branch_exists?(branch_name)
::Gitlab::UserAccess.new(current_user, project: project).can_push_to_branch?(branch_name)
end
def project_branches
options_for_select(@project.repository.branch_names, @project.default_branch)
end
......
......@@ -48,30 +48,4 @@ module PreferencesHelper
def user_color_scheme
Gitlab::ColorSchemes.for_user(current_user).css_class
end
def default_project_view
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 @project.feature_available?(:issues, current_user)
"projects/issues/issues"
else
"customize_workflow"
end
end
def anonymous_project_view
if !@project.empty_repo? && can?(current_user, :download_code, @project)
'files'
else
'activity'
end
end
end
This diff is collapsed.
......@@ -55,7 +55,7 @@ module TreeHelper
def tree_edit_branch(project = @project, ref = @ref)
return unless can_edit_tree?(project, ref)
if can_push_branch?(project, ref)
if project.user_can_push_to_branch?(current_user, ref)
ref
else
project = tree_edit_project(project)
......
......@@ -15,6 +15,7 @@ class Project < ActiveRecord::Base
include ValidAttribute
include ProjectFeaturesCompatibility
include SelectForProjectAuthorization
include Presentable
include Routable
include GroupDescendant
include Gitlab::SQL::Pattern
......@@ -1015,6 +1016,12 @@ class Project < ActiveRecord::Base
!ProtectedBranch.default_branch_protected? || team.max_member_access(user.id) > Gitlab::Access::DEVELOPER
end
def user_can_push_to_branch?(user, branch_name)
return false unless repository.branch_exists?(branch_name)
::Gitlab::UserAccess.new(user, project: self).can_push_to_branch?(branch_name)
end
def forked?
return true if fork_network && fork_network.root_project != self
......
class ProjectPresenter < Gitlab::View::Presenter::Delegated
include ActionView::Helpers::NumberHelper
include ActionView::Helpers::UrlHelper
include GitlabRoutingHelper
include StorageHelper
include TreeHelper
presents :project
def project_stat_anchor_items(show_auto_devops_callout:)
[
files_anchor_data,
commits_anchor_data,
branches_anchor_data,
tags_anchor_data,
readme_anchor_data,
changelog_anchor_data,
license_anchor_data,
contribution_guide_anchor_data,
gitlab_ci_anchor_data,
autodevops_anchor_data(show_auto_devops_callout: show_auto_devops_callout),
kubernetes_cluster_anchor_data
].compact.reject { |i| !i[:enabled] }
end
def project_stat_button_items(show_auto_devops_callout:)
[
changelog_anchor_data,
license_anchor_data,
contribution_guide_anchor_data,
autodevops_anchor_data(show_auto_devops_callout: show_auto_devops_callout),
kubernetes_cluster_anchor_data,
gitlab_ci_anchor_data,
koding_anchor_data
].compact.reject { |i| i[:enabled] }
end
def empty_project_stat_anchor_items
[
autodevops_anchor_data,
kubernetes_cluster_anchor_data
].compact.reject { |i| !i[:enabled] }
end
def empty_project_stat_button_items
[
new_file_anchor_data,
readme_anchor_data,
license_anchor_data,
autodevops_anchor_data,
kubernetes_cluster_anchor_data
].compact.reject { |i| i[:enabled] }
end
def default_project_view
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
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 add_koding_stack_path
project_new_blob_path(
project,
default_branch || 'master',
file_name: '.koding.yml',
commit_message: "Add Koding stack script",
content: <<-CONTENT.strip_heredoc
provider:
aws:
access_key: '${var.aws_access_key}'
secret_key: '${var.aws_secret_key}'
resource:
aws_instance:
#{project.path}-vm:
instance_type: t2.nano
user_data: |-
# Created by GitLab UI for :>
echo _KD_NOTIFY_@Installing Base packages...@
apt-get update -y
apt-get install git -y
echo _KD_NOTIFY_@Cloning #{project.name}...@
export KODING_USER=${var.koding_user_username}
export REPO_URL=#{root_url}${var.koding_queryString_repo}.git
export BRANCH=${var.koding_queryString_branch}
sudo -i -u $KODING_USER git clone $REPO_URL -b $BRANCH
echo _KD_NOTIFY_@#{project.name} cloned.@
CONTENT
)
end
def license_short_name
license = repository.license
license&.nickname || license&.name || 'LICENSE'
end
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
def can_current_user_push_code?
if empty_repo?
can?(current_user, :push_code, project)
else
user_can_push_to_branch?(current_user, default_branch)
end
end
def files_anchor_data
{
enabled: true,
label: _('Files (%{human_size})') % { human_size: storage_counter(statistics.total_repository_size) },
link: project_tree_path(project)
}
end
def commits_anchor_data
{
enabled: true,
label: n_('Commit (%{commit_count})', 'Commits (%{commit_count})', statistics.commit_count) % { commit_count: number_with_delimiter(statistics.commit_count) },
link: project_commits_path(project, repository.root_ref)
}
end
def branches_anchor_data
{
enabled: true,
label: n_('Branch (%{branch_count})', 'Branches (%{branch_count})', repository.branch_count) % { branch_count: number_with_delimiter(repository.branch_count) },
link: project_branches_path(project)
}
end
def tags_anchor_data
{
enabled: true,
label: n_('Tag (%{tag_count})', 'Tags (%{tag_count})', repository.tag_count) % { tag_count: number_with_delimiter(repository.tag_count) },
link: project_tags_path(project)
}
end
def new_file_anchor_data
if current_user && can_current_user_push_code?
{
enabled: false,
label: _('New file'),
link: project_new_blob_path(project, default_branch || 'master'),
class_modifier: 'new'
}
end
end
def readme_anchor_data
if current_user && can_current_user_push_code? && repository.readme.blank?
{
enabled: false,
label: _('Add Readme'),
link: add_readme_path
}
elsif repository.readme.present?
{
enabled: true,
label: _('Readme'),
link: default_project_view != 'readme' ? readme_path : '#readme'
}
end
end
def changelog_anchor_data
if current_user && can_current_user_push_code? && repository.changelog.blank?
{
enabled: false,
label: _('Add Changelog'),
link: add_special_file_path(file_name: 'CHANGELOG')
}
elsif repository.changelog.present?
{
enabled: true,
label: _('Changelog'),
link: changelog_path
}
end
end
def license_anchor_data
if current_user && can_current_user_push_code? && repository.license_blob.blank?
{
enabled: false,
label: _('Add License'),
link: add_license_path
}
elsif repository.license_blob.present?
{
enabled: true,
label: license_short_name,
link: license_path
}
end
end
def contribution_guide_anchor_data
if current_user && can_current_user_push_code? && repository.contribution_guide.blank?
{
enabled: false,
label: _('Add Contribution guide'),
link: add_special_file_path(file_name: 'CONTRIBUTING.md', commit_message: 'Add contribution guide')
}
elsif repository.contribution_guide.present?
{
enabled: true,
label: _('Contribution guide'),
link: contribution_guide_path
}
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
{
enabled: auto_devops_enabled?,
label: auto_devops_enabled? ? _('Auto DevOps enabled') : _('Enable Auto DevOps'),
link: project_settings_ci_cd_path(project, anchor: 'js-general-pipeline-settings')
}
elsif auto_devops_enabled?
{
enabled: true,
label: _('Auto DevOps enabled'),
link: nil
}
end
end
def kubernetes_cluster_anchor_data
if current_user && can?(current_user, :create_cluster, project)
cluster_link = clusters.size == 1 ? project_cluster_path(project, clusters.first) : project_clusters_path(project)
if clusters.empty?
cluster_link = new_project_cluster_path(project)
end
{
enabled: !clusters.empty?,
label: clusters.empty? ? _('Add Kubernetes cluster') : n_('Kubernetes cluster', 'Kubernetes clusters', clusters.size),
link: cluster_link
}
end
end
def gitlab_ci_anchor_data
if current_user && can_current_user_push_code? && repository.gitlab_ci_yml.blank? && !auto_devops_enabled?
{
enabled: false,
label: _('Set up CI/CD'),
link: add_ci_yml_path
}
elsif repository.gitlab_ci_yml.present?
{
enabled: true,
label: _('CI/CD configuration'),
link: ci_configuration_path
}
end
end
def koding_anchor_data
if current_user && can_current_user_push_code? && koding_enabled? && repository.koding_yml.blank?
{
enabled: false,
label: _('Set up Koding'),
link: add_koding_stack_path
}
end
end
def koding_enabled?
Gitlab::CurrentSettings.koding_enabled?
end
end
......@@ -20,4 +20,4 @@
distributed with computer software, forming part of its documentation.
GitLab will render it here instead of this message.
%p
= link_to "Add Readme", add_special_file_path(@project, file_name: 'README.md'), class: 'btn btn-new'
= link_to "Add Readme", @project.add_readme_path, class: 'btn btn-new'
- if koding_enabled? && current_user && @repository.koding_yml && can_push_branch?(@project, @project.default_branch)
- if koding_enabled? && current_user && @repository.koding_yml && @project.user_can_push_to_branch?(current_user, @project.default_branch)
= link_to koding_project_url(@project), class: 'btn project-action-button inline', target: '_blank', rel: 'noopener noreferrer' do
_('Run in IDE (Koding)')
- @no_container = true
- breadcrumb_title "Details"
- @project = @project.present(current_user: current_user)
= render partial: 'flash_messages', locals: { project: @project }
......@@ -32,8 +33,8 @@
.prepend-top-20
%nav.project-stats{ class: container_class }
= render 'stat_anchor_list', anchors: empty_project_stat_anchor_items(@project)
= render 'stat_anchor_list', anchors: empty_project_stat_button_items(@project)
= render 'stat_anchor_list', anchors: @project.empty_project_stat_anchor_items
= render 'stat_anchor_list', anchors: @project.empty_project_stat_button_items
- if can?(current_user, :push_code, @project)
%div{ class: [container_class, ("limit-container-width-sm" unless fluid_layout)] }
......
- project_stat_items_args = { show_auto_devops_callout: show_auto_devops_callout?(@project) }
- @no_container = true
- breadcrumb_title "Details"
- @content_class = "limit-container-width" unless fluid_layout
- @project = @project.present(current_user: current_user)
= content_for :meta_tags do
= auto_discovery_link_tag(:atom, project_path(@project, rss_url_options), title: "#{@project.name} activity")
......@@ -14,8 +16,8 @@
- if can?(current_user, :download_code, @project)
%nav.project-stats{ class: container_class }
= render 'stat_anchor_list', anchors: project_stat_anchor_items(@project)
= render 'stat_anchor_list', anchors: project_stat_button_items(@project)
= render 'stat_anchor_list', anchors: @project.project_stat_anchor_items(project_stat_items_args)
= render 'stat_anchor_list', anchors: @project.project_stat_button_items(project_stat_items_args)
%div{ class: [container_class, ("limit-container-width" unless fluid_layout)] }
......@@ -25,7 +27,7 @@
= icon("exclamation-triangle fw")
#{ _('Archived project! Repository is read-only') }
- view_path = default_project_view
- view_path = @project.default_project_view
- if show_auto_devops_callout?(@project)
= render 'shared/auto_devops_callout'
......
......@@ -69,7 +69,7 @@
- else
= form.submit 'Save changes', class: 'btn btn-save'
- if !issuable.persisted? && !issuable.project.empty_repo? && (guide_url = contribution_guide_path(issuable.project))
- if !issuable.persisted? && !issuable.project.empty_repo? && (guide_url = issuable.project.present.contribution_guide_path)
.inline.prepend-top-10
Please review the
%strong= link_to('contribution guidelines', guide_url)
......
require 'spec_helper'
describe 'Project show page', :feature do
include ProjectsHelper
context 'when project pending delete' do
let(:project) { create(:project, :empty_repo, pending_delete: true) }
......@@ -29,6 +27,7 @@ describe 'Project show page', :feature do
describe 'empty project' do
let(:project) { create(:project, :public, :empty_repo) }
let(:presenter) { project.present(current_user: user) }
describe 'as a normal user' do
before do
......@@ -71,13 +70,13 @@ describe 'Project show page', :feature do
it '"Add Readme" button linked to new file populated for a readme' do
page.within('.project-stats') do
expect(page).to have_link('Add Readme', href: add_special_file_path(project, file_name: 'README.md'))
expect(page).to have_link('Add Readme', href: presenter.add_readme_path)
end
end
it '"Add License" button linked to new file populated for a license' do
page.within('.project-stats') do
expect(page).to have_link('Add License', href: add_special_file_path(project, file_name: 'LICENSE'))
expect(page).to have_link('Add License', href: presenter.add_license_path)
end
end
......@@ -121,6 +120,7 @@ describe 'Project show page', :feature do
describe 'populated project' do
let(:project) { create(:project, :public, :repository) }
let(:presenter) { project.present(current_user: user) }
describe 'as a normal user' do
before do
......@@ -192,7 +192,7 @@ describe 'Project show page', :feature do
expect(project.repository.gitlab_ci_yml).to be_nil
page.within('.project-stats') do
expect(page).to have_link('Set up CI/CD', href: add_special_file_path(project, file_name: '.gitlab-ci.yml'))
expect(page).to have_link('Set up CI/CD', href: presenter.add_ci_yml_path)
end
end
......@@ -327,7 +327,7 @@ describe 'Project show page', :feature do
visit project_path(project)
page.within('.project-stats') do
expect(page).to have_link('Set up Koding', href: add_koding_stack_path(project))
expect(page).to have_link('Set up Koding', href: presenter.add_koding_stack_path)
end
end
end
......
......@@ -264,32 +264,6 @@ describe ProjectsHelper do
end
end
describe '#license_short_name' do
let(:project) { create(:project) }
context 'when project.repository has a license_key' do
it 'returns the nickname of the license if present' do
allow(project.repository).to receive(:license_key).and_return('agpl-3.0')
expect(helper.license_short_name(project)).to eq('GNU AGPLv3')
end
it 'returns the name of the license if nickname is not present' do
allow(project.repository).to receive(:license_key).and_return('mit')
expect(helper.license_short_name(project)).to eq('MIT License')
end
end
context 'when project.repository has no license_key but a license_blob' do
it 'returns LICENSE' do
allow(project.repository).to receive(:license_key).and_return(nil)
expect(helper.license_short_name(project)).to eq('LICENSE')
end
end
end
describe '#sanitized_import_error' do
let(:project) { create(:project, :repository) }
......
require 'spec_helper'
describe ProjectPresenter do
let(:user) { create(:user) }
let(:project) { create(:project) }
let(:presenter) { described_class.new(project, current_user: user) }
describe '#license_short_name' do
context 'when project.repository has a license_key' do
it 'returns the nickname of the license if present' do
allow(project.repository).to receive(:license_key).and_return('agpl-3.0')
expect(presenter.license_short_name).to eq('GNU AGPLv3')
end
it 'returns the name of the license if nickname is not present' do
allow(project.repository).to receive(:license_key).and_return('mit')
expect(presenter.license_short_name).to eq('MIT License')
end
end
context 'when project.repository has no license_key but a license_blob' do
it 'returns LICENSE' do
allow(project.repository).to receive(:license_key).and_return(nil)
expect(presenter.license_short_name).to eq('LICENSE')
end
end
end
end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment