Improve labels validation and expose error messages
This commit is contained in:
parent
ed9e922dd0
commit
7ad93ab250
6 changed files with 84 additions and 15 deletions
|
@ -138,6 +138,10 @@ module Issuable
|
|||
labels.order('title ASC').pluck(:title)
|
||||
end
|
||||
|
||||
def remove_labels
|
||||
labels.delete_all
|
||||
end
|
||||
|
||||
def add_labels_by_names(label_names)
|
||||
label_names.each do |label_name|
|
||||
label = project.labels.create_with(
|
||||
|
|
|
@ -6,14 +6,14 @@ class Label < ActiveRecord::Base
|
|||
has_many :issues, through: :label_links, source: :target, source_type: 'Issue'
|
||||
|
||||
validates :color,
|
||||
format: { with: /\A\#[0-9A-Fa-f]{6}+\Z/ },
|
||||
format: { with: /\A#[0-9A-Fa-f]{6}\Z/ },
|
||||
allow_blank: false
|
||||
validates :project, presence: true
|
||||
|
||||
# Don't allow '?', '&', and ',' for label titles
|
||||
validates :title,
|
||||
presence: true,
|
||||
format: { with: /\A[^&\?,&]*\z/ },
|
||||
format: { with: /\A[^&\?,&]+\z/ },
|
||||
uniqueness: { scope: :project_id }
|
||||
|
||||
scope :order_by_name, -> { reorder("labels.title ASC") }
|
||||
|
|
|
@ -114,17 +114,21 @@ module API
|
|||
|
||||
# Helper method for validating all labels against its names
|
||||
def validate_label_params(params)
|
||||
errors = {}
|
||||
|
||||
if params[:labels].present?
|
||||
params[:labels].split(',').each do |label_name|
|
||||
label = user_project.labels.create_with(
|
||||
color: Label::DEFAULT_COLOR).find_or_initialize_by(
|
||||
title: label_name.strip)
|
||||
|
||||
if label.invalid?
|
||||
return true
|
||||
errors[label.title] = label.errors
|
||||
end
|
||||
end
|
||||
end
|
||||
false
|
||||
|
||||
errors
|
||||
end
|
||||
|
||||
# error helpers
|
||||
|
|
|
@ -52,8 +52,8 @@ module API
|
|||
attrs = attributes_for_keys [:title, :description, :assignee_id, :milestone_id]
|
||||
|
||||
# Validate label names in advance
|
||||
if validate_label_params(params)
|
||||
return render_api_error!('Label names invalid', 405)
|
||||
if (errors = validate_label_params(params)).any?
|
||||
render_api_error!({ labels: errors }, 400)
|
||||
end
|
||||
|
||||
issue = ::Issues::CreateService.new(user_project, current_user, attrs).execute
|
||||
|
@ -90,8 +90,8 @@ module API
|
|||
attrs = attributes_for_keys [:title, :description, :assignee_id, :milestone_id, :state_event]
|
||||
|
||||
# Validate label names in advance
|
||||
if validate_label_params(params)
|
||||
return render_api_error!('Label names invalid', 405)
|
||||
if (errors = validate_label_params(params)).any?
|
||||
render_api_error!({ labels: errors }, 400)
|
||||
end
|
||||
|
||||
issue = ::Issues::UpdateService.new(user_project, current_user, attrs).execute(issue)
|
||||
|
@ -99,7 +99,8 @@ module API
|
|||
if issue.valid?
|
||||
# Find or create labels and attach to issue. Labels are valid because
|
||||
# we already checked its name, so there can't be an error here
|
||||
if params[:labels].present?
|
||||
unless params[:labels].nil?
|
||||
issue.remove_labels
|
||||
# Create and add labels to the new created issue
|
||||
issue.add_labels_by_names(params[:labels].split(','))
|
||||
end
|
||||
|
|
|
@ -73,12 +73,12 @@ describe API::API, api: true do
|
|||
response.status.should == 400
|
||||
end
|
||||
|
||||
it 'should return 405 on invalid label names' do
|
||||
it 'should return 400 on invalid label names' do
|
||||
post api("/projects/#{project.id}/issues", user),
|
||||
title: 'new issue',
|
||||
labels: 'label, ?'
|
||||
response.status.should == 405
|
||||
json_response['message'].should == 'Label names invalid'
|
||||
response.status.should == 400
|
||||
json_response['message']['labels']['?']['title'].should == ['is invalid']
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -97,12 +97,56 @@ describe API::API, api: true do
|
|||
response.status.should == 404
|
||||
end
|
||||
|
||||
it 'should return 405 on invalid label names' do
|
||||
it 'should return 400 on invalid label names' do
|
||||
put api("/projects/#{project.id}/issues/#{issue.id}", user),
|
||||
title: 'updated title',
|
||||
labels: 'label, ?'
|
||||
response.status.should == 405
|
||||
json_response['message'].should == 'Label names invalid'
|
||||
response.status.should == 400
|
||||
json_response['message']['labels']['?']['title'].should == ['is invalid']
|
||||
end
|
||||
end
|
||||
|
||||
describe 'PUT /projects/:id/issues/:issue_id to update labels' do
|
||||
let!(:label) { create(:label, title: 'dummy', project: project) }
|
||||
let!(:label_link) { create(:label_link, label: label, target: issue) }
|
||||
|
||||
it 'should not update labels if not present' do
|
||||
put api("/projects/#{project.id}/issues/#{issue.id}", user),
|
||||
title: 'updated title'
|
||||
response.status.should == 200
|
||||
json_response['labels'].should == [label.title]
|
||||
end
|
||||
|
||||
it 'should remove all labels' do
|
||||
put api("/projects/#{project.id}/issues/#{issue.id}", user),
|
||||
labels: ''
|
||||
response.status.should == 200
|
||||
json_response['labels'].should == []
|
||||
end
|
||||
|
||||
it 'should update labels' do
|
||||
put api("/projects/#{project.id}/issues/#{issue.id}", user),
|
||||
labels: 'foo,bar'
|
||||
response.status.should == 200
|
||||
json_response['labels'].should include 'foo'
|
||||
json_response['labels'].should include 'bar'
|
||||
end
|
||||
|
||||
it 'should return 400 on invalid label names' do
|
||||
put api("/projects/#{project.id}/issues/#{issue.id}", user),
|
||||
labels: 'label, ?'
|
||||
response.status.should == 400
|
||||
json_response['message']['labels']['?']['title'].should == ['is invalid']
|
||||
end
|
||||
|
||||
it 'should allow special label names' do
|
||||
put api("/projects/#{project.id}/issues/#{issue.id}", user),
|
||||
labels: 'label:foo, label-bar,label_bar,label/bar'
|
||||
response.status.should == 200
|
||||
json_response['labels'].should include 'label:foo'
|
||||
json_response['labels'].should include 'label-bar'
|
||||
json_response['labels'].should include 'label_bar'
|
||||
json_response['labels'].should include 'label/bar'
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -50,6 +50,14 @@ describe API::API, api: true do
|
|||
json_response['message'].should == 'Color is invalid'
|
||||
end
|
||||
|
||||
it 'should return 400 for too long color code' do
|
||||
post api("/projects/#{project.id}/labels", user),
|
||||
name: 'Foo',
|
||||
color: '#FFAAFFFF'
|
||||
response.status.should == 400
|
||||
json_response['message'].should == 'Color is invalid'
|
||||
end
|
||||
|
||||
it 'should return 400 for invalid name' do
|
||||
post api("/projects/#{project.id}/labels", user),
|
||||
name: '?',
|
||||
|
@ -147,5 +155,13 @@ describe API::API, api: true do
|
|||
response.status.should == 400
|
||||
json_response['message'].should == 'Color is invalid'
|
||||
end
|
||||
|
||||
it 'should return 400 for too long color code' do
|
||||
post api("/projects/#{project.id}/labels", user),
|
||||
name: 'Foo',
|
||||
color: '#FFAAFFFF'
|
||||
response.status.should == 400
|
||||
json_response['message'].should == 'Color is invalid'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue