Add ProjectLabel model

parent e2dd75c0
...@@ -128,7 +128,8 @@ class IssuableFinder ...@@ -128,7 +128,8 @@ class IssuableFinder
@labels = Label.where(title: label_names) @labels = Label.where(title: label_names)
if projects if projects
@labels = @labels.where(project: projects) label_ids = LabelsFinder.new(current_user, project_id: projects).execute.select(:id)
@labels = @labels.where(labels: { id: label_ids })
end end
else else
@labels = Label.none @labels = Label.none
......
...@@ -57,21 +57,21 @@ module LabelsHelper ...@@ -57,21 +57,21 @@ module LabelsHelper
def edit_label_path(label) def edit_label_path(label)
case label case label
when GroupLabel then edit_group_label_path(label.group, label) when GroupLabel then edit_group_label_path(label.group, label)
else edit_namespace_project_label_path(label.project.namespace, label.project, label) when ProjectLabel then edit_namespace_project_label_path(label.project.namespace, label.project, label)
end end
end end
def destroy_label_path(label) def destroy_label_path(label)
case label case label
when GroupLabel then group_label_path(label.group, label) when GroupLabel then group_label_path(label.group, label)
else namespace_project_label_path(label.project.namespace, label.project, label) when ProjectLabel then namespace_project_label_path(label.project.namespace, label.project, label)
end end
end end
def toggle_subscription_label_path(label) def toggle_subscription_label_path(label)
case label case label
when GroupLabel then toggle_subscription_group_label_path(label.group, label) when GroupLabel then toggle_subscription_group_label_path(label.group, label)
else toggle_subscription_namespace_project_label_path(label.project.namespace, label.project, label) when ProjectLabel then toggle_subscription_namespace_project_label_path(label.project.namespace, label.project, label)
end end
end end
...@@ -79,7 +79,7 @@ module LabelsHelper ...@@ -79,7 +79,7 @@ module LabelsHelper
title, icon = title, icon =
case label case label
when GroupLabel then ['Group', 'folder-open'] when GroupLabel then ['Group', 'folder-open']
else ['Project', 'bookmark'] when ProjectLabel then ['Project', 'bookmark']
end end
options[:class] ||= '' options[:class] ||= ''
......
...@@ -15,15 +15,12 @@ class Label < ActiveRecord::Base ...@@ -15,15 +15,12 @@ class Label < ActiveRecord::Base
default_value_for :color, DEFAULT_COLOR default_value_for :color, DEFAULT_COLOR
belongs_to :project
has_many :lists, dependent: :destroy has_many :lists, dependent: :destroy
has_many :label_links, dependent: :destroy has_many :label_links, dependent: :destroy
has_many :issues, through: :label_links, source: :target, source_type: 'Issue' has_many :issues, through: :label_links, source: :target, source_type: 'Issue'
has_many :merge_requests, through: :label_links, source: :target, source_type: 'MergeRequest' has_many :merge_requests, through: :label_links, source: :target, source_type: 'MergeRequest'
validates :color, color: true, allow_blank: false validates :color, color: true, allow_blank: false
validates :project, presence: true, if: :project_label?
# 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/ }
...@@ -137,10 +134,6 @@ class Label < ActiveRecord::Base ...@@ -137,10 +134,6 @@ class Label < ActiveRecord::Base
.count .count
end end
def project_label?
type.blank? && !template?
end
def label_format_reference(format = :id) def label_format_reference(format = :id)
raise StandardError, 'Unknown format' unless [:id, :name].include?(format) raise StandardError, 'Unknown format' unless [:id, :name].include?(format)
......
...@@ -107,7 +107,7 @@ class Project < ActiveRecord::Base ...@@ -107,7 +107,7 @@ class Project < ActiveRecord::Base
# Merge requests from source project should be kept when source project was removed # Merge requests from source project should be kept when source project was removed
has_many :fork_merge_requests, foreign_key: 'source_project_id', class_name: MergeRequest has_many :fork_merge_requests, foreign_key: 'source_project_id', class_name: MergeRequest
has_many :issues, dependent: :destroy has_many :issues, dependent: :destroy
has_many :labels, dependent: :destroy has_many :labels, dependent: :destroy, class_name: 'ProjectLabel'
has_many :services, dependent: :destroy has_many :services, dependent: :destroy
has_many :events, dependent: :destroy has_many :events, dependent: :destroy
has_many :milestones, dependent: :destroy has_many :milestones, dependent: :destroy
...@@ -730,8 +730,10 @@ class Project < ActiveRecord::Base ...@@ -730,8 +730,10 @@ class Project < ActiveRecord::Base
def create_labels def create_labels
Label.templates.each do |label| Label.templates.each do |label|
label = label.dup label = label.dup
label.template = nil label.template = false
label.project_id = self.id label.project_id = self.id
label.type = 'ProjectLabel'
label.save label.save
end end
end end
......
class ProjectLabel < Label
belongs_to :project
validates :project, presence: true
end
class LabelPolicy < BasePolicy class ProjectLabelPolicy < BasePolicy
def rules def rules
return unless @user
can! :admin_label if Ability.allowed?(@user, :admin_label, @subject.project) can! :admin_label if Ability.allowed?(@user, :admin_label, @subject.project)
end end
end end
= form_for [@project.namespace.becomes(Namespace), @project, @label], html: { class: 'form-horizontal label-form js-quick-submit js-requires-input' } do |f| = form_for @label, as: :label, url: url, html: { class: 'form-horizontal label-form js-quick-submit js-requires-input' } do |f|
= form_errors(@label) = form_errors(@label)
.form-group .form-group
......
...@@ -7,4 +7,4 @@ ...@@ -7,4 +7,4 @@
= icon('bookmark') = icon('bookmark')
Edit Project Label Edit Project Label
%hr %hr
= render 'form' = render 'form', url: namespace_project_label_path(@project.namespace.becomes(Namespace), @project, @label)
...@@ -7,4 +7,4 @@ ...@@ -7,4 +7,4 @@
= icon('bookmark') = icon('bookmark')
New Project Label New Project Label
%hr %hr
= render 'form' = render 'form', url: namespace_project_labels_path(@project.namespace.becomes(Namespace), @project)
class SetProjectLabelTypeOnLabels < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
def up
update_column_in_batches(:labels, :type, 'ProjectLabel') do |table, query|
query.where(table[:project_id].not_eq(nil))
end
end
def down
update_column_in_batches(:labels, :type, nil) do |table, query|
query.where(table[:project_id].not_eq(nil))
end
end
end
...@@ -70,7 +70,7 @@ module Banzai ...@@ -70,7 +70,7 @@ module Banzai
end end
def object_link_text(object, matches) def object_link_text(object, matches)
if object.project.nil? || object.project == context[:project] if object.is_a?(GroupLabel) || object.project == context[:project]
LabelsHelper.render_colored_label(object) LabelsHelper.render_colored_label(object)
else else
LabelsHelper.render_colored_cross_project_label(object) LabelsHelper.render_colored_cross_project_label(object)
......
...@@ -237,7 +237,7 @@ module Gitlab ...@@ -237,7 +237,7 @@ module Gitlab
def create_label(name) def create_label(name)
color = nice_label_color(name) color = nice_label_color(name)
Label.create!(project_id: project.id, name: name, color: color) project.labels.create!(name: name, color: color)
end end
def format_content(raw_content) def format_content(raw_content)
......
FactoryGirl.define do FactoryGirl.define do
factory :label do factory :label, class: ProjectLabel do
sequence(:title) { |n| "label#{n}" } sequence(:title) { |n| "label#{n}" }
color "#990000" color "#990000"
project project
......
require 'spec_helper' require 'spec_helper'
describe Label, models: true do describe Label, models: true do
let(:label) { create(:label) } describe 'modules' do
it { is_expected.to include_module(Referable) }
it { is_expected.to include_module(Subscribable) }
end
describe 'associations' do describe 'associations' do
it { is_expected.to belong_to(:project) }
it { is_expected.to have_many(:label_links).dependent(:destroy) }
it { is_expected.to have_many(:issues).through(:label_links).source(:target) } it { is_expected.to have_many(:issues).through(:label_links).source(:target) }
it { is_expected.to have_many(:label_links).dependent(:destroy) }
it { is_expected.to have_many(:lists).dependent(:destroy) } it { is_expected.to have_many(:lists).dependent(:destroy) }
end end
describe 'modules' do
subject { described_class }
it { is_expected.to include_module(Referable) }
end
describe 'validation' do describe 'validation' do
it { is_expected.to validate_presence_of(:project) }
it { is_expected.to validate_uniqueness_of(:title) } it { is_expected.to validate_uniqueness_of(:title) }
it 'validates color code' do it 'validates color code' do
expect(label).not_to allow_value('G-ITLAB').for(:color) is_expected.not_to allow_value('G-ITLAB').for(:color)
expect(label).not_to allow_value('AABBCC').for(:color) is_expected.not_to allow_value('AABBCC').for(:color)
expect(label).not_to allow_value('#AABBCCEE').for(:color) is_expected.not_to allow_value('#AABBCCEE').for(:color)
expect(label).not_to allow_value('GGHHII').for(:color) is_expected.not_to allow_value('GGHHII').for(:color)
expect(label).not_to allow_value('#').for(:color) is_expected.not_to allow_value('#').for(:color)
expect(label).not_to allow_value('').for(:color) is_expected.not_to allow_value('').for(:color)
expect(label).to allow_value('#AABBCC').for(:color) is_expected.to allow_value('#AABBCC').for(:color)
expect(label).to allow_value('#abcdef').for(:color) is_expected.to allow_value('#abcdef').for(:color)
end end
it 'validates title' do it 'validates title' do
expect(label).not_to allow_value('G,ITLAB').for(:title) is_expected.not_to allow_value('G,ITLAB').for(:title)
expect(label).not_to allow_value('').for(:title) is_expected.not_to allow_value('').for(:title)
expect(label).to allow_value('GITLAB').for(:title) is_expected.to allow_value('GITLAB').for(:title)
expect(label).to allow_value('gitlab').for(:title) is_expected.to allow_value('gitlab').for(:title)
expect(label).to allow_value('G?ITLAB').for(:title) is_expected.to allow_value('G?ITLAB').for(:title)
expect(label).to allow_value('G&ITLAB').for(:title) is_expected.to allow_value('G&ITLAB').for(:title)
expect(label).to allow_value("customer's request").for(:title) is_expected.to allow_value("customer's request").for(:title)
end end
end end
...@@ -53,6 +47,8 @@ describe Label, models: true do ...@@ -53,6 +47,8 @@ describe Label, models: true do
end end
describe '#to_reference' do describe '#to_reference' do
let(:label) { create(:label) }
context 'using id' do context 'using id' do
it 'returns a String reference to the object' do it 'returns a String reference to the object' do
expect(label.to_reference).to eq "~#{label.id}" expect(label.to_reference).to eq "~#{label.id}"
......
require 'spec_helper'
describe ProjectLabel, models: true do
describe 'relationships' do
it { is_expected.to belong_to(:project) }
end
describe 'validations' do
it { is_expected.to validate_presence_of(:project) }
end
end
...@@ -56,7 +56,7 @@ describe Project, models: true do ...@@ -56,7 +56,7 @@ describe Project, models: true do
it { is_expected.to have_many(:runners) } it { is_expected.to have_many(:runners) }
it { is_expected.to have_many(:variables) } it { is_expected.to have_many(:variables) }
it { is_expected.to have_many(:triggers) } it { is_expected.to have_many(:triggers) }
it { is_expected.to have_many(:labels).dependent(:destroy) } it { is_expected.to have_many(:labels).class_name('ProjectLabel').dependent(:destroy) }
it { is_expected.to have_many(:users_star_projects).dependent(:destroy) } it { is_expected.to have_many(:users_star_projects).dependent(:destroy) }
it { is_expected.to have_many(:environments).dependent(:destroy) } it { is_expected.to have_many(:environments).dependent(:destroy) }
it { is_expected.to have_many(:deployments).dependent(:destroy) } it { is_expected.to have_many(:deployments).dependent(:destroy) }
......
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