Validate if project label title does not exist at group level

parent cfedd42b
...@@ -24,13 +24,14 @@ class Label < ActiveRecord::Base ...@@ -24,13 +24,14 @@ class Label < ActiveRecord::Base
# Don't allow ',' for label titles # Don't allow ',' for label titles
validates :title, presence: true, format: { with: /\A[^,]+\z/ } validates :title, presence: true, format: { with: /\A[^,]+\z/ }
validates :title, uniqueness: true, unless: :template? validates :title, uniqueness: { scope: [:group_id, :project_id] }
before_save :nullify_priority before_save :nullify_priority
default_scope { order(title: :asc) } default_scope { order(title: :asc) }
scope :templates, -> { where(template: true) } scope :templates, -> { where(template: true) }
scope :with_title, ->(title) { where(title: title) }
def self.prioritized def self.prioritized
where.not(priority: nil).reorder(:priority, :title) where.not(priority: nil).reorder(:priority, :title)
......
...@@ -2,4 +2,18 @@ class ProjectLabel < Label ...@@ -2,4 +2,18 @@ class ProjectLabel < Label
belongs_to :project belongs_to :project
validates :project, presence: true validates :project, presence: true
validate :title_must_not_exist_at_group_level
delegate :group, to: :project, allow_nil: true
private
def title_must_not_exist_at_group_level
return unless group.present?
if group.labels.with_title(self.title).exists?
errors.add(:title, :label_already_exists_at_group_level, group: group.name)
end
end
end end
...@@ -5,6 +5,7 @@ en: ...@@ -5,6 +5,7 @@ en:
hello: "Hello world" hello: "Hello world"
errors: errors:
messages: messages:
label_already_exists_at_group_level: "already exists at group level for %{group}. Please choose another one."
wrong_size: "is the wrong size (should be %{file_size})" wrong_size: "is the wrong size (should be %{file_size})"
size_too_small: "is too small (should be at least %{file_size})" size_too_small: "is too small (should be at least %{file_size})"
size_too_big: "is too big (should be at most %{file_size})" size_too_big: "is too big (should be at most %{file_size})"
......
...@@ -4,4 +4,10 @@ FactoryGirl.define do ...@@ -4,4 +4,10 @@ FactoryGirl.define do
color "#990000" color "#990000"
project project
end end
factory :group_label, class: GroupLabel do
sequence(:title) { |n| "label#{n}" }
color "#990000"
group
end
end end
...@@ -13,7 +13,7 @@ describe Label, models: true do ...@@ -13,7 +13,7 @@ describe Label, models: true do
end end
describe 'validation' do describe 'validation' do
it { is_expected.to validate_uniqueness_of(:title) } it { is_expected.to validate_uniqueness_of(:title).scoped_to([:group_id, :project_id]) }
it 'validates color code' do it 'validates color code' do
is_expected.not_to allow_value('G-ITLAB').for(:color) is_expected.not_to allow_value('G-ITLAB').for(:color)
......
...@@ -7,5 +7,39 @@ describe ProjectLabel, models: true do ...@@ -7,5 +7,39 @@ describe ProjectLabel, models: true do
describe 'validations' do describe 'validations' do
it { is_expected.to validate_presence_of(:project) } it { is_expected.to validate_presence_of(:project) }
context 'validates if title must not exist at group level' do
let(:group) { create(:group, name: 'gitlab-org') }
let(:project) { create(:empty_project, group: group) }
before do
create(:group_label, group: group, title: 'Bug')
end
it 'returns error if title already exists at group level' do
label = described_class.new(project: project, title: 'Bug')
label.valid?
expect(label.errors[:title]).to include 'already exists at group level for gitlab-org. Please choose another one.'
end
it 'does not returns error if title does not exist at group level' do
label = described_class.new(project: project, title: 'Security')
label.valid?
expect(label.errors[:title]).to be_empty
end
it 'does not returns error if project does not belong to group' do
another_project = create(:empty_project)
label = described_class.new(project: another_project, title: 'Bug')
label.valid?
expect(label.errors[:title]).to be_empty
end
end
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