diff --git a/app/models/project.rb b/app/models/project.rb index 376f8efacb1c1060ef76586b3916d5ff02c27164..15465d9b3567b44acab0b8d1df77af5eaf0327fc 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -331,7 +331,7 @@ class Project < ActiveRecord::Base ports: ->(project) { project.persisted? ? VALID_MIRROR_PORTS : VALID_IMPORT_PORTS }, enforce_user: true }, if: [:external_import?, :import_url_changed?] validates :star_count, numericality: { greater_than_or_equal_to: 0 } - validate :check_limit, on: :create + validate :check_personal_projects_limit, on: :create validate :check_repository_path_availability, on: :update, if: ->(project) { project.renamed? } validate :visibility_level_allowed_by_group, if: -> { changes.has_key?(:visibility_level) } validate :visibility_level_allowed_as_fork, if: -> { changes.has_key?(:visibility_level) } @@ -809,18 +809,22 @@ class Project < ActiveRecord::Base ::Gitlab::CurrentSettings.mirror_available end - def check_limit - unless creator.can_create_project? || namespace.kind == 'group' - projects_limit = creator.projects_limit + def check_personal_projects_limit + # Since this method is called as validation hook, `creator` might not be + # present. Since the validation for that will fail, we can just return + # early. + return if !creator || creator.can_create_project? || + namespace.kind == 'group' - if projects_limit == 0 - self.errors.add(:limit_reached, "Personal project creation is not allowed. Please contact your administrator with questions") + limit = creator.projects_limit + error = + if limit.zero? + _('Personal project creation is not allowed. Please contact your administrator with questions') else - self.errors.add(:limit_reached, "Your project limit is #{projects_limit} projects! Please contact your administrator to increase it") + _('Your project limit is %{limit} projects! Please contact your administrator to increase it') end - end - rescue - self.errors.add(:base, "Can't check your ability to create project") + + self.errors.add(:limit_reached, error % { limit: limit }) end def visibility_level_allowed_by_group diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 404cb0793714ad2fd0aa88354aab66bfdf32d6f5..85628ba030b9566e38c66813b20e84ecf9e526f1 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -4934,6 +4934,9 @@ msgstr "" msgid "Personal Access Token" msgstr "" +msgid "Personal project creation is not allowed. Please contact your administrator with questions" +msgstr "" + msgid "Pick a name" msgstr "" @@ -8145,6 +8148,9 @@ msgstr "" msgid "Your name" msgstr "" +msgid "Your project limit is %{limit} projects! Please contact your administrator to increase it" +msgstr "" + msgid "Your projects" msgstr "" diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index 08eed9c06de96b43f673d74a887a1796ccce5a1f..7a8dc59039eabe7fc486ca0bd9643f24d2a783b9 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -209,9 +209,14 @@ describe Project do it 'does not allow new projects beyond user limits' do project2 = build(:project) - allow(project2).to receive(:creator).and_return(double(can_create_project?: false, projects_limit: 0).as_null_object) + + allow(project2) + .to receive(:creator) + .and_return( + double(can_create_project?: false, projects_limit: 0).as_null_object + ) + expect(project2).not_to be_valid - expect(project2.errors[:limit_reached].first).to match(/Personal project creation is not allowed/) end describe 'wiki path conflict' do @@ -4431,6 +4436,75 @@ describe Project do end end + describe '#check_personal_projects_limit' do + context 'when creating a project for a group' do + it 'does nothing' do + creator = build(:user) + project = build(:project, namespace: build(:group), creator: creator) + + allow(creator) + .to receive(:can_create_project?) + .and_return(false) + + project.check_personal_projects_limit + + expect(project.errors).to be_empty + end + end + + context 'when the user is not allowed to create a personal project' do + let(:user) { build(:user) } + let(:project) { build(:project, creator: user) } + + before do + allow(user) + .to receive(:can_create_project?) + .and_return(false) + end + + context 'when the project limit is zero' do + it 'adds a validation error' do + allow(user) + .to receive(:projects_limit) + .and_return(0) + + project.check_personal_projects_limit + + expect(project.errors[:limit_reached].first) + .to match(/Personal project creation is not allowed/) + end + end + + context 'when the project limit is greater than zero' do + it 'adds a validation error' do + allow(user) + .to receive(:projects_limit) + .and_return(5) + + project.check_personal_projects_limit + + expect(project.errors[:limit_reached].first) + .to match(/Your project limit is 5 projects/) + end + end + end + + context 'when the user is allowed to create personal projects' do + it 'does nothing' do + user = build(:user) + project = build(:project, creator: user) + + allow(user) + .to receive(:can_create_project?) + .and_return(true) + + project.check_personal_projects_limit + + expect(project.errors).to be_empty + end + end + end + def rugged_config rugged_repo(project.repository).config end