Commit c49d19a5 authored by Filipa Lacerda's avatar Filipa Lacerda

Merge branch 'fork-btn-enabled-user-groups' into 'master'

Fix fork button being disabled for users who can fork to group

Closes #38462

See merge request gitlab-org/gitlab-ce!14551
parents 0e82f6d3 93aa6d04
...@@ -14,7 +14,6 @@ ...@@ -14,7 +14,6 @@
/* global NotificationsDropdown */ /* global NotificationsDropdown */
/* global GroupAvatar */ /* global GroupAvatar */
/* global LineHighlighter */ /* global LineHighlighter */
/* global ProjectFork */
/* global BuildArtifacts */ /* global BuildArtifacts */
/* global GroupsSelect */ /* global GroupsSelect */
/* global Search */ /* global Search */
...@@ -476,7 +475,9 @@ import { ajaxGet, convertPermissionToBoolean } from './lib/utils/common_utils'; ...@@ -476,7 +475,9 @@ import { ajaxGet, convertPermissionToBoolean } from './lib/utils/common_utils';
shortcut_handler = true; shortcut_handler = true;
break; break;
case 'projects:forks:new': case 'projects:forks:new':
new ProjectFork(); import(/* webpackChunkName: 'project_fork' */ './project_fork')
.then(fork => fork.default())
.catch(() => {});
break; break;
case 'projects:artifacts:browse': case 'projects:artifacts:browse':
new ShortcutsNavigation(); new ShortcutsNavigation();
......
...@@ -124,7 +124,6 @@ import './preview_markdown'; ...@@ -124,7 +124,6 @@ import './preview_markdown';
import './project'; import './project';
import './project_avatar'; import './project_avatar';
import './project_find_file'; import './project_find_file';
import './project_fork';
import './project_import'; import './project_import';
import './project_label_subscription'; import './project_label_subscription';
import './project_new'; import './project_new';
......
/* eslint-disable func-names, space-before-function-paren, wrap-iife, prefer-arrow-callback, max-len */ export default () => {
(function() { $('.fork-thumbnail a').on('click', function forkThumbnailClicked() {
this.ProjectFork = (function() { if ($(this).hasClass('disabled')) return false;
function ProjectFork() {
$('.fork-thumbnail a').on('click', function() {
$('.fork-namespaces').hide(); $('.fork-namespaces').hide();
return $('.save-project-loader').show(); return $('.save-project-loader').show();
}); });
} };
return ProjectFork;
})();
}).call(window);
...@@ -516,7 +516,7 @@ a.deploy-project-label { ...@@ -516,7 +516,7 @@ a.deploy-project-label {
text-align: center; text-align: center;
width: 169px; width: 169px;
&:hover, &:hover:not(.disabled),
&.forked { &.forked {
background-color: $row-hover; background-color: $row-hover;
border-color: $row-hover-border; border-color: $row-hover-border;
...@@ -543,6 +543,15 @@ a.deploy-project-label { ...@@ -543,6 +543,15 @@ a.deploy-project-label {
padding-top: $gl-padding; padding-top: $gl-padding;
color: $gl-text-color; color: $gl-text-color;
&.disabled {
opacity: .3;
cursor: not-allowed;
&:hover {
text-decoration: none;
}
}
.caption { .caption {
min-height: 30px; min-height: 30px;
padding: $gl-padding 0; padding: $gl-padding 0;
......
...@@ -11,6 +11,8 @@ class GlobalPolicy < BasePolicy ...@@ -11,6 +11,8 @@ class GlobalPolicy < BasePolicy
with_options scope: :user, score: 0 with_options scope: :user, score: 0
condition(:access_locked) { @user.access_locked? } condition(:access_locked) { @user.access_locked? }
condition(:can_create_fork, scope: :user) { @user.manageable_namespaces.any? { |namespace| @user.can?(:create_projects, namespace) } }
rule { anonymous }.policy do rule { anonymous }.policy do
prevent :log_in prevent :log_in
prevent :access_api prevent :access_api
...@@ -40,6 +42,10 @@ class GlobalPolicy < BasePolicy ...@@ -40,6 +42,10 @@ class GlobalPolicy < BasePolicy
enable :create_group enable :create_group
end end
rule { can_create_fork }.policy do
enable :create_fork
end
rule { access_locked }.policy do rule { access_locked }.policy do
prevent :log_in prevent :log_in
end end
......
class NamespacePolicy < BasePolicy class NamespacePolicy < BasePolicy
rule { anonymous }.prevent_all rule { anonymous }.prevent_all
condition(:personal_project, scope: :subject) { @subject.kind == 'user' }
condition(:can_create_personal_project, scope: :user) { @user.can_create_project? }
condition(:owner) { @subject.owner == @user } condition(:owner) { @subject.owner == @user }
rule { owner | admin }.policy do rule { owner | admin }.policy do
enable :create_projects enable :create_projects
enable :admin_namespace enable :admin_namespace
end end
rule { personal_project & ~can_create_personal_project }.prevent :create_projects
end end
...@@ -4,12 +4,11 @@ ...@@ -4,12 +4,11 @@
= link_to namespace_project_path(current_user, current_user.fork_of(@project)), title: _('Go to your fork'), class: 'btn has-tooltip' do = link_to namespace_project_path(current_user, current_user.fork_of(@project)), title: _('Go to your fork'), class: 'btn has-tooltip' do
= custom_icon('icon_fork') = custom_icon('icon_fork')
%span= s_('GoToYourFork|Fork') %span= s_('GoToYourFork|Fork')
- elsif !current_user.can_create_project?
= link_to new_project_fork_path(@project), title: _('You have reached your project limit'), class: 'btn has-tooltip disabled' do
= custom_icon('icon_fork')
%span= s_('CreateNewFork|Fork')
- else - else
= link_to new_project_fork_path(@project), class: 'btn' do - can_create_fork = current_user.can?(:create_fork)
= link_to new_project_fork_path(@project),
class: "btn btn-default #{'has-tooltip disabled' unless can_create_fork}",
title: (_('You have reached your project limit') unless can_create_fork) do
= custom_icon('icon_fork') = custom_icon('icon_fork')
%span= s_('CreateNewFork|Fork') %span= s_('CreateNewFork|Fork')
.count-with-arrow .count-with-arrow
......
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
- if @namespaces.present? - if @namespaces.present?
%label.label-light %label.label-light
%span %span
Click to fork the project to a user or group Click to fork the project
- @namespaces.in_groups_of(6, false) do |group| - @namespaces.in_groups_of(6, false) do |group|
.row .row
- group.each do |namespace| - group.each do |namespace|
...@@ -29,8 +29,12 @@ ...@@ -29,8 +29,12 @@
.caption .caption
= namespace.human_name = namespace.human_name
- else - else
.fork-thumbnail - can_create_project = current_user.can?(:create_projects, namespace)
= link_to project_forks_path(@project, namespace_key: namespace.id), method: "POST" do .fork-thumbnail{ class: ("disabled" unless can_create_project) }
= link_to project_forks_path(@project, namespace_key: namespace.id),
method: "POST",
class: ("disabled has-tooltip" unless can_create_project),
title: (_('You have reached your project limit') unless can_create_project) do
- if /no_((\w*)_)*avatar/.match(avatar) - if /no_((\w*)_)*avatar/.match(avatar)
.no-avatar .no-avatar
= icon 'question' = icon 'question'
......
---
title: Fixed fork button being disabled for users who can fork to a group
merge_request:
author:
type: fixed
require 'spec_helper'
describe 'Project fork' do
let(:user) { create(:user) }
let(:project) { create(:project, :public, :repository) }
before do
sign_in user
end
it 'allows user to fork project' do
visit project_path(project)
expect(page).not_to have_css('a.disabled', text: 'Fork')
end
it 'disables fork button when user has exceeded project limit' do
user.projects_limit = 0
user.save!
visit project_path(project)
expect(page).to have_css('a.disabled', text: 'Fork')
end
context 'master in group' do
before do
group = create(:group)
group.add_master(user)
end
it 'allows user to fork project to group or to user namespace' do
visit project_path(project)
expect(page).not_to have_css('a.disabled', text: 'Fork')
click_link 'Fork'
expect(page).to have_css('.fork-thumbnail', count: 2)
expect(page).not_to have_css('.fork-thumbnail.disabled')
end
it 'allows user to fork project to group and not user when exceeded project limit' do
user.projects_limit = 0
user.save!
visit project_path(project)
expect(page).not_to have_css('a.disabled', text: 'Fork')
click_link 'Fork'
expect(page).to have_css('.fork-thumbnail', count: 2)
expect(page).to have_css('.fork-thumbnail.disabled')
end
end
end
...@@ -52,6 +52,29 @@ describe GlobalPolicy do ...@@ -52,6 +52,29 @@ describe GlobalPolicy do
end end
end end
describe "create fork" do
context "when user has not exceeded project limit" do
it { is_expected.to be_allowed(:create_fork) }
end
context "when user has exceeded project limit" do
let(:current_user) { create(:user, projects_limit: 0) }
it { is_expected.not_to be_allowed(:create_fork) }
end
context "when user is a master in a group" do
let(:group) { create(:group) }
let(:current_user) { create(:user, projects_limit: 0) }
before do
group.add_master(current_user)
end
it { is_expected.to be_allowed(:create_fork) }
end
end
describe 'custom attributes' do describe 'custom attributes' do
context 'regular user' do context 'regular user' do
it { is_expected.not_to be_allowed(:read_custom_attribute) } it { is_expected.not_to be_allowed(:read_custom_attribute) }
......
require 'spec_helper'
describe NamespacePolicy do
let(:current_user) { create(:user) }
let(:namespace) { current_user.namespace }
subject { described_class.new(current_user, namespace) }
context "create projects" do
context "user namespace" do
it { is_expected.to be_allowed(:create_projects) }
end
context "user who has exceeded project limit" do
let(:current_user) { create(:user, projects_limit: 0) }
it { is_expected.not_to be_allowed(:create_projects) }
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